2013-07-16 32 views
0

我无法为方法体内的类修补一个类。如何在一个方法内部修补一个ruby类

在方法内部定义, 我试图以两种方式使用类:

1]创建一个实例,并使用方法的一部开拓创新的定义在类中我使用

2] Monkey patch(pverride)类中的一种方法,现在使用带有新方法定义的实例。

基本上我会在我的程序中使用上述两个类的实例。

挑战是我重写的方法在初始化期间被调用,所以我必须在创建类的实例之前重写它。

这里是一个小样本:

class A 

    def initialize 
    do_something 
    end 

    def do something 
    #implementation 
    end 

end 

现在,我想用相同的方法两次,但一旦使用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 

我得到的(错误:方法体类DEF),我尝试猴子修补类,因为我试图改变一个方法的内部类。

如何在一种方法中实现猴子修补类?

感谢

+1

你得到上面的错误?哪个错误?这是C级,而不是C级。 – oldergod

+0

对不起,如果您浏览了代码,您可能会错过代码中标记的错误。为了清晰起见,再次编写它 – codeObserver

+0

稍微无关,但我很确定''//在红宝石中不标记注释 –

回答

3

而不是使用class Clazz; blabla; end重新Clazz和猴子打补丁,你可以使用Module#class_evalModule#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 
+0

谢谢@爱丽。你能解释一下,为什么必须添加给定类A的单例实例已经被修补以使用新的方法定义。它并不清楚“class << new_instance; self end”在做什么,特别是在新实例已经创建之后。 – codeObserver

+0

@codeObserver我认为你想修改一个特殊实例的实例方法(从创建开始并持续实例的整个生命周期)。如果您没有为特殊的'new_instance'修复猴子修补方法,'new_instance'将在恢复后使用方法的原始实现。对singleton实例的猴子补丁使新方法在'new_instance'的整个生命周期中被使用。如果你只是想在创建过程中改变行为,你可以省略singleton类的补丁。 –

+0

@codeObserver'class << new_instance; self end'返回'new_instance'的特征类(或单例类,〜Google it〜)。这是与'new_instance'关联的特殊类。在该类中定义的所有方法只会对'new_instance'可见。所以这就是猴子修补给定实例而不是给定类的所有实例的方法。 –

相关问题