2

次のコードを検討してください。

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

AS::Concern と単純な古い Ruby を介して含まれるモジュールの祖先の順序が異なるのはなぜですか?

FirstClass.ancestors
# => [FirstClass, Inner, Outer, Object, PP::ObjectMixin, Kernel, BasicObject]

SecondClass.ancestors
# => [SecondClass, SecondOuter, SecondInner, Object, PP::ObjectMixin, Kernel, BasicObject]
4

2 に答える 2

1

Andrey Deineko の回答は、何が起こっているのかを理解するための重要な基礎を提供してくれました。

モジュールがクラスまたは他のモジュールに含まれているとどうなりますか? 関連すると思われることが 2 つあります。

  • append_featuresと呼ばれます。

このモジュールが別のモジュールにインクルードされると、Ruby はこのモジュール内の append_features を呼び出し、mod 内の受信モジュールに渡します。Ruby のデフォルトの実装では、このモジュールがまだ mod またはその祖先の 1 つに追加されていない場合、このモジュールの定数、メソッド、およびモジュール変数を mod に追加します。Module#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が、他のモジュールに含まれているものに含まれているだけです。ただし、含まれていますInnerOuterSecondOuterInner

上記のコードをコンソールに貼り付けると、次のステートメントが画面に出力されます。

including Inner in SecondOuter
including Outer in FirstClass
including Inner in FirstClass
including SecondOuter in SecondClass

1 番目と 4 番目のステートメントは、SecondClassの祖先の順序を説明しています。 Innerは の祖先でSecondOuterあり、 は の祖先ですSecondClass。したがって、

SecondOuter.ancestors
=> [SecondOuter, Inner]

SecondClass.ancestors
=> [SecondClass, SecondOuter, Inner, Object, PP::ObjectMixin, Kernel, BasicObject]

FirstClass3 番目と 4 番目のステートメントは、の祖先の外部モジュールと内部モジュールの順序が逆になっている理由を示しています。

まず、Innerはの祖先ではありませんOuter

第二に、 is の前にOuter含まれますが、 dos の前に解決ます。その結果、FirstClassInnerInner.includedOuter.included

Outer.ancestors
=> [Outer]

FirstClass.ancestors
=> [FirstClass, Inner, Outer, Object, PP::ObjectMixin, Kernel, BasicObject]

AS::Concern を拡張してinclude SomeModuleステートメントをincluded doブロックに入れると、上記のSomeModule方法と同様に効果的にインクルードされOuterます。

Ruby 2.3.1 モジュール ドキュメント

ActiveSupport::懸念included

于 2016-10-16T14:02:15.957 に答える