Andrey Deineko の回答は、何が起こっているのかを理解するための重要な基礎を提供してくれました。
モジュールがクラスまたは他のモジュールに含まれているとどうなりますか? 関連すると思われることが 2 つあります。
このモジュールが別のモジュールにインクルードされると、Ruby はこのモジュール内の append_features を呼び出し、mod 内の受信モジュールに渡します。Ruby のデフォルトの実装では、このモジュールがまだ mod またはその祖先の 1 つに追加されていない場合、このモジュールの定数、メソッド、およびモジュール変数を mod に追加します。Module#include も参照してください。
レシーバーが別のモジュールまたはクラスに含まれるたびに呼び出されるコールバック。モジュールが別のモジュールに含まれているときにコードで何らかのアクションを実行したい場合は、これを 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
1 番目と 4 番目のステートメントは、SecondClass
の祖先の順序を説明しています。 Inner
は の祖先でSecondOuter
あり、 は の祖先ですSecondClass
。したがって、
SecondOuter.ancestors
=> [SecondOuter, Inner]
SecondClass.ancestors
=> [SecondClass, SecondOuter, Inner, Object, PP::ObjectMixin, Kernel, BasicObject]
FirstClass
3 番目と 4 番目のステートメントは、の祖先の外部モジュールと内部モジュールの順序が逆になっている理由を示しています。
まず、Inner
はの祖先ではありませんOuter
。
第二に、 is の前にOuter
含まれますが、 dos の前に解決します。その結果、FirstClass
Inner
Inner.included
Outer.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