機略戦記

Maneuver warfare

privateメソッドを外から実行

irbとかrails consoleでデバックを行なっている時に、privateなメソッドを呼び出して動作を確認したい時がたまにある。

そんな時、my_object.private_my_methodのように"."でメソッドを実行する代わりに、my_object.send(:private_my_method)と、#sendでメソッドを実行すると、カプセル化を破ってprivateなメソッドを実行することが出来る。

#sendとは、「レシーバーが持っているメソッドを実行するメソッド」で、#sendに引数としてメソッド名を渡す事でメソッドを実行できる。 #sendは、Kernelのインスタンスメソッドなのでほぼ全てのオブジェクトに対して使う事が出来る。

やってみる

  • 例えば、このMyClassインスタンスのprivateメソッドirbから呼び出したいとする
  • 普通に"."で実行すると(当然)NoMethodErrorとなる
[2] pry(main)> MyClass.new.private_my_method
NoMethodError: private method `private_my_method'  
called for #<MyClass:0x007ff2c9bf0e50>
  • しかし、sendを使うと呼び出せる!
[3] pry(main)> MyClass.new.send(:private_my_method)
"private!"

ちなみに、irb上だけでなく、ソースコード上でも同じ方法でprivateなメソッドを呼び出せる。
もちろんカプセル化を破壊しているので保守性が落ちるしバグを生みやすいので、乱用しないように気をつける必要がある。
自分の場合は、カプセル化を破壊するのはirb上でデバックをする時だけに限るようにしている。


さらにちなみに:
- この方法でprotectedなメソッドも呼び出せる
- #sendで無く#public_sendを使えばカプセル化を破らずに動的にメソッドが呼び出せる