Как использовать define_method во включенном модуле для создания методов? - PullRequest
0 голосов
/ 17 октября 2019

Мне нужен метод класса step, который динамически создает методы экземпляра.

step(:start) do |payload|
  puts payload
end

Это создаст эквивалент:

def start(payload)
  payload
end

Проблема, с которой я сталкиваюсь, заключается вполучение блока, переданного в метод класса, оценивают в контексте экземпляра.

Кажется, проблема в том, что блок, поскольку он является замыканием, оценивается в контексте того, где был определен класс.

module Steps
  def step(name, &block)
    define_method(name) do |payload|
      self # => Foo instance
      block.call(payload)
    end
  end
end

class Foo
  extend Steps

  step(:start) do |payload|
    self # => Foo class
    payload # => 1
    self.data # => undefined method `data' for Foo:Class (NoMethodError)
  end

  def data
    'DATA'
  end
end

puts Foo.new.start(1)

Можно ли оценить блок в контексте экземпляра?

Самое близкое, что я получил, - это использование instance_eval, однако я не могу понять, какпередать аргумент payload в блок:

define_method(name) do |payload|
  instance_eval(&block)
end

Когда я делаю выше self в переданном блоке, это экземпляр Foo, поэтому я могу вызвать data, но как получить доступpayload

1 Ответ

0 голосов
/ 17 октября 2019

instance_exec

Выполняет данный блок в контексте получателя (obj). Чтобы установить контекст, переменная self устанавливается в obj во время выполнения кода, предоставляя коду доступ к переменным экземпляра obj. Аргументы передаются как параметры блока.

define_method(name) do |payload|
  instance_exec(payload, &block)
end

ref: Изменить привязку блока без оценки?

...