メタプログラミングRuby読みメモ 2

3章 メソッド

重複問題

  • コードの重複は間違いを犯すかのせいをはらむ
  • Ruby はいくつか解決方法を持つ

動的メソッド

  • メソッドを動的に呼び出す
    • メソッドを呼び出すには通常はドット記法を使う
    • Object#sendを使って呼び出す方法もある
    • send の第一引数はオブジェクトに送信するメッセージ、つまりメソッド名である
      • 送るメソッド名にはシンボルまたは文字列が使える
    • send を用いることで、呼び出したいメソッド名が通常の引数となり、実行時に呼び出すメソッドを指定できる
    • これを動的ディスパッチと呼ぶ
    • send メソッドは privateのメソッドすら呼び出すことができる
  • メソッドを動的に定義する
    • Module#define_method を使うと、メソッドを動的に定義することもできる
      • メソッド名とブロックを渡し、ブロックがメソッドの本体となる
      • define_methodが実行されたクラスのインスタンスメソッドとして定義される
    • これを動的メソッドと呼ぶ

method_missing

  • Ruby にはメソッド呼び出しを制限するコンパイラは存在しないため、存在しないメソッドも呼び出すことができる
  • メソッドが見つからなかった時、RubyBasicObject#method_missingを呼び出す
  • method_missing は private だが、send を使えば呼び出すこともできる
  • method_missing は NoMethodError を出す

  • NoMethodErrorってこういう仕組みだったんだ...すごい

  • method_missing をオーバーライドすれば受け取ったメッセージを捕まえることができる

    • ブロックが渡されていればそれも捕まえることができる
  • method_missing をオーバーライドすることで、実際には存在しないメソッドを呼び出せる
  • method_missing でのバグは潰しにくい
    • method_missing をオーバーライドしているため NoMethodError を出せずに無限ループしてしまうこともある

ゴーストメソッド

  • 同じようなメソッドをたくさん定義しなければいけないときには、いちいち定義せずにmethod_missingの呼び出しに反応すればいいこともある
  • ここで処理されたメッセージは呼び出し側からは通常のメソッドのように見えるが、レシーバー側には定義されていない
  • これをゴーストメソッドと呼ぶ
  • ゴーストメソッドを補足して、他のオブジェクトに転送するオブジェクトを動的プロキシと呼ぶ
  • respond_to_missing?をオーバーライドすればrespond_toにも反応できるようになる
  • 常に super を呼び出す、respond_to_missing?を再定義することを基本に実装する必要がある
  • methods?の結果一覧に登場しないなどの通常のメソッドとの振る舞いの違いがある
  • 「可能であれば動的メソッドを使い、仕方がなければゴーストメソッドを使う」

ブランクスレート

  • ゴーストメソッドと継承した本物のメソッドの名前が衝突すると、後者が呼び出される
  • 継承したメソッドが必要ない場合は削除すれば衝突を解消できる
  • 名前の衝突を防ぎたいのであれば、不要メソッドは削除するべき
    • undef_method で削除できる
  • 最小限のメソッドしかない状態のクラスをブランクスレートと呼ぶ
  • Rubyにはこのブランクスレートが用意されている
    • それがBasicObjectである