Ruby

[Ruby] モジュールの include と prepend-[2]

"前のエントリ" で モジュールを prepend すると, オーバーライドがおきると書いた.
ではモジュールを prepend したとき, オーバーライドしたメソッドのなかで super を実行するとどうなるか.

prepend 時の super の挙動

when_prepend_behavior_of_prepend.rb
# モジュールのメソッドで super を実行する
module M
  def hoge
    puts "hoge is defined by module"
    super
  end
end

# モジュールを prepend するクラス
class ClsPrependModule
  prepend M
  def hoge
    puts "hoge is defined by ClsPrependModule"
  end
end

挙動の確認

verify_behavior1.rb
ClsPrependModule.new.hoge # :=> hoge is defined by module
                          # :=> hoge is defined by ClsPrependModule

結論

prepend されたモジュールの, オーバーライドすることになるメソッドで super を実行すると, オーバーライドされる側のメソッド, つまり prepend したクラスの同名メソッドが実行されることがわかった.

おまけ

じゃあ, super で実行されるメソッド(つまり prepend したクラスのメソッド)で, さらに super を実行するとどうなるか.

verify_exec_super_in_prepended_class.rb
# モジュールのメソッドで super を実行する
module M
  def hoge
    puts "hoge is defined by module"
    super
  end
end

# モジュールを prepend するクラス
class ClsPrependModule
  prepend M
  def hoge
    puts "hoge is defined by ClsPrependModule"
    super
  end
end

挙動の確認

verify_behavior2.rb
# 実行
ClsPrependModule.new.hoge

# 結果
hoge is defined by module
hoge is defined by ClsPrependModule
NoMethodError: super: no superclass method `hoge' for #<ClsPrepen
  1. モジュールのメソッドがコールされ実行される
  2. super で prepend したクラスのメソッドがコールされ実行される
  3. prepend したクラスの上位クラス(ここでは Objectクラス)では「hoge()メソッド」が定義されていないので NoMethodError が発生した