Как обезьяна заплатить рубиновый класс внутри метода

Я не могу обезьяны заплатить класс внутри тела метода.

В рамках определения метода, Я пытаюсь использовать класс двумя способами:

1] Создайте экземпляр и используйте определение orignal метода в классе, который я использую

2] Monkey patch (pverride) метод в классе и теперь используйте экземпляр с новым определением метода.

В принципе, я бы использовал оба вышеуказанных экземпляра класса в своей программе.

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

Вот небольшой макет:

class A

  def initialize
   do_something
  end

  def do something
     #implementation
  end

end

Теперь я хочу использовать A в том же методе дважды, но один раз с помощью модифицированной версии do_something Вот как я пытаюсь это сделать:

def my_method

  orig_instance = A.new

  #patch the class
  Class A          # ERROR: CLASS DEF IN METHOD BODY
   class << self
     alias_method :old_do_something, :do_something

     def self.do_something
        # new implementation
     end
  end

  new_instance = A.new

  #restore method
   class << self
     alias_method :do_something,:old_do_something

     def self.do_something
        # new implementation
     end
  end        



end # end of method

Я получаю (ERROR: CLASS DEF IN METHOD BODY), где я пытаюсь обезглавить патч класса, так как я пытаюсь изменить класс внутри метода.

Как достичь обезьяны, исправляющей класс в методе?

Спасибо

Ответ 1

Вместо использования class Clazz; blabla; end для повторного открытия Clazz и патча обезьяны вы можете использовать Module#class_eval, Module#instance_eval и некоторые другие утилиты/методы метапрограммирования, чтобы сделать тот же трюк. И поскольку этот блок, принятый этими методами, не создает новые области привязки, он более удобен в практике метапрограмм.

def my_method
  puts ">> creating orig_instance"
  orig_instance = A.new

  puts ">> dump orig_instance"
  orig_instance.do_something

  new_do_something = lambda do
    puts "Modified A#do_something"
  end

  # monkey patch class A so that the modified version of do_something get called
  # during initialization of new_instance
  A.class_eval do
    alias_method :old_do_something, :do_something
    define_method :do_something, new_do_something
  end

  puts ">> creating new_instance"
  new_instance = A.new

  puts ">> dump before do_something gets restored"
  new_instance.do_something
  orig_instance.do_something

  # add singleton method for the special instance
  # so that the instance always calls the modified do_something
  new_instance_singleton = class << new_instance; self end
  new_instance_singleton.send :define_method, :do_something, new_do_something

  # restore the modified do_something
  # so that orig_instance and all other instances (except new_instance) have the original definition
  A.class_eval do
    alias_method :do_something, :old_do_something
  end
  puts ">> dump for final result"
  new_instance.do_something
  orig_instance.do_something
end

И вот результат вызова my_method:

>> creating orig_instance
Original A#do_something
>> dump orig_instance
Original A#do_something
>> creating new_instance
Modified A#do_something
>> dump before do_something gets restored
Modified A#do_something
Modified A#do_something
>> dump for final result
Modified A#do_something
Original A#do_something