【一人 Ruby Advent Calendar 2017】private メソッドを呼びだそう【10日目】
一人 Ruby Advent Calendar 2017 10日目の記事になります。
さて、今回は Ruby の private
についていろいろ
Ruby で private メソッドを定義する
Ruby では private
(という名前のメソッド)を使用することでメソッドを private
として定義することができます。
class X def homu "homu" end # 任意のメソッドを private にする private :homu # 引数がなかった場合は以降に定義されるメソッドを private メソッドとして定義する private def mami # メソッド内であれば呼び出すことが出来る homu + mado end def mado "mado" end end x = X.new # private メソッドは呼び出せない # Error: private method `homu' called for #<X:0x00000000025cc1a8> (NoMethodError) p x.homu
こんな感じでクラス外からはメソッドを呼び出すことができません。
private
メソッドを呼び出す
さてさて、private
メソッドを定義することでクラス外から呼び出せない…と、思いきや実はクラス外からも簡単に呼び出すことができます。
#send
を使う
class X private def homu "homu" end end x = X.new # send だと任意のメソッドで呼び出すことが出来る p x.send :homu # => "homu"
#instance_exec
や #instance_eval
を使う
class X private def homu "homu" end end x = X.new p x.instance_eval { # ブロック内で直接メソッド呼び出す homu } # => "homu"
特異メソッド経由で呼び出す
class X private def homu "homu" end end x = X.new # メソッドを再定義して def x.homu # 元のメソッドを呼び出す super() end p x.homu
どういうこと?
これは Ruby の private
の仕様がx.func
のように『x.
をつけて呼び出せないようにする』となっているためです。
なので
x = X.new # インスタンスオブジェクトからメソッド呼び出す x.func
のように通常はインスタンスオブジェクト経由で呼び出す事ができません。
しかし、逆にいえば x.func
のような形式ではなくて
# #send 経由で呼び出す x.send :func
のように #send
経由でメソッド呼び出したり、
# instance_eval 内ではコンテキストが x になるので # x. を付ける必要なく func を呼び出せる x.instance_eval { func }
みたいに #instance_exec
を使うことで x.
を付けることなくメソッドを呼び出す事ができます。
ちなみに次のように self.
を付けて呼び出した場合はエラーになります。
class X def homu # OK homu # Error: private method `mado' called for #<X:0x0000000001934670> (NoMethodError) self.homu end private def mado "mado" end end
まとめ
private
メソッドにメソッド名を渡すとそのメソッドがprivate
メソッドになるprivate
メソッドに引数を渡さなかった場合は以降に定義されるメソッドがprivate
になるprivate
メソッドはx.func
のようにx.
をつけて呼び出せないx.
をつけなければ呼び出せるので簡単に外部から呼び出すことが出来る
このように Ruby では『private
メソッドが外部から呼び出せない』とは限らないので広い意味での『private
メソッド』を定義したい場合は工夫が必要になってきます。