我注意到 Rails 源代码中有几个地方使用了 module_eval
。一个地方在ActiveRecord::Enum另一个在 ActiveRecord::Store .我熟悉 class_eval
和 instance_eval
并使用它们来扩展现有类或对象的功能,但对于 module_eval
,它似乎有不同的用途。
在这两种情况下,他们都使用相似的模式来定义模块:
def _store_accessors_module
@_store_accessors_module ||= begin
mod = Module.new
include mod
mod
end
end
如果模块包含在定义它的类中,那么在这样的嵌套模块中定义相关方法有什么好处?代码隔离更好吗?我问的原因是因为我有一个 gem 可以为 Active Record 添加功能,并且想知道这种方法是否更像是做同样事情的“最佳实践”方式。 Here's the relevant source code of my gem供引用。
最佳答案
在嵌套模块中定义方法的原因是用户可以覆盖这些方法并仍然可以访问 super
以获取原始功能。回想一下,当您在 Ruby 中包含模块时,它们被插入到当前类的祖先列表中,super
的工作方式是简单地遍历祖先数组,寻找响应当前方法的第一个对象。为此,模块的名称并不重要,因为它只是一种类似继承链的传递机制。所以这就是为什么他们只定义一个匿名的新模块并即时包含它。
如果您查看您列出的 2 个示例的责备 View ,您可以看到更改背后的原因。 commit message in the ActiveRecord::Store example使情况非常好。如您所见,他们添加了覆盖访问器定义 color
并通过 super || 附加到原始方法结果的能力。 '红色'
。然而,在最初的实现中,必须重写 color
访问器方法,然后执行与原始访问器方法相同的工作,即调用 read_store_attribute(:settings, :color) | | '红色'
。因此,这一切都是为了不被迫重现内部结构或使用别名方法链来增强动态定义方法的功能。
我不确定这在您的 gem 中是否是一个有用的功能,但我猜可能不是,因为您的访问器似乎正在返回定义明确的对象枚举相关对象。但是,当然,这取决于您和 gem 的用户 :)。
关于ruby-on-rails - 为什么 Active Record 在内部使用 module_eval 来实现某些功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24909410/