When I write methods that take an optional block, I typically use something like
block.call if block_given?
However, in method defined dynamically like the one below, block_given?
doesn't seem to work.
class Foo
%w[bar baz].each do |method_name|
define_singleton_method(method_name) do |&block|
puts "Was #{method_name} given a block? #{block_given?}"
puts block.call
end
end
end
Foo.bar { puts 'I am a block' }
The block is called as expected, but block_given?
returns false.
Why is this?
Blocks are closures, so they remember local variables (eg method_name
). They also remember blocks: yield
and block_given?
are looking for the block that was active at the time that define_method
was called, not the block passed to bar
. There wasn't one, so block given returns false.
A better illustration of this is
def create_method
define_singleton_method('foo') do |&block|
puts "Was given a block? #{block_given?}"
puts yield
puts block.call
end
end
create_method {'block passed to create_method'}
foo {'block passed to the created method'}
which outputs
Was given a block? true
block passed to create_method
block passed to the created method
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