2014-07-23 37 views
4

我注意到在使用module_eval的Rails源代码中有一些地方。一个地方在ActiveRecord::Enum,另一个在ActiveRecord::Store。我熟悉class_evalinstance_eval并用他们扩展现有的类或对象的功能,但在module_eval的情况下,好像它服务于不同的目的。为什么Active Record在内部为某些功能使用module_eval?

在这两种情况下,他们使用的是类似的模式来定义模块:

def _store_accessors_module 
    @_store_accessors_module ||= begin 
    mod = Module.new 
    include mod 
    mod 
    end 
end 

如果被包含在它的定义在类模块,有什么好处是有定义一个嵌套模块中的相关方法喜欢这个?是否更好地隔离代码?我问的原因是因为我有一个为Active Record增加功能的创业板,我想知道这种做法是否更像是做同样事情的“最佳做法”。 Here's the relevant source code of my gem仅供参考。

回答

3

嵌套模块中被定义的方法的原因是,使用户可以覆盖的方法,仍然有机会获得super获得的原始功能。回想一下,当您在红宝石他们只是通过祖先数组迭代,查找响应当前方法的第一个对象插入到祖先列表当前类和super作品模块。为此,模块的名称并不重要,因为它只是一个继承链式的传递机制。所以这就是为什么他们只是定义一个匿名的新模块并将它包含在内。

如果您查看列出的2个示例的错误视图,可以看到更改背后的推理。 commit message in the ActiveRecord::Store example使情况相当好。正如您所看到的,他们添加了覆盖访问器定义color的功能,并通过super || 'red'添加了原始方法的结果。然而,在原始实现中,人们不得不重写color访问器方法,然后执行与原始访问器方法相同的工作,即调用read_store_attribute(:settings, :color) || 'red'。所以它不是被迫重现内部结构或使用别名方法链来增强动态定义方法的功能。

我不知道这是否是在你的宝石一个非常有用的功能,但我猜,也许并不像你存取似乎恢复良好定义的对象枚举相关的对象。但是,当然,这取决于你和宝石的用户:)。

+0

感谢您的详细解释! –

相关问题