4

我有一个类 Ryte::Theme。如果我在课堂上调用included_modules,我会回来(缩写):

[Ryte::Bundleable::Core、Ryte::Bundleable::Validators、Ryte::Bundleable::Builder、ActiveModel::Validations::HelperMethods、ActiveModel::Validations、ActiveSupport::Callbacks、Ryte::Bundleable]

Ryte::Theme 通过单个模块 Ryte::Bundleable 引入嵌套模块。以下是相关的类和模块定义:

class Ryte::Theme
  include Ryte::Bundleable
end


module Ryte::Bundleable
  extend ActiveSupport::Concern

  included do
    include ActiveModel::Validations
    include Ryte::Bundleable::Builder
    include Ryte::Bundleable::Validators
    include Ryte::Bundleable::Core
  end
end

鉴于此,为什么我会收到以下回复:

Ryte::Theme.include?(Ryte::Theme::Validators)
=> true

我还没有包含这个附加模块。这在 included_modules 响应中很明显。这与 ActiveSupport 关注有关吗?我希望能够包含 Ryte::Theme::Validators 并将其混入,但由于它认为它已经被包含,它不会“再次”包含它(如果这是真的,它不应该包含它)。因此,当我将包含添加到类定义中时,它会被遗忘,如下所示:

class Ryte::Theme
  include Ryte::Bundleable
  include Ryte::Theme::Validators # <- Does not load
end

为什么这个额外的模块 Ryte::Theme::Validators 也没有混合在一起?

添加

好的,刚刚意识到:

1.9.3p194 :005 > Ryte::Bundleable::Validators == Ryte::Theme::Validators
 => true 

奇怪..这是为什么?

4

1 回答 1

6

更新:这ActiveSupport::Concern 有关(见下文)。

尝试以下操作:

# initialize constants
class A; end                               # class Ryte
module A::B; end                           # module Ryte::Bundleable
module A::B::C; end                        # module Ryte::Bundleable::Validators

module A::B                                # module Ryte::Bundleable
  def self.include(base)
    base.class_eval do
      include A::B::C                      # include Ryte::Bundleable::Validators
    end
  end
end

class D                                    # class Ryte::Theme
  include A::B                             # include Ryte::Bundleable
end

A::B::C == D::C                            #=> true

发生这种情况是因为模块和类的命名空间方式:当您A::B::C从内部包含时A::B,模块名称是相对于模块本身引用的,它变成了 just C(在您的情况下, just Validators)。因此,当您A::B在其他类D中包含而不是包含名为A::B::C(ie Ryte::Bundleable::Validators) 的模块时,ruby 包含一个名为C(ie Validators) 的模块。这就是为什么Ryte::Bundleable::Validators == Ryte::Theme::Validators评估为真。

但是,对于上面的示例:

D.include?(A::B::C)                       #=> false

所以这就是ActiveSupport::Concern开始的地方。重新定义上面的模块A::B,如下所示:

module A::B                                # module Ryte::Bundleable
  extend ActiveSupport::Concern

  included do
    include A::B::C                      # include Ryte::Bundleable::Validators
  end
end

你会发现D.include?(A::B::C)现在评估为真。老实说,我不确定为什么会发生这种情况,但它一定与上面的命名空间有关。

于 2012-09-09T06:30:55.443 回答