タイトルが全てなのですが実際にコードを書いて試してみました。
Module#append_featuresを上書きする例
Ruby技術者認定試験Gold version 2.1で似た問題が出てた気がします。
試験ではsuperが必要か否かで選択肢が分かれていました。
正解はsuperを入れている選択肢だったと思います。
①append_features内での継承関係の確認
出力結果からappend_features内ではまだモジュールMがincludeされていないことが分かる。
append_featuresの引数klassは、モジュールMをインクルードするクラスであるA。
module M
def self.append_features(klass)
p klass.ancestors
super
end
end
class A
include M
end
[A, Object, Kernel, BasicObject]
②モジュールがincludeされていることを確認
クラスAはモジュールMをincludeしていることが分かる。
module M
def self.append_features(klass)
p klass.ancestors
super
end
end
class A
include M
end
puts "------------------------------------"
puts "in top-level"
p A.ancestors
[A, Object, Kernel, BasicObject]
------------------------------------
in top-level
[A, M, Object, Kernel, BasicObject]
③superを書いていないとモジュールがincludeされないことを確認
superがコメントアウトされていると、クラスAがモジュールMをincludeできていないことが分かる。
module M
def self.append_features(klass)
p klass.ancestors
# super
end
end
class A
include M
end
puts "------------------------------------"
puts "in top-level"
p A.ancestors
[A, Object, Kernel, BasicObject]
------------------------------------
in top-level
[A, Object, Kernel, BasicObject]
Module#append_featuresについての参考リンク
Rubyリファレンス(Oiax)
http://ref.xaio.jp/ruby/classes/module/append_features
※リンク先のRubyは1.9.2みたいですが、2.1.5でも同じ挙動でした。
def append_features(klass)
code...
end
append_featuresメソッドは、モジュールが他のクラスやモジュールにインクルードされる前に呼び出されます。
引数にはモジュールをインクルードするクラスやモジュールが入ります。
append_featuresはincludeメソッドによって呼び出されます。Moduleクラスのオリジナルのappend_featuresはインクルード機能の本体です。append_featuresを上書きするときは、superを呼び出さないとモジュールがインクルードされません。
次の例では、append_featuresの中でメッセージを表示したあとで、superでインクルード機能を呼び出しています。
module Feature
def self.append_features(klass)
puts "#{klass} is going to include #{self}!"
super
end
end
class Container
include Feature
end
Container is going to include Feature!
るりま
append_features(module_or_class) -> self
モジュール(あるいはクラス)に self の機能を追加します。
このメソッドは Module#include の実体であり、 include を Ruby で書くと以下のように定義できます。
def include(*modules)
modules.reverse_each do |mod|
# append_features や included はプライベートメソッドなので
# 直接 mod.append_features(self) などとは書けない
mod.__send__(:append_features, self)
mod.__send__(:included, self)
end
end
[SEE_ALSO] Module#included