Rubyのメソッドについてあらためてしっかり理解する
今回はメソッドについてです。 Rubyに限らずほぼ全ての言語には
を定義可能です。 今回はこれらについて詳しく見ていきます。
パブリックと プライベートメソッドの違い
こちらはわかっている方が大多数かと思いますが、改めて確認です。 パブリックメソッドはクラス外から呼び出せる公的なメソッド、 プライベートメソッドはクラス内でしか呼び出せない私的なメソッドです。
class A def some_public_method puts "this is public instance method" end def call_private_method some_private_method end private def some_private_method puts "this is private instance method" end end # パブリックメソッド(呼び出せる) A.new.some_public_method # => this is public instance method # プライベートメソッド(呼び出せない) A.new.some_private_method # => private method `private_instance_method' called for #<A:0x007fe0b204e300> (NoMethodError) # 内部から呼び出すことは可能 A.new.call_private_method # => this is private instance method
プライベートメソッドが呼び出せないのはRubyの仕組みとして * privateメソッドにレシーバーをつけてはいけない * 自分(self)以外のオブジェクトのメソッドを呼び出すときはレシーバをつけなければいけない という2つのルールがコンフリクトしてしまうためです。 参考(url)
インスタンスメソッドとクラスメソッド
こちらも基本です。クラスメソッドはクラスから直接呼び出せるメソッドインスタンスメソッドはクラスからnewで作られたインスタンスから呼び出せるメソッドです。( Rubyではクラスもオブジェクトなのでクラスメソッドはクラスのインスタンスメソッドとも言えるかと思います 。)
class B def some_instance_method puts "this is instance method" end def self.some_class_method puts "this is class method" end end # インスタンスメソッドはクラスをnewしたインスタンスから呼び出せる B.new.some_instance_method # => this is instance method # クラスメソッドはクラスから直接呼び出せる B.some_class_method # => this is class method # インスタンスからクラスメソッドは呼び出せrない B.new.some_class_method # => undefined method `some_class_method' for #<B:0x007f8cc4113b60> (NoMethodError) # クラスからインスタンスメソッドは呼び出せない B.some_instance_method # => undefined method `some_instance_method' for B:Class (NoMethodError)
パブリック・プライベートとクラス・インスタンスメソッドをそれぞれ組み合わせたもの
今度はそれぞれを組み合わせたものを試してみます
class C def some_public_instance_method puts "this is public instance method" end def self.some_public_class_method puts "this is public class method" end private def some_private_instance_method puts "this is private instance method" end def self.some_private_class_method puts "this is private class method" end end C.some_private_class_method # => this is private class method
とは言っても今までで出てきていないのはプライベートなクラスメソッドのみです。ここで不思議なことが起きるのですが、プライベートなクラスメソッドはクラスの外から呼び出せてしまいます。つまりパブリックなクラスメソッドと同じ動きをしてしまいます。 ちょっとこれはかなり不思議な事態なのですが恐らく * privateメソッドにレシーバーをつけてはいけない =>(クラス側から見ればself.some_private_class_method=C.some_private_classmethodと解釈されてレシーバーはついていない) * 自分(self)以外のオブジェクトのメソッドを呼び出すときはレシーバをつけなければいけない =>(呼び出し側から見ればCがレシーバー) となって呼び出せてしまうのかなと思います。あくまでこれは僕の推測ですのでご注意ください。(もしご存知の方いらっしゃいましたら、コメントでご教示いただけると幸いです。)
本当にプライベートなクラスメソッドを定義するにはprivate_class_methodを使う必要があります。
class D def self.some_private_class_method puts "hello" end private_class_method :some_private_class_method end D.some_private_class_method # => private method `some_private_class_method' called for D:Class (NoMethodError)
これで意図した動作になりました。