まりぴよこのブログ

日々の日記。技術ネタでまとまりきってないものの記録、伝わる文章の書き方を練習とか。

Rubyの勉強(落ち葉拾いその2)Rubyのメソッドについて

Rubyメソッドメソッドについてあれれ?となった・・

Java屋からやってくる人がたいてい陥る罠にハマったらしい。。

Rubyにおけるメソッドの正しい定義を調べてみた。

def self.method_name ・・・・selfってなんだっけ・・・

元にしてたコード

class MatrixSum
  def self.sumup_numbers(input)
    # なんやかんや・・・
  end
end

メソッド定義の時に、前のコードから引っ張って来てそのままだった def self.method_name が、改めて見てみたら意味が分からなかった。。 (こういうのヨクナイ!!)

ヨクナイので改めて調べてみると、ほんと〜に全然わかってなかったことがわかった。。

手元にあるRubyの参考書、「パーフェクトRuby」で調べてみると・・

P.53 2-5-3 self メソッドの中では、そのメソッドが属しているインスタンスself という名前の議事変数で参照できます。 これは他の言語で言うthisにあたります。

と書いてある。。。

メソッド定義時に付いてる場合は、なんかちょっと違う・・・

調べてみたらこの記事がヒット

qiita.com

これだ!!

で、元記事を読んだ方が全然良いので詳しく書かないけど・・

メソッドの種類

つまりメソッド定義にselfくっつけた時は、クラスメソッドを定義してたってことですな。。

クラスメソッド、つまりJava屋的には、メソッドstatic 付けた状態なわけだ。

そして更にハマる・・

ここで何故か脱線して、一部のメソッドクラスメソッドなんだけど、外から呼び出してないから呼び出せないようしてみようかな・・ と思う。。

そして更にハマる・・

外から呼び出せないメソッド = private付けてみたら良いんじゃね?Java屋的発想)

class MatrixSum
  def self.sumup_numbers(input)
    # なんやかんや・・・
    instance_private_method
  end
  
  private
    def instance_private_method
      puts "I'm private"
    end
end

エラー!!

Failure/Error: instance_private_method
NameError:
  undefined local variable or method `instance_private_method' for MatrixSum:Class

急に呼び出せなくなる・・・

何故に〜;;

Rubyにおけるprivateメソッドとは

qiita.com

これだ!!(Qiita様々やな・・)

  • ルール1:privateのついたメソッドを呼び出す時は、レシーバは指定できない
  • ルール2:自分(self)以外のオブジェクトのメソッドを呼び出すには、レシーバを指定する必要がある

なるほどなるほど! なんかシンプルなルールでわかりやすい。

つまり、 「クラスメソッドはレシーバーなしで呼ばれるもの、なのに、そこからレシーバー経由でしか呼び出せないprivateメソッド呼ぼうとすると、メソッドないよ!と怒られる。。」 という状態だったようです。。

他言語からRubyの世界にやってくると、大抵一度はみなあれ??と思うところのようで・・

先人の記録が沢山・・・

Rubyのクラスメソッドは同じクラスのprotectedメソッドやprivateメソッドにアクセスできない - give IT a try

JavaやC#の常識が通用しないRubyのprivateメソッド - give IT a try

サブクラスがインスタンス経由で呼び出せる親クラスのメソッド

更にハマる・・おそるべしクラスメソッド・・

ここまで記事を書いてから・・もしかして、privateの後に書いたメソッドにも self って付けたらprivate扱いのクラスメソッドできるんじゃね!!?

と思い、更にごちゃごちゃやってみた・・・ (結論:できんかった・・)

class MethodCheck

  def self.my_class_method
    puts "I'm class method"
  end

  def my_instance_method
    puts "I'm instance method"
  end

  private
    def self.my_private_class_method
      puts "Am I realy secret? (class method)"
    end

    def my_private_instance_method
      puts "Am I secret? (instance method)"
    end
end

呼び出してみよう!

まずはおさらいのクラスメソッド呼び出し。

MethodCheck.my_class_method

問題なし!

続いて、これもおさらいのインスタンスメソッドなのに、むりやりクラスメソッドみたいに呼び出してみる。

#MethodCheck.my_instance_method
# => undefined method `my_instance_method' for MethodCheck:Class (NoMethodError)

呼び出せない。問題なし! (よしよし。わかって来たぞ。。)

続いて、インスタンスメソッドをちゃんとインスタンスメソッドとして呼び出してみる。

my = MethodCheck.new
my.my_instance_method

良い感じ!

privateの後に書いたメソッド達が、ちゃんとprivateかどうかチェックしてみる

Rubyで定義されているメソッド一覧を呼び出せる methods を使ってみる。

継承してるメソッドもどばっと出て来てしまうので、 grep で自分が定義したメソッド名だけを引っ掛けるようにして・・

# インスタンスメソッドをチェックしてみる
puts "CHECK instance methods"
p my.methods.grep(/my/)
# => [:my_instance_method]

インスタンスメソッドは大丈夫!

# クラスメソッドをチェックしてみる
puts "CHECK class methods"
p MethodCheck.methods.grep(/my/)
# => [:my_class_method, :my_private_class_method]

・・・!??

あれれ??

privateの後に書いたのに!!

無視されてない???

調べてみた

tmtms.hatenablog.com

そもそもキーワードが違うらしい・・・

private_class_method

って付けないとダメみたい。。

実は、最後の方まだちゃんと理解してないので、もっとRuby力上がってから戻ってきたい・・ (ここにしおりでも挟んどきたい;;)

再履修・・

ダラダラ書いたけど・・ちゃんと理解しきれてない;; でもこの記事はもう長くなりすぎちゃったから、これで公開しちゃおう;;

エントリ書く前よりは頭の中整理出来たので・・まぁ、一定の効果はあったと思おう♪

はてなブログのカテゴリーに「再履修」って付けてみた。。 再履修増えすぎないと良いなぁ ww