如何在方法中修补ruby类

时间:2013-07-16 00:22:22

标签: ruby ruby-on-rails-3 metaprogramming monkeypatching

我无法在方法体内修补一个类。

在方法定义中, 我试图以两种方式使用一个类:

1]创建一个实例并使用我正在使用的类中的方法的orignal定义

2]猴子补丁(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 个答案:

答案 0 :(得分:3)

您可以使用class Clazz; blabla; endClazz和其他一些元编程实用程序/方法来执行相同操作,而不是使用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