Переопределенный метод с выходом не выбрасывает блок - PullRequest
0 голосов
/ 07 января 2012

Может кто-нибудь объяснить, почему последний получатель бросает указанный блок?

class Foo
  def yielder
    yield "hello"
  end
end

class Mod

  def initialize
    @@foo = Foo.new
  end

  def self.foo
    @@foo
  end

end

worker = Mod.new

Mod.foo.yielder do |hello|
  puts hello
end

Mod.foo.class.send(:define_method,:yielder) do
   yield "new hello"
end

Mod.foo.yielder do |hello|
  puts hello
end

Дает:

привет
test.rb: 27: в блоке in': блок не указан (yield) (LocalJumpError)
из test.rb: 30: in `'

1 Ответ

3 голосов
/ 07 января 2012

Краткое введение:

Вам не нужен экземпляр Mod, если вы определяете @@ foo снаружи initialize.

Вам не нужен класс Mod для решения проблемы:

class Foo
  def yielder
    p 2
    yield "hello"
  end
end
foo = Foo.new

foo.yielder do |hello|
  puts hello
end

foo.class.send(:define_method,:yielder) do
  p 1
   yield "new hello"
end

foo.yielder do |hello|
  puts hello
end

Вы можете снова сократить свой пример:

class Foo
end
foo = Foo.new

foo.class.send(:define_method,:yielder) do
   yield "new hello"
end

foo.yielder do |hello|
  puts hello
end

Это то же самое, что и

class Foo
  define_method(:yielder) do
    yield "new hello"
  end
end

foo = Foo.new
foo.yielder do |hello|
  puts hello
end

Конец введения.

А теперь я не уверен, правильно ли я понял, что вы хотите (и если я правильно понимаю, рубин правильно;)) define_method принимает блок и использует его как тело метода. Если новый метод должен получить блок самостоятельно, вы должны определить его в интерфейсе определения и вызвать его:

class Foo
  define_method(:yielder) do | &prc |
    prc.call("new hello")
  end
end

foo = Foo.new
foo.yielder do |hello|
  puts hello
end

Или та же логика в вашем примере:

class Foo
  def yielder
    yield "hello"
  end
end

class Mod

  def initialize
    @@foo = Foo.new
  end

  def self.foo
    @@foo
  end

end

worker = Mod.new

Mod.foo.yielder do |hello|
  puts hello
end

Mod.foo.class.send(:define_method,:yielder) do | &prc |
   prc.call "new hello"
end

Mod.foo.yielder do |hello|
  puts hello
end

Чтобы сделать код более устойчивым, я бы порекомендовал некоторые проверки с block_given?.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...