动态地将模块中的方法添加到类的特定实例

时间:2011-03-14 02:11:56

标签: ruby singleton eval local-variables eigenclass

这是交易:我需要用一些方法扩展class Box的特定实例。我需要包含实时内部模块的方法,我希望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

但是我没能让eigenclass运行 class_eval 而不用monkeypatching这个类:

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

我有这么好的(和可靠的)方法吗?

2 个答案:

答案 0 :(得分:8)

您需要将模块中的方法动态添加到Box的特定实例Kernel#extend方法:

box.extend MyModule

另外,因为动词“to inject”已经在Enumerable#inject的Ruby中具有含义,所以描述它的最佳动词是“扩展”。

答案 1 :(得分:3)

我不能在那里遵循你的推理。 self.class.class_eval会在您的示例中正常运行,如下所示:

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

编辑:澄清评论。

使用Object#extend在模块中包含方法作为类方法(比如在本征类中定义它们),如下所示:

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"