Ruby の remove_method と undef_method の違い

さてさて、せっかくアドベントカレンダーでブログを書き続けているのでどうせならこのまま書き続けていこうかなーと思います。
まあすぐに止まりそうですが。
今回の内容は某所でちょっと話題になっていたので覚書。

remove_method と undef_method の違い

remove_method はメソッドを『削除』にし、undef_method はメソッドを『未定義』します。
どういうことかというと継承リストに呼び出せるメソッドが複数ある場合に違いがあります。

class Base
  def hoge
    "Base#hoge"
  end
end

class Super < Base
  def hoge
    "Super#hoge"
  end
end

# Super クラスで定義したメソッドが呼ばれる
pp Super.new.hoge
# => "Super#hoge"


class Super
  # Super で定義されているメソッドを削除する
  remove_method :hoge
end

# Base クラスで定義したメソッドが呼ばれる
pp Super.new.hoge
# => "Base#hoge"


class Super
  # Super で定義されているメソッドを未定義
  undef_method :hoge
end


# Super クラスからは undef_method したメソッドが呼べなくなる
# error: undefined method `hoge' for #<Super:0x00005631f4397278> (NoMethodError)
# pp Super.new.hoge

# こういう書き方だと呼び出すことは可能
pp Base.instance_method(:hoge).bind(Super.new).call

remove_method だとまさに『そのクラスのメソッドを削除する』っていう動作になるんですが、 undef_method だと『メソッドを呼び出せなくする』っていう動作になります。
たまーーーーーーに一時的にメソッドを生やしてその後削除することがあるんですが remove_methodundef_method の違いがわかってないと思わぬところで嵌りそうですねえ。