Making sense out of ruby's dynamic method calls

Case 1:

def n
puts "inside n"
end

def m(&m2)
m2.call
end

m(&method(:n))
m() {puts "hello"}

>> inside n
>> hello


Case 2:

def m()
yield
end
m(&method(:n))
m() {puts "hello"}

>> inside n
>> hello

Case 3:

def m(&m2)
m2.call
yield
p m2.class
end

m(&method(:n))
m() {puts "hello"}

>> inside n
>> inside n
>> Proc
>> hello
>> hello
>> Proc


Case 4: (Adding checking before calling)

def m(&m2)
m2.call unless m2.nil?
end

def m
yield if block_given?
end

Case 5:

p = Proc.new(&method(:n))
p.call
m(&p)

>> inside n #p.call
>> inside n #m(&p)

Case 6:
p = Proc.new() {puts 'hello'}
p.call
m(&p)

>> hello #p.call
>> hello #m(&p)

Case 7:

p = method(:n).to_proc
m(&p)

>> inside n


Conclusions and Summary
- The decision of using yield or call in a method does not affect how the method is invoked. It can be given a block or a &Proc, or a &Method.
- If yield is used, then block_given? is used for checking.
- If call is used, then nil? is used for checking.
- For a method m, a parameter of the form &m2 can only appear at the end of the parameter list (therefore, at most once). This parameter corresponds to a block, or a &Proc, or a &Method.
- A method symbol (or a function pointer) can be created using "method(:)" (note the usage of ':' to obtain a symbol).
- A procedure can be created using "Proc.new(&x)" where x is a Method or a Proc. A procedure can also be created using Proc.new() {...} via a block.

Comments

capsid said…
Great post! I had trouble figuring out what ruby's ampersand was for until I read this.

Many thanks.

Popular posts from this blog

Creating an HTTP Streaming Client in Silverlight

The Order of Rails Validation Filters

Comparison of equality operators in Ruby: == vs. equal? vs. eql? vs. ===