LoginSignup
2
2

More than 5 years have passed since last update.

method_missing

Posted at

method_missingとは

呼びだされたメソッドが存在しなかった時に呼ばれるメソッド。
NoMethodErrorを返してくれるやつ。
BasicObjectクラスに定義されている。

rubyのメソッド探索の流れ

rubyでは呼びだされたメソッドが見つかるまで継承ツリーを辿っていき、最終的に最上位であるBasicObjectクラスまで探しに行く。
BasicObjectまで探しに行っても見つからなかった場合は、レシーバーの直接のクラスにmethod_missingメソッドが無いか探索し、ない場合は再び継承ツリーを辿ってmethod_missingメソッドを探しに行く。

以下のようなクラス、モジュールがあったとします。

module Hello
  def hello
    p "Helloモジュール"
  end
end

class GrandParent
  def hello
    p "GrandParentクラス"
  end
end

class Parent < GrandParent
  include Hello
end

class Child < Parent
end

child = Child.new
child.hello        #=> "Helloモジュール"
p Child.ancestors  #=> [Child, Parent, Hello, GrandParent, Object, Kernel, BasicObject]

childオブジェクトに対してhelloメソッドが呼ばれると、childオブジェクトの直接のクラスであるChildクラスから継承ツリーを辿ってhelloメソッドを探しに行く。最初にhelloメソッドをもっているのはHelloモジュールなので、"Helloモジュール"という文字列が出力される。

メソッド探索の流れは
Childクラス -> Parentクラス -> Helloモジュール -> GrandParentクラス
-> Objectクラス -> Kernelモジュール -> BasicObjectクラス
となる。

したがって、存在しないメソッドを呼び出したときも上記の流れでmethod_missingメソッドを探しに行く。

BasicObject#method_missingをオーバーライド

特定のクラスでmethod_missingメソッドをオーバーライドすることで定義されていないメソッドが呼ばれてもNoMethodErrorを出さない(特定の処理を実行させる)ことができる。

method_missingに渡される引数は以下のようになっている。

引数 中身
第一引数 呼び出しに失敗したメソッド名のシンボル
残りの引数 呼び出しに失敗したメソッドに渡された引数(可長変引数)

Arrayのような振る舞いをさせたいDelegateArrayクラスをArrayを継承せずに作ってみます。

delegate_array.rb
class DelegateArray
  attr_reader :array

  def initialize
    @array = []
  end

  def method_missing(name, *args)
    if Array.instance_methods.include?(name)
      p "method_missingが呼ばれました"
      return @array.__send__ name, *args
    end

    # method_missingないで存在しないメソッドが呼ばれると
    # SystemStackErrorが発生するので、Arrayに定義された
    # メソッド以外のときはsuperを呼び出す
    super
  end
end

delegate_array = DelegateArray.new
delegate_array << 1     
p delegate_array.array

実行結果

$ ruby delegate_array.rb
"method_missingが呼ばれました"
[1]
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2