2011-03-14 64 views
3

以下是处理:我需要使用某些方法扩展具体类的实例。我需要包括模块内的生活方式,我希望Box实例能够包括动态模块。 我现在用一个钩子与一个eval:将模块中的方法动态添加到类的特定实例中

class Box 
    def after_initialize 
    if self.injected_module.present? 
     eval("class << self; include #{self.injected_module}; end") 
    end 
    end 
end 

这是合作得非常好,但我真的觉得脏当我使用EVAL。我正在寻找类似的东西:

module_to_inject = self.injected_module 
self.eigenclass.class_eval do 
    include module_to_inject 
end 

但我不能没有的Monkeypatching类,如能够得到eigenclass上运行class_eval

class Box; def eigenclass; class << self; self; end end end 

有一个美丽的(和可靠)的方式来做到这一点?

回答

8

所有你需要从模块添加方法的Box具体情况动态地为该Kernel#extend方法:

box.extend MyModule 

而且,因为动词“注入”已经从Enumerable#inject在Ruby中一个意思,用于描述最好的动词,这是“延长”。

+0

非常感谢!它像一个魅力一样工作! – 2011-03-14 12:53:41

3

我无法跟随你的推理。 self.class.class_eval会工作得很好在你的榜样,像这样:

class Box 
    def after_initialize 
    self.class.class_eval do 
     include(self.injected_module) 
    end 
    end 
end 

编辑:澄清意见。

使用Object#extend包括在一个模块类方法的方法(像在eigenclass会定义它们),像这样:

module MyModule 
    def method 
     puts "called from #{self.inspect}" 
    end 
end 

class Box 
    def self.injected_module 
     MyModule 
    end 

    def require_module 
     self.class.class_eval do 
      extend self.injected_module 
     end 
    end 
end 

b = Box.new 
b.require_module 
Box.method 
# prints "called from Box" 
+0

这个解决方案的问题是它将一个方法添加到类本身中,而不是放入_eigenclass_中。这样,如果我在执行此代码后创建另一个Box实例,该实例将获得新方法。我正在寻找将方法作为单例方法包含到我创建的实例中! – 2011-03-14 02:42:28

+0

我无法遵循这个推理。你似乎有“特征类”的概念困惑。 “eigenclass”是类的同义词,直接在类上调用的方法,如“Box.method”。然而,在这里,你将一个Module包含到一个类中,定义了实例方法。你能否试图澄清你究竟想要什么? – 2011-03-14 03:12:10

+0

我最好的猜测是你要返回一个单例实例,并希望将一个模块的方法作为类方法添加,所以你可以调用'Box.method'而不是调用实例的方法,比如'Box.instance.method' 。您应该使用[Object#extend](http://www.ruby-doc.org/core/classes/Object.html#M001002),而不是使用include。 – 2011-03-14 03:18:00