Consider the following code:
require 'active_support/concern'
module Inner
end
module Outer
extend ActiveSupport::Concern
included do
include Inner
end
end
class FirstClass
include Outer
end
module SecondInner
end
module SecondOuter
include SecondInner
end
class SecondClass
include SecondOuter
end
Why is the ancestor order different for modules included via AS::Concern vs. plain-old Ruby?
FirstClass.ancestors
# => [FirstClass, Inner, Outer, Object, PP::ObjectMixin, Kernel, BasicObject]
SecondClass.ancestors
# => [SecondClass, SecondOuter, SecondInner, Object, PP::ObjectMixin, Kernel, BasicObject]
答案 0 :(得分:4)
ActiveSupport::Concern
不会更改祖先查找顺序。
如果你改变module Outer
使用纯Ruby来做同样的事情,AS会做什么,但没有AS,你会看到它有相同的祖先链:
module Outer
def self.included(base)
base.send(:include, Inner)
end
end
SecondClass.ancestors
#=> [SecondClass, SecondOuter, SecondInner, Object, PP::ObjectMixin, Kernel, BasicObject]
答案 1 :(得分:0)
Andrey Deineko的回答为理解正在发生的事情提供了重要的基础。
当模块包含在类或其他模块中时会发生什么?有两件事似乎相关:
append_features
被召唤。当这个模块包含在另一个模块中时,Ruby在这个模块中调用append_features,并在mod中传递接收模块。 Ruby的默认实现是将此模块的常量,方法和模块变量添加到mod,如果此模块尚未添加到mod或其祖先之一。另请参见模块#include。
included
被称为只要接收器包含在另一个模块或类中,就会调用回调。如果您的代码想要在模块包含在另一个模块中时执行某些操作,则应该优先使用Module.append_features。
我们无法挂钩append_features
但我们可以在模块中定义included
。
module Inner
def self.included(base)
puts "including #{self} in #{base}"
end
end
module Outer
def self.included(base)
puts "including #{self} in #{base}"
base.send(:include, Inner)
end
end
module SecondOuter
include Inner
def self.included(base)
puts "including #{self} in #{base}"
end
end
class FirstClass
include Outer
end
class SecondClass
include SecondOuter
end
Outer和SecondOuter之间的区别在于Inner
的使用方式。在Outer
中,Inner
包含 ,但仅包含在包含Outer
的其他模块中。但是,在SecondOuter
中,Inner
包含。
将上述代码粘贴到控制台中时,屏幕上会显示以下语句:
including Inner in SecondOuter
including Outer in FirstClass
including Inner in FirstClass
including SecondOuter in SecondClass
第一和第四个陈述解释了SecondClass
祖先的顺序。 Inner
是SecondOuter
的祖先,SecondClass
的祖先是SecondOuter.ancestors
=> [SecondOuter, Inner]
SecondClass.ancestors
=> [SecondClass, SecondOuter, Inner, Object, PP::ObjectMixin, Kernel, BasicObject]
的祖先。因此我们有
FirstClass
第三和第四个陈述说明为什么Inner
的祖先的外部和内部模块顺序是相反的:
首先,Outer
不是Outer
的祖先。
其次,FirstClass
在Inner
之前包含Inner.included
,但 Outer.included
在Outer.ancestors
=> [Outer]
FirstClass.ancestors
=> [FirstClass, Inner, Outer, Object, PP::ObjectMixin, Kernel, BasicObject]
之前解析。这导致
include SomeModule
当我们扩展AS :: Concern并在included do
块中添加SomeModule
语句时,我们实际上包括Outer
类似于上面{{1}}的方式。< / p>