How to pass the current binding’s block to some other method?

I’ve posted this question to the mailing list but I might as well ask it here too, in case any of my three or four readers know the answer. Suppose I have a method that will yield to a block if one is given:

def try(x, y, z)   # ... do some other stuff first ...   yield self if block_given? end

Such that you can call it like so:

obj.try(1, 2, 3) { |recv| ... do something with recv ... }

Now suppose that I create an alias to this method, for the purpose of overriding how it’s called, e.g.

alias old_try try def try(hash)   old_try(hash[:x], hash[:y], hash[:z]) end

If someone calls this new and improved version of try and provides a block, is there any way for me to somehow pass that block down into oldtry without actually modifying the method signature for oldtry? I had thought maybe there was some trickery I could do with the binding for the “outer” method call (i.e. the one to the new version of try) but that doesn’t appear to be the case.

Posted February 8th, 2007 in Ruby.

6 comments:

  1. Aaron Pfeifer:

    I could be misinterpreting your question, but do you mean something like this?


    alias old_try try
    def try(hash, &block)
    old_try(hash[:x], hash[:y], hash[:z], &block)
    end

  2. mfp:

    As Phrogz showed in the ML:


    # unmodified
    def try(x, y, z)
      (yield * y) if block_given?
    end
    # ^^^^

    alias old_try try

    def try(hash, &block)
      old_try(*hash.values_at(:a, :b, :c), &block)
    end

    try(:a => 1, :b => 5, :c => 3) { "foo" } # => "foofoofoofoofoo"
    RUBY_VERSION # => "1.8.5"

  3. mfp:

    forgot to say that the &Proc.new thing also works, but &block is better and does what you want

  4. Brian:

    could your “new” try method just be something like:

    def try(hash,&block)
    if block
    old_try(hash[:x], hash[:y], hash[:z] ) { |self| block.call(self) }
    else
    old_try(hash[:x], hash[:y], hash[:z])
    end
    end

  5. Lyle:

    @Aaron (and mfp): I was looking for some way that doesn’t require me to modify the original source code for try().

    @Brian: Good idea! I think that should do the trick.

  6. Lyle:

    @Mauricio: OK, I now see that the method that you and Phrogz were recommending does work, at least with a little sample program I wrote. For some reason I didn’t think that it was working properly in my “real” code; I need to go back and see what I was doing differently.

    @Brian: Joel VanderWerf (from the ML) suggested a similar approach, but just doing another “yield self” in the block instead of using block.call(self). I think either one should work similarly.