On Github kaosf / 20141026-tokushimarb-slide
このスライド自体のリポジトリは kaosf/20141026-tokushimarb-slide にあります
間違いを発見したら Issue あるいは PullRequest を下さい
method_missing
メソッドが無いときに呼ばれるメソッド
class A def initialize(x) @x = x end def m @x end end a = A.new 1 puts a.m #=> 1
A という名前のクラスを作成
コンストラクタで引数を渡してそれがメンバ変数として保存される
m という名前のメソッドでそのメンバ変数が取得出来る
a.n
まったく同じ数値にはならないと思うが
<main>': undefined method `n' for #<A:0x007ffa70909878 @x=1> (NoMethodError)
のような n が無いですというエラーが出るはず
class A # ... def method_missing(name, *args) end end
ここでおもむろに上記のようなメソッドを追加してみる
先ほどの
a.n
を実行してみるとエラーが出なくなった
何故だろう
元々存在した method_missing メソッドがオーバライドされたから
※余談ですが公式のドキュメントは常に参照しましょう
※意外と知らないことが書いてあったりします
ドキュメントによると第一引数がメソッド名のシンボルで第二引数がメソッドに与えられた引数
class A # ... def method_missing(name, *args) p name p args end end a.n 1, 2, nil, 'a'
結果
:n [1, 2, nil, "a"]
確かに
…と思って欲しい
ありもしないメソッドが呼ばれたときにその事実を捕捉出来ると共に与えられた情報(メソッド名と全引数)も捕捉することが出来る
昔のRails(3まで)には動的ファインダというものがあった
※今でもあるが非推奨になっている
Blog.find_by_title('foo bar') # SQL で言うところの # SELECT * FROM blogs WHERE title = 'foo bar';
※Blog というモデルがあり title というフィールドを持っていると想定
Blog というモデルのクラスには毎度毎度
find_by_title などというメソッドは定義されていない
にも関わらず呼び出すことが出来た
class Blog def self.method_missing(name, *args) if name.to_s =~ /find_by_(.*)/ #where(['? = ?', $1, args.first) p $1 p args.first else super.method_missing name, args end end end
実際は全然違うがそれはこの際無視する
where は実行出来ないのでここでは情報を表示してみるだけ
先ほどの例で
Blog.find_by_title 'foo bar'
だと "title" と "foo bar" が出る
Blog.foo_method
だと基底クラスの method_missing が呼ばれるためNoMethodError が発生する
お察しの通りコードの読み通しがクソになる
意味もなく使うのやめよう
respond_to_missing? も正しくオーバライドしようrespond_to? がちゃんと機能するように
すごいメタプログラミング楽しく学ぼう
ちなみにメソッドを動的に追加したいだけならdefine_method というメソッドがあります
参考: define_method
スライドからコピーしてもいいですが一応 kaosf/20141026-tokushimarb-codes にも置いておきます
おしまい