动态地将模块中的方法添加到类的特定实例
Posted
技术标签:
【中文标题】动态地将模块中的方法添加到类的特定实例【英文标题】:Add methods from modules to specific instances of a class dynamically 【发布时间】:2011-07-14 17:22:04 【问题描述】:这是交易:我需要使用一些方法来扩展 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
我是否有一种漂亮(且可靠)的方式来做到这一点?
【问题讨论】:
【参考方案1】:我无法理解你的推理。 self.class.class_eval
在您的示例中可以正常工作,如下所示:
class Box
def after_initialize
self.class.class_eval do
include(self.injected_module)
end
end
end
编辑:澄清 cmets。
使用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"
【讨论】:
这个解决方案的问题是它在类本身中添加了一个方法,而不是在eigenclass中。这样,如果我在执行此代码后创建另一个 Box 实例,该实例将获得新方法。我希望将这些方法作为单例方法包含到我正在创建的实例中! 我也无法理解这种推理。您似乎对“特征类”的概念感到困惑。 “eigenclass”是类的同义词,直接在类上调用的方法,如Box.method
。然而,在这里,您将一个模块包含到一个类中,定义实例方法。你能试着澄清一下你到底想要什么吗?
我最好的猜测是,您正在返回一个单例实例,并希望将 Module 中的方法添加为类方法,因此您可以调用 Box.method
而不是调用实例上的方法,例如 @987654331 @。然后你应该使用Object#extend 而不是包含。
据我所知,eigenclass 不是 link 类的同义词 - 让我直截了当地说:我有一个 Box 的实例,我们称之为 boxie .我想将方法添加到 boxie(例如,可以通过其 eigenclass 拥有自己的方法),而不是 Box(class)。我要添加的方法位于模块 M 中,但如果不使用eval
,我无法将它们包含到实例中,因为我无法将“实例方法”动态地直接包含到特征类中。
eigenclass
在 ruby 术语中是 singleton class
。 class << self
习惯用法使 self 成为定义方法的上下文,因此您定义的是类方法而不是实例方法。阅读this question 了解更多详情。你链接的是ruby的方法查找树。您只需要自己回答:您希望 Module 中的方法是实例方法(对于 boxie)还是类方法(对于 Box) - 第一个使用 include
,后者使用 extend
。【参考方案2】:
您需要动态地将模块中的方法添加到 Box
的特定实例是 Kernel#extend
方法:
box.extend MyModule
另外,因为动词“to injection”在Enumerable#inject
的Ruby 中已经有了意义,描述这一点的最佳动词是“to extend”。
【讨论】:
以上是关于动态地将模块中的方法添加到类的特定实例的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将参数传递给 Django 中的基于类的视图实例?