这是交易:我需要用一些方法扩展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
我有这么好的(和可靠的)方法吗?
答案 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"