LoginSignup
6
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-01-16

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

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

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4