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

On Thu, Jul 31, 2008 at 11:06 AM, Lou Z. [email protected] wrote:

end
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,

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

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

Lou

On Jul 31, 2008, at 19:10, Lou Z. wrote:

=> “”
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.

ERRATUM

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

instead of
replace str

bad mistake of my part sorry.

Robert

On Thu, Jul 31, 2008 at 7:10 PM, Lou Z. [email protected] wrote:

irb(main):028:0> s = NString.new(“hi”)
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

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


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

There’s no one thing that’s true. It’s all true.

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

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.

On Thu, Jul 31, 2008 at 1:47 PM, Lou Z. [email protected] wrote:

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

Lou Z. 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

On Thu, Jul 31, 2008 at 4:51 PM, Lou Z. [email protected] 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 11:03 PM, Gregory B.
[email protected] wrote:

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

-greg
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

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

There’s no one thing that’s true. It’s all true.

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

On Thu, Jul 31, 2008 at 7:10 PM, Lou Z. [email protected] wrote:

irb(main):028:0> s = NString.new(“hi”)
replicate your results:
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 4:51 PM, Lou Z. [email protected] wrote:

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 Fri, Aug 1, 2008 at 7:54 AM, Jesús Gabriel y
Galán[email protected] 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…
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