きっかけ
を見かけて、いったい何がおかしいのか、そもそも`singleton_method`ってなんだ?と思ったところが始まり。 クラスの理解もおぼつかない初心者が @shyouhei を質問攻めにしながらその謎に迫ります。rubyのこの挙動何が起こってるの… https://t.co/SeioDJ8DDA
— Urabe, Shyouhei (@shyouhei) 2016年3月15日
singleton_methodとは?
日本語で言うところの特異メソッド。普通のメソッドはクラス定義に書かれており、そのクラスから作ったインスタンスで利用できるものだけれど、特異メソッドはとある一つのインスタンスにだけ追加されるメソッドのこと。
str1 = String.new
def str1.new_singleton_method
puts "str1の特異メソッドだよ"
end
str1.new_singleton_method
# => str1の特異メソッドだよ
str2 = String.new
str2.new_singleton_method
# => undefined method `new_singleton_method' for "":String (NoMethodError)
しかし、ruby-doc ( http://docs.ruby-lang.org/ja/2.2.0/doc/spec=2fdef.html#singleton_method ) を見てみるとクラスの特異メソッドと書いてある。しかも継承されると。クラスの特異メソッドってなんだ!?インスタンス化されたものにだけ追加できるメソッドじゃないのか!?と思ったら、私のクラスに対する理解が浅いだけでした。クラスはClassというクラスのインスタンス。 ( http://docs.ruby-lang.org/ja/2.2.0/doc/spec=2fdef.html#class ) にそう書いてある。だからクラスにも特異メソッドを追加できる。でもそれはクラスメソッドと同じように見える。というかクラスメソッドをクラスの特異メソッドとして実装している?書き方としてはこんな感じ。
class Foo
def Foo.new_singleton_method
puts "Fooの特異メソッドだよ"
end
end
Foo.new_singleton_method
# => Fooの特異メソッドだよ
見た目クラスメソッドと差がないですね。ちなみにこれが継承される、という話はちょっと変。とある一つのインスタンスにのみ追加されるメソッドが特異メソッドのはずなので。でもここは「変だけど使い勝手優先」by @shyouhei らしいです。
では、 singleton_method_added() って何?
これは
class Foo
def singleton_method_added(n)
puts "新しく追加された特異メソッドは以下だよ"
p n
end
end
foo = Foo.new
def foo.new_singleton_method1
end
# => 新しく追加された特異メソッドは以下だよ
# => :new_singleton_method1
こんな風に使える。
この singleton_method_added()
の中身が、新たに特異メソッドが追加された時に実行されるのだ。引数として渡せるのは新たに追加された特異メソッド名のシンボル ( http://docs.ruby-lang.org/ja/2.2.0/class/Symbol.html ) 。
その振る舞い方はわかった。けれども、このsingleton_method_added()
ってなんて呼べばいいんだろう?名前があらかじめ決まっている、という意味ではビルトインメソッドのように思えるけど、呼び出されるタイミングは決まってる上その振る舞いは定義されていないので、ビルトインメソッドとはまた違う。メソッドであることは確かだけど、その名前を自由に決められないし、どのタイミングで動くのかということもあらかじめ決まっているから、単純にメソッドと呼ぶのにも抵抗がある。
なので、なんて呼べばいいか @shyouhei に聞いてみたところ、「フック」との答えが。なるほど。特定のタイミングで割り込むからフックなのか。となんだか納得。
そして、冒頭のバグ?の意味
冒頭のバグ#12131は、singleton_method_added()そのものをインスタンス化したオブジェクトの特異メソッドとして追加した時に、singleton_method_added()自体が動いてしまうのはおかしくないか?という問いだったのだ。
そして、それはおかしくないよね、いやおかしい、という感じでTwitterで議論がされている、と。
この議論についてはベテランの皆様に任せるのが一番いいと思うので、私の探求はここで終わり。