Выполнять динамические вызовы методов, используя обработчик NoMethodError вместо method_missing - PullRequest
1 голос
/ 27 января 2010

Я пытаюсь создать API для динамических процессов перезагрузки; прямо сейчас я нахожусь в точке, где я хочу предоставить во всех контекстах метод с именем reload!, однако я реализую этот метод для объекта, который имеет некоторое состояние (поэтому он не может быть в ядре).

Предположим, у нас есть что-то вроде

WorkerForker.run_in_worker do
  # some code over here...
  reload! if some_condition
end

Внутри метода run_in_worker есть код, подобный следующему:

begin
  worker = Worker.new(pid, stream)
  block.call
rescue NoMethodError => e
  if (e.message =~ /reload!/) 
    puts "reload! was called"
    worker.reload! 
  else
    raise e
  end
end

Так что я делаю это таким образом, потому что я хочу сделать метод reload! доступным в любом вложенном контексте, и я не хочу связывать получаемый блок с instance_eval на worker экземпляр.

Итак, мой вопрос: есть ли какие-либо сложности в отношении этого подхода? Я не знаю, сделал ли кто-нибудь это уже (еще не читал так много кода), и если это уже было сделано? Есть ли лучший способ достичь цели этого кода?

Ответы [ 3 ]

1 голос
/ 29 января 2010

Если я вас сейчас понимаю, как насчет этого:

my_object = Blah.new
Object.send(:define_method, :reload!) { 
    my_object.reload!
    ...
}

Используя этот метод, каждый объект, который вызывает метод reload!, изменяет одно и то же общее состояние, поскольку my_object захватывается блоком, переданным в define_method

0 голосов
/ 29 января 2010

Похоже, вы просто хотите, чтобы каждый метод знал об объекте без того, чтобы об этом методе или владельце метода не было сказано. Способ сделать это - глобальная переменная. Обычно это не считается хорошей идеей (потому что это приводит к проблемам параллелизма, проблемам владения, усложняет модульное тестирование и т. Д.), Но если это то, что вам нужно, то это так.

0 голосов
/ 27 января 2010

что не так с этим делать?

def run_in_worker(&block)
    ...
    worker = Worker.new(pid, stream)
    block.call(worker)
end

WorkerForker.run_in_worker do |worker|
    worker.reload! if some_condition
end
...