1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyのメソッドを検索して実行する

2022-02-03 23:43:20

メソッドが呼び出されたとき、Rubyは2つのことをします。

1. メソッドを検索します。この方法はメソッドルックアップと呼ばれます。

2. メソッドを実行する。そのためにRubyにはselfというものが必要です。

メソッドを見つけて実行する、このようなプロセスは、どのオブジェクト指向言語でも起こります。しかし、Rubyのような非常に動的な言語では、このプロセスを深く理解することが特に重要です。メソッドが一体どこで定義されているのか、不思議に思ったことはありませんか?もしそうなら、メソッドのルックアップとセルフを深く理解することは間違いなく価値があります。

メソッドが呼び出されると、Rubyはオブジェクトのクラスの中からそのメソッドを探します。しかし、もっと複雑な例を挙げる前に、receiver と ancestors chain という2つの新しい概念を理解する必要があります。

レシーバーとは、メソッドを呼び出す先のオブジェクトのことです。例えば、my_string.reverse() の文では、my_string が受け手です。

祖先連鎖の概念を理解するには、まずRubyのクラスを見てみるとよいでしょう。あるクラスからそのスーパークラスへ、さらにそのスーパークラスのスーパークラスへと移動し、最終的にObjectクラス(すべてのクラスのデフォルトのスーパークラス)、そしてBasicObjectクラス(Rubyクラスアーキテクチャのルートノード)へ到達すると想像してください。この過程で通るクラスのパスが、そのクラスの祖先チェーンです(祖先チェーンにはモジュールも含まれることがあります)。

メソッドを見つけるために、Ruby はまずアクセプタのクラスを探し、それからメソッドを見つけるまで祖先の鎖をたどっていくのです。

class MyClass
  def my_method
    my_method()
  end
end
 
class MySubclass <MyClass
end
 
obj = MySubclass.new
obj.my_method() # = >"my_method()"


  my_method()メソッドが呼ばれると、Rubyはレシーバobjから始めて、MySubclassクラスにやってきます。ここでmy_method()メソッドが見つからないので、RubyはMyClassクラスまで行き、そこでメソッドを見つけます。

ここでも見つからなければ、Object クラス、BasicObject クラスと祖先の連鎖をたどっていくことになる。このようなルックアップの動作を、多くの人が図を描くときの順序で言うと、「一歩右へ、そして上へ」というルールで知られています。つまり、まず受信者がいるクラスまで右へ一歩進み、それから与えられたメソッドを見つけるまで祖先の連鎖をたどっていくのです。

ここまではメソッドの見つけ方だけでしたが、いよいよ実行の仕方を見ていきましょう。

あなたがRubyのインタプリタだと想像してください。誰かが my_method() というメソッドを呼び出したとして、そのメソッドを "one step to the right, then up" で見つけると、そのメソッドは次のように定義されていることがわかります。

def my_method
  temp = @x + 1
  my_other_method(temp)    
end


  このメソッドを実行するには、2つの質問に答える必要があります。まず、インスタンス変数 @x はどのオブジェクトに属しているか?2つ目は、どのオブジェクトに対してmy_other_method()というメソッドを呼び出すべきか?

インスタンス変数 @x と my_other_method() メソッドは両方とも受信者、つまり最初に my_method() メソッドを呼び出したオブジェクトに属しています。しかし、Rubyにはこれが贅沢だという直感はありません。メソッドが呼ばれたとき、Ruby は受け手の参照を保持する必要があり、この参照があるからこそ、どのオブジェクトが受け手であるかを記憶し、それを使ってメソッドを実行することができるのです。このレシーバの参照は、自分のためにも使うことができます。