I\'m not making sense of the following behavior (see also in this SO thread):
def def_test
puts \'def_test.in\'
yield if block_given?
puts \'def_test.o
block_given?
considers def
scope, not lambda
scope:
def test
l = lambda do
yield if block_given?
end
l.call
end
test { puts "In block" }
The lambda
is a closure and it seems to be capturing the block_given? and block from its outer scope. This behavior does make sense as the block is, more or less, an implied argument to the outer method; you can even capture the block in a named argument if desired:
def def_test(&block)
frobnicate &block
end
So the block is part of the argument list even when it isn't named.
Consider this simple piece of code:
def f
lambda do
puts "\tbefore block"
yield if block_given?
puts "\tafter block"
end
end
puts 'Calling f w/o block'
x = f; x.call
puts
puts 'Calling f w/ block'
x = f { puts "\t\tf-block" }; x.call
puts
puts 'Calling f w/o block but x with block'
x = f; x.call { puts "\t\tx-block" }
puts
puts 'Calling f w/ block and x with block'
x = f { puts "\t\tf-block" }; x.call { puts "\t\tx-block" }
This produces the following for me with 1.9.2:
Calling f w/o block
before block
after block
Calling f w/ block
before block
f-block
after block
Calling f w/o block but x with block
before block
after block
Calling f w/ block and x with block
before block
f-block
after block
Furthermore, Proc#call (AKA proc ===
) doesn't take a block:
prc === obj → result_of_proc
Invokes the block, with obj as the block‘s parameter. It is to allow a proc object to be a target of when clause in the case statement.
Compare the first line with the documentation for Enumerable#chunk (for example):
enum.chunk {|elt| ... } → an_enumerator
The {...}
indicates that chunk
is documented to take a block, the lack of such notation for Proc#call
indicates that Proc#call
does not take a block.
This isn't exactly an authoritative answer but maybe it clears things up a little bit.