Ключом к этой черной магии является instance_eval
, который оценит блок в контексте его получателя.Обычно self
внутри блока будет определяться областью действия;instance_eval
изменит self
внутри своего блока на то, что получило сообщение instance_eval
.
class Dog
def bark
puts "Woof"
end
def initialize(&block)
instance_eval(&block)
end
end
Dog.new { bark }
# => "Woof"
В этом случае instance_eval(&block)
совпадает с self.instance_eval(&block)
, что означает self
внутри блока будет экземпляр Dog
;тогда bark
- это, конечно, self.bark
, где self
- это Dog
.
Существует школа мысли, что instance_eval
является вредным .Я согласен, что лучше всего ограничить его использование четко определенными DSL.То есть это может работать для TK, RSpec или Sinatra, но если вы думаете, что это круто и хотите использовать его, хорошо подумать дважды.