この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
こんにちは、bibioです。ruby には super というオーバーライドしているメソッドを呼び出す機能があります。
何気なく使うとはまることがあるので違いを区別します。
説明した通り、superはオーバーライドしているメソッドを呼び出す機能です。
class A
def foo
puts "A#foo"
end
end
class B < A
def foo
super
puts "B#bar"
end
end
のとき、次のように出力されます。
B.new.foo
=>
A#foo
B#bar
では、以下のような例だとどうでしょうか?
class A
def foo
puts "A#foo"
end
end
module M
def foo
puts "M#foo"
end
end
class B < A
include M
def foo
super
puts "B#bar"
end
end
突然ですが、問題です。 B.new.foo() を実行したときに出力されるのは次のうちどれでしょうか?
(1)
M#bar
A#bar
B#bar
(2)
A#bar
B#bar
(3)
M#bar
B#bar
正解は・・・(3)
super はオーバーライドをするメソッドを呼び出すのであって、常に親クラスのメソッドを呼び出すわけではありません。名前に引きずられそうですね。
何もMix-inされていない場合、オーバーライドする親クラスのメソッドが呼び出されます。(なければ、その親クラスの親)といって、どれにもマッチしなければ method_missing が呼ばれます。通常は、NoMethodError になります。
オーバーライドされたメソッド呼び出しの階層を注意します。
include でモジュールをMix-inした場合は、元のクラスの上位に割り込みます。
メソッドの探索順にいえば、A->M->B になります。
メソッドの階層は ancestorsメソッドを使って調べます。上の例だと次の通り(Ruby2.1.xの場合)
irb> B.ancestors
=> [B, M, A, Object, Kernel, BasicObject]