Super with block

Hi all,

I'm looking for a bit of help. I can't seem to get the block to "pass
through" to the parent class. I figured without an '&' in the parameter
list there would be no conversion to proc but maybe that is not the
case.

class Nstring < String
  def gsub!(*args)
    super
  end
end

This works as I expected:

s = Nstring.new("hi")
s.gsub!(/(hi)/,'\1')
=> "hi"

But this, not so much:

s.gsub!(/(hi)/) {$1}
=> ""

Thanks,
Lou

···

--
Posted via http://www.ruby-forum.com/.

Hi,

This worked for me:

irb(main):023:0> class NString < String
irb(main):024:1> def gsub!(*args, &blk)
irb(main):025:2> super(*args, &blk)
irb(main):026:2> end
irb(main):027:1> end
=> nil
irb(main):028:0> s = NString.new("hi")
=> "hi"
irb(main):029:0> s.gsub!(/(hi)/){$1}
=> "hi"

Hope this helps,

Jesus.

···

On Thu, Jul 31, 2008 at 11:06 AM, Lou Zell <lzell11@gmail.com> wrote:

Hi all,

I'm looking for a bit of help. I can't seem to get the block to "pass
through" to the parent class. I figured without an '&' in the parameter
list there would be no conversion to proc but maybe that is not the
case.

class Nstring < String
def gsub!(*args)
   super
end
end

This works as I expected:

s = Nstring.new("hi")
s.gsub!(/(hi)/,'\1')
=> "hi"

But this, not so much:

s.gsub!(/(hi)/) {$1}
=> ""

Hi,

This worked for me:

irb(main):023:0> class NString < String
irb(main):024:1> def gsub!(*args, &blk)
irb(main):025:2> super(*args, &blk)
irb(main):026:2> end
irb(main):027:1> end
=> nil
irb(main):028:0> s = NString.new("hi")
=> "hi"
irb(main):029:0> s.gsub!(/(hi)/){$1}
=> "hi"

Hope this helps,

Jesus.

Hi Jesus, thank you for your response. Unfortunately, I could not
replicate your results:

class NString < String
def gsub!(*args, &blk)
super(*args, &blk)
end
end

=> nil

s = NString.new("hi")

=> "hi"

s.gsub!(/(hi)/){$1}

=> ""

Perhaps it is my version of ruby?
~$ ruby -v
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]

Lou

···

--
Posted via http://www.ruby-forum.com/\.

Looks like this is a problem with using $1 inside the block. Replacing {$1} with {|m| m} makes it work.

However, a different issue I now remember running into a long time ago is that `super` is pretty quirky regarding blocks:

Calling it as just `super` will pass the block.
`super(*args, &block)` will as well, obviously.
`super(*args)` will too!

The only way to avoid passing the block to super is `super(*args, &nil)`, however ugly that might be.

All of this is tested in 1.8.6, and is probably the same in 1.9.

···

On Jul 31, 2008, at 19:10, Lou Zell wrote:

class NString < String
def gsub!(*args, &blk)
super(*args, &blk)
end

=> nil

s = NString.new("hi")

=> "hi"

s.gsub!(/(hi)/){$1}

=> ""

--
Mikael Høilund
http://hoilund.org/

Hi,

This worked for me:

irb(main):023:0> class NString < String
irb(main):024:1> def gsub!(*args, &blk)
irb(main):025:2> super(*args, &blk)
irb(main):026:2> end
irb(main):027:1> end
=> nil
irb(main):028:0> s = NString.new("hi")
=> "hi"
irb(main):029:0> s.gsub!(/(hi)/){$1}
=> "hi"

Hope this helps,

Jesus.

Hi Jesus, thank you for your response. Unfortunately, I could not
replicate your results:

class NString < String
def gsub!(*args, &blk)
super(*args, &blk)
end
end

=> nil

your problem has nothing to do with passing the block along in gsub!

s = NString.new("hi")

guess what s is here?
If you guessed "", you guessed correctly

=> "hi"

s.gsub!(/(hi)/){$1}

=> ""

normal given that s was ""

Probably subclassing is not what you want, but it can be accomplished of course

Perhaps it is my version of ruby?
~$ ruby -v
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]

Lou
--
Posted via http://www.ruby-forum.com/\.

Here is the final solution
class NString < String
def initialize str
    replace str
end
def gsub! *args
   super( *args, &Proc::new ) # that is just to show you yet another
way to do this but passing &blk is better
end
end

n = Nstring::new( "123")
p n
p n.gsub!(/.../){ |m| m.reverse } # $1 is not set as somebody did
point out already

HTH
Robert

···

On Thu, Jul 31, 2008 at 7:10 PM, Lou Zell <lzell11@gmail.com> wrote:

--
http://ruby-smalltalk.blogspot.com/

There's no one thing that's true. It's all true.
--
Ernest Hemingway

Sorry, it seems that my $1 was set by previous tests in IRB :frowning:
The others are right and the discussion has been interesting.
It also shows you have to be careful with tests in IRB...

Jesus.

···

On Thu, Jul 31, 2008 at 7:10 PM, Lou Zell <lzell11@gmail.com> wrote:

Hi,

This worked for me:

irb(main):023:0> class NString < String
irb(main):024:1> def gsub!(*args, &blk)
irb(main):025:2> super(*args, &blk)
irb(main):026:2> end
irb(main):027:1> end
=> nil
irb(main):028:0> s = NString.new("hi")
=> "hi"
irb(main):029:0> s.gsub!(/(hi)/){$1}
=> "hi"

Hope this helps,

Jesus.

Hi Jesus, thank you for your response. Unfortunately, I could not
replicate your results:

Mikael, I can deal with that, I'll swap out the $'s with block params.
Thanks for the workaround!

Lou

···

--
Posted via http://www.ruby-forum.com/.

ERRATUM

use
replace str[0..-1] or
replace str.dup

instead of
  replace str

bad mistake of my part sorry.

Robert

I know that and I still managed to screw up my String subclass
constructor :-(. But I agree, interesting thread, always
good to refresh some "basic" things.
Cheers
Robert

···

On Fri, Aug 1, 2008 at 7:54 AM, Jesús Gabriel y Galán <jgabrielygalan@gmail.com> wrote:

Sorry, it seems that my $1 was set by previous tests in IRB :frowning:
The others are right and the discussion has been interesting.
It also shows you have to be careful with tests in IRB...

your problem has nothing to do with passing the block along in gsub!

s = NString.new("hi")

guess what s is here?
If you guessed "", you guessed correctly

Wait, why would s be empty? I can use Nstring.new just like String.new

class Nstring < String
end

=> nil

n = Nstring.new("hi")

=> "hi"

puts n

hi

Lou

···

--
Posted via http://www.ruby-forum.com/\.

Lou Zell wrote:

Mikael, I can deal with that, I'll swap out the $'s with block params.
Thanks for the workaround!

Lou

Actually, this did not work the way I expected. It is fine for a case
like this:
str = "match1"
gsub!(/(match1)/) {|m| m}

But not this:
str = "match1match2"
gsub!(/(match1)(match2)/) {|m1,m2| m1 + m2}

Where I am really looking for:
str = "match1match2"
gsub!(/(match1)(match2)/) { $1 + $2}

So let me ask this instead: How do I pass a block from one method to
another without invoking the block?

For instance, let's say I want to create a method nsub! that behaves
EXACTLY like gsub!

class String
  def nsub!(*args)
    gsub!(args[0]) {yield}
  end
end

This will not work, say I do this:

s = String.new("whatever")
s.nsub!(/(what)/) {$1}

The yield in the body of nsub! invokes the block {$1}, but in this
context $1 is nil, so it is like I am calling

gsub!(args[0]) {nil}

Which is obviously not what I want. I would like to pass the original
code block:

gsub!(args[0]) {$1}

Any ideas?

Lou

···

--
Posted via http://www.ruby-forum.com/\.

If you guessed "", you guessed correctly

Wait, why would s be empty? I can use Nstring.new just like String.new

class Nstring < String
end

=> nil

n = Nstring.new("hi")

=> "hi"

puts n

you are right I am wrong, no idea what I did OMG.
Seems your only problem was the $1 in the block
Sorry for the noise
R.

your problem has nothing to do with passing the block along in gsub!

s = NString.new("hi")

guess what s is here?
If you guessed "", you guessed correctly

Wait, why would s be empty? I can use Nstring.new just like String.new

class Nstring < String
end

=> nil

n = Nstring.new("hi")

=> "hi"

puts n

hi

Same here:

seltzer:~ sandal$ ruby -v
ruby 1.8.6 (2008-06-20 patchlevel 230) [i686-darwin8.11.1]
seltzer:~ sandal$ irb

class NString < String
end

=> nil

n = NString.new("hi")

=> "hi"

puts n

hi

That having been said, I generally avoid sub-classing core Ruby
objects because I think some of them use optimizations that cause
internal C methods to be called rather than the methods of a subclass,
resulting in strange behaviour. That having been said, I don't know
that I've ever seen it in practice. Does anyone have an example of
this, or am I just being paranoid?

-greg

···

On Thu, Jul 31, 2008 at 1:47 PM, Lou Zell <lzell11@gmail.com> wrote:

Which is obviously not what I want. I would like to pass the original
code block:

gsub!(args[0]) {$1}

Any ideas?

If you don't mind a little redundancy, you can match the string first,
pull the MatchData object, and yield that:

class String
  def nsub!(*args)
     m = match(args[0])
     gsub!(args[0]) { yield(m) }
  end
end

=> nil

str = "match1match2"

=> "match1match2"

str.nsub!(/(match1)(match2)/) { |m| m[1] + "---" + m[2] }

=> "match1---match2"

str

=> "match1---match2"

It would be nice if MatchData was yielded by gsub instead of a string.

-greg

···

On Thu, Jul 31, 2008 at 4:51 PM, Lou Zell <lzell11@gmail.com> wrote:

--
Killer Ruby PDF Generation named after a magnificent sea creature:
GitHub - practicingruby/prawn: THIS REPOSITORY HAS MOVED TO: | Non-tech stuff at:
http://metametta.blogspot.com

Lou Zell wrote:

Mikael, I can deal with that, I'll swap out the $'s with block params.
Thanks for the workaround!

Lou

Actually, this did not work the way I expected. It is fine for a case
like this:
str = "match1"
gsub!(/(match1)/) {|m| m}

But not this:
str = "match1match2"
gsub!(/(match1)(match2)/) {|m1,m2| m1 + m2}

Where I am really looking for:
str = "match1match2"
gsub!(/(match1)(match2)/) { $1 + $2}

So let me ask this instead: How do I pass a block from one method to
another without invoking the block?

I forgot to answer this before:

class String
  def nsub!(*args,&block)
    gsub!(args[0],&block)
  end
end

But unfortunately, this does not fix your problem:

str = "match1match2"

=> "match1match2"

str.nsub!(/(match1)(match2)/) { |m| $1 + "---" + $2 }

NoMethodError: undefined method `+' for nil:NilClass

···

On Thu, Jul 31, 2008 at 4:51 PM, Lou Zell <lzell11@gmail.com> wrote:

Well, maybe, but do not despair, while the $ special variables are not
available in the block Regexp.last_match *is*

506/6 > cat gsub.rb && ruby gsub.rb
'abc'.gsub(/(.)(.)/){ p Regexp.last_match }
#<MatchData "ab" 1:"a" 2:"b">

HTH
Robert

···

On Thu, Jul 31, 2008 at 11:03 PM, Gregory Brown <gregory.t.brown@gmail.com> wrote:

It would be nice if MatchData was yielded by gsub instead of a string.

-greg

--
http://ruby-smalltalk.blogspot.com/

There's no one thing that's true. It's all true.
--
Ernest Hemingway

But unfortunately, this does not fix your problem:

Indeed. But all is not lost. I *think* this will work fine for what I
need to do (it's tweaked from the solution you gave earlier, thank you).

class String
  def nsub!(*args)
    if m = match(args[0])
       gsub!(args[0]) {yield(*m.to_a[1..-1])}
    end
  end
end

s = "match1match2"

=> "match1match2"

s.nsub!(/(match1)(match2)/) {|m1,m2| m2 + m1}

=> "match2match1"

I haven't done much with it yet, but from some preliminary tests it
seems to work.

Thanks for the help everyone!

Lou

···

--
Posted via http://www.ruby-forum.com/\.