define_method と block_given?(Ruby)

Ruby でメソッドにブロックが与えられているかを確認する、Kernel#block_given?というメソッドがある。

def foo
  p block_given?
end

foo       #=>false
foo {}    #=>true

 
これが、メソッドをModule#define_methodで定義した場合、使えない。

define_method(:foo) do
  p block_given?
end

foo       #=>false
foo {}    #=>false

というか、そもそもこの場合、yieldが使えないので、ブロックは Procオブジェクトで与えてやることになる。

define_method(:foo) do
  yield
end
#=>Invalid yield (SyntaxError)

define_method(:foo) do |&bk|
  bk.call
end

 
では、こうするとして、block_given?はどういう手段で代替するか。
それは、ブロックが与えられていない場合、bknilになることを使えば、実現できそうである。

define_method(:foo) do |&bk|
  p bk    #ブロックが与えられていなければnilになる
  bk.call if bk
end

foo       #=>nil
foo {}    #=>#<Proc:0x00007f1464fe6508>

 
※参考
bugs.ruby-lang.org