6

オプションのブロックを取るメソッドを書くとき、私は通常、次のようなものを使用します

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を返します。

どうしてこれなの?

4

1 に答える 1

9

ブロックはクロージャーであるため、ローカル変数 ( などmethod_name) を記憶します。また、 blocks:yieldを記憶し、 に渡されたブロックではなく、呼び出さblock_given?れた時点でアクティブだったブロックを探しています。1 つもなかったので、指定されたブロックは false を返します。define_methodbar

これのより良い例は

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
于 2012-08-22T10:08:09.997 に答える