gensym

プログラミングと読書、勉強に関するメモ

メタプログラミングRuby その3 [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

2.4 メソッドを呼び出すときに何が起きているの?

オブジェクトがメソッドを呼び出すときにはまずオブジェクト自身のクラスを探索し、見つからなければスーパークラスを探索する。
これを本文中で「右へ一歩、それから上へ」と表している。

class MyClass
  def my_method; "my_method()"; end
end

class MySubClass < MyClass
end

obj = MySubClass.new
obj.my_method
# -> "my_method()"

# 継承チェーンを調べる
MySubClass.ancestors
# -> [MySubClass, MyClass, Object, PP::ObjectMixin, Kernel, BasicObject]

これは rails において空っぽのクラスが驚くほど多様なメソッドを持っている理由だ。

モジュールがインクルードされるとモジュールはインクルードされたクラスの真上に挿入される。
include ではなく prepend を使うと下に挿入される。
メソッドが見つかると探索は止まるので、これにより挿入されたモジュールのメソッドがオーバーライドされると言うことだろうか。

module M1
  def my_method
    "M1#my_method"
  end
end

class C
  include M1
end

class D < C ; end

D.ancestors
# -> [D, C, M1, Object, PP::ObjectMixin, Kernel, BasicObject]

class C2
  prepend M2
end

class D2 < C2; end
D2.ancestors
# ->  [D2, M1, C2, Object, PP::ObjectMixin, Kernel, BasicObject]

カレントオブジェクトには self でアクセスできる。
python の self はこのくらい慎ましくなれなかったのだろうか。

class String
  def add_hello
    "hello, " + self
  end
end

"Bob".add_hello
# -> "hello, Bob"

オープンクラスの欠点として既存のメソッドのオーバーライドができてしまうという物があったが、refine を使うことで望む範囲の中だけでオーバーライドさせることができる。

module StringEx
  refine String do
    def to_i
      "i"
    end
  end
end

module StringUse
  using StringEx
  "33".to_i
# -> "i"
end

"33".to_i
# -> 33

ただしこれを pry や irb でやるとエラーになってしまう。
参考 : ruby - Why did I get `main.using is permitted only at toplevel` when I used a Refinement in IRB? - Stack Overflow
スクリプトを書いて実行したら無事動いた。

2.5 はクイズで 2.6 は章のまとめになる。
2章ではオブジェクトの構成やメソッドの探索、実際的なオープンクラスやモジュールの呼び出しなどを学んだ。
どうしても曖昧にしたままになりがちで、かつきちんと使いこなせたら有用な事ばかりだった。
次章も期待できそうだ。