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

Accessing Resources in Java, use of getResource method of Class and ClassLoader, How to access test data in unit tests

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

TCPView