Это разница в семантике def
и define_method
. Смотрите это:
module M
def outer(&block)
puts "outer: #{yield}"
def inner1
puts "inner1: #{yield}"
end
M.define_method(:inner2) do
puts "inner2: #{yield}"
end
M.define_method(:inner3) do |&block|
puts "inner3: #{block.call}"
end
inner1 { 1 }
inner2 { 2 }
inner3 { 3 }
end
end
class A
include M
end
A.new.outer { 0 }
# => outer: 0
# inner1: 1
# inner2: 0 (!!!)
# inner3: 3
yield
работает только внутри def
.
Таким образом, inner1
вызывает свой собственный блок;но inner2
использует блок def
, в котором он находится. Правильный способ вызвать блок внутри define_method
- захватить его в списке параметров (как вы это сделали), а затем использовать #call
или #[]
на нем, как показывает inner3
.
В вашем коде нет def
вокруг, поэтому при вашем yield
блок недоступен. Вы можете использовать вышеуказанный метод и заменить yield
на block.call
.