Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does adding a block to Object.send pass it to the called method?

Tags:

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 } 
like image 801
Hal Avatar asked Jan 12 '12 06:01

Hal


People also ask

How do you pass block to method in Ruby?

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.

What is the difference between a lambda a block and a proc?

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.

Is block an object in Ruby?

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.


2 Answers

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 
like image 125
mu is too short Avatar answered Oct 30 '22 11:10

mu is too short


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!

like image 39
ligfx Avatar answered Oct 30 '22 10:10

ligfx