Passing around Ruby blocks
I have some code that I am bundling together that required me to tackle a rather strange problem. Basically, I had one function that took a block, and another function that wrapped around that function. It looks something like this:
def inner(*args) yield args[0], args[1]*args[2] end def wrapper inner(3,4,5) end
The question is, how do I pass a block to wrapper and have it get passed to inner? Google wasn’t much help here. My solution looks like:
def call_block yield 4, 5, 6 end def wrap_block(&blk) call_block { |*args| blk.call(*args) } end wrap_block { |x,y,z| puts x+y+z }
Would love to see a smarter solution…
June 16th, 2010 at 8:01 am
wrap_block is redundant in ruby.
This works just as well.
def call_block
yield 4, 5, 6
end
call_block { |x,y,z| puts x+y+z }
June 16th, 2010 at 8:41 am
I think you’re missing the point. The point is, if I have an internal function that I want to call with the block passed in to the outer function, how do I do it without having to use Procs (well, & binds the block to a Proc … but I mean explicitly)? So, for example:
def private_inner_function(a, b, c)
yield a+b+c
end
def public_outer_function(x, y, z, &blk)
inner_function(x+y, z, z-y) { |*args| blk.call(*args) }
end
outer_function(1, 2, 3) { |x| puts x }
Unless, of course, I missed your point…
June 16th, 2010 at 12:50 pm
Your Code:
def private_inner_function(a, b, c)
yield a+b+c
end
def public_outer_function(x, y, z, &blk)
private_inner_function(x+y, z, z-y) { |*args| blk.call(*args) }
end
public_outer_function(1, 2, 3) { |x| puts x }
Much Clearer Version (get rid of the extra explicit blk.calls)(I think this is what you were after?):
def private_inner_function(a, b, c)
yield a+b+c
end
def public_outer_function(x, y, z, &some_random_anonymous_function)
private_inner_function(x+y, z, z-y, &some_random_anonymous_function)
end
public_outer_function(1, 2, 3) { |x| puts x }
Yes? Every method in ruby is expecting that you are going to pass it an optional block, so the &blk reference in the public_outer_function would be redundant except that you’re trying to pass the anonymous function to another method, in which case you need to name your anonymous function.
The nuance (at least the way I understand it) is that ruby methods are already expecting an anonymous block, so you don’t need to name your block, UNLESS you planning on passing the block on to another method (as you are). It’s not until you need to pass reference to that anonymous block that you need to even give it a name (&blk, or &whatever_block).
If you’re using using a proxy pattern just to get in front of the internal_method, this is a simpler example, without arguments:
def private_call_block
yield 4, 5, 6
end
def public_call_block(&blk)
private_call_block(&blk)
end
public_call_block { |x,y,z| puts x+y+z }
Your first example didn’t illustrate that you were actually doing anything with the public_method, altering the arguments, before passing it along to the internal method.
June 16th, 2010 at 12:57 pm
Kirk,
That is indeed much cleaner! Thank you very much for sharing the info. Learn new things every day.