为什么`block_given?`不能在这个动态定义的方法中工作?

时间:2012-08-22 09:05:40

标签: ruby ruby-1.9 ruby-1.9.3

当我编写采用可选块的方法时,我通常使用类似

的方法
block.call if block_given?

但是,在如下动态定义的方法中,block_given?似乎不起作用。

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' }

按预期调用块,但block_given?返回false。

为什么会这样?

1 个答案:

答案 0 :(得分:9)

块是闭包,因此它们记住局部变量(例如method_name)。他们还会记住阻止:yieldblock_given?正在寻找在调用define_method时处于活动状态的阻止,而不是传递给bar的阻止。没有一个,所以给出的块返回false。

更好的说明是

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'}

输出

Was given a block? true
block passed to create_method
block passed to the created method