Edited at

Module#append_featuresを上書きする時はsuperを書かないとモジュールがincludeされない

More than 3 years have passed since last update.

タイトルが全てなのですが実際にコードを書いて試してみました。


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!



るりま

http://docs.ruby-lang.org/ja/2.1.0/method/Module/i/append_features.html

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