I just completed the Ruby Koans, and neither the unit on calling methods using Object.send nor the Ruby documentation on the method provides any information on using blocks with the send method. Will a block attached to the send method be passed to the method it calls, or will the block be lost?
Example:
foo.send(:a_method) { bar.another_method }
In Ruby, methods can take blocks implicitly and explicitly. Implicit block passing works by calling the yield keyword in a method. The yield keyword is special. It finds and calls a passed block, so you don't have to add the block to the list of arguments the method accepts.
A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Lambdas are anonymous functions, objects of the class Proc, they are useful in most of the situations where you would use a proc.
A block is the same thing as a method, but it does not belong to an object. Blocks are called closures in other programming languages. There are some important points about Blocks in Ruby: Block can accept arguments and returns a value.
The documentation is a bit unclear on this:
send(symbol [, args...]) → obj
Invokes the method identified by symbol, passing it any arguments specified.
But note the any arguments specified part. The block that you give to a method is really a funny type of implicit argument so that you can do things like:
def m(&b) @a.each(&b) end m { |e| puts e }
to pass the block around as a Proc instance. However, you can also do this:
def m yield end m { puts 'pancakes' }
so the block is special as far as the argument list is concerned but the block still behaves as an argument even if it is sometimes implicit.
Given the above "block is sort of an argument" rambling and the importance of blocks in Ruby, it would be reasonable for send
to pass the block through. You can also try it but you have to careful about accidental and undocumented behavior with the "try it" approach:
class C def m yield end end o = C.new o.send(:m) { puts 'pancakes' } # "pancakes" comes out
Yes. Consider the following:
class A def explicit(&b); b; end def implicit; yield "hello"; end end >> A.new.send(:explicit) { } => #<Proc:0x0000000000000000@(irb):19> >> A.new.send(:implicit) { |greeting| puts greeting } hello => nil
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With