3

这是交易:我需要使用一些方法扩展 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而无需像以下那样对类进行猴子补丁:

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

有没有一种漂亮(可靠)的方法可以让我做到这一点?

4

2 回答 2

8

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

box.extend MyModule

此外,由于动词“注入”在 Ruby 中已经具有含义 from Enumerable#inject,因此描述这一点的最佳动词是“扩展”。

于 2011-03-14T05:56:06.253 回答
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"
于 2011-03-14T02:20:40.953 回答