为什么ruby响应我已经混合了一个模块,当我还没有包含它?

时间:2012-09-09 00:39:37

标签: ruby-on-rails ruby

我有一个类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并将它混合在一起,但因为它认为它已经被包含在内,所以它不会再次包含它(因为它不应该包含它)。因此,当我将include添加到类定义时,它会被遗忘,如下所示:

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

为什么这个附加模块Ryte :: Theme :: Validators也没有混入?

ADDED

好的,刚刚意识到:

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

奇怪..这是为什么?

1 个答案:

答案 0 :(得分:5)

更新:此 与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时,模块名称是相对于模块本身引用的,它只是{{1 (在你的情况下,只是C)。因此,当您在其他类Validators中包含A::B时,而不是包含名为D的模块(即A::B::C),ruby包含一个名为Ryte::Bundleable::Validators的模块(即C)。这就是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 现在评估为真。老实说,我不确定为什么会这样,但它必须与上面的命名空间有关。