動的メソッド
メソッドを呼び出す方法
- ドットを使う
- send()を使う
- send()メソッドの第一引数は呼び出すメソッド名 => 文字列またはシンボル
- その他の引数はそのままメソッドに渡される
send()を使えばコードの実行時に呼び出すメソッドを直前に決められる。なので動的な処理が可能になる。これを動的ディスバッチと呼ぶ。
プライバシー問題
send()メソッドの問題はprivateメソッドも呼ばれるということだ。
- 例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
プライバシーの尊重のため、public_send()を使う方法もある。
- 例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
メソッドを動的に定義
- define_method()
Module#define_method()を使えば、メソッドをその場で定義できる。
1 2 3 4 5 6 7 8 9 | |
define_methodはClassの中で実行され、my_method()がCクラスのインスタンスメソッドとして定義される。実行時にメソッドを定義するこの技術を動的メソッドと呼ぶ。
method_missing()
method_missing()のオーバーライド
method_missing()メソッドはBasicObjectのインスタンスメソッドだ。つまり、BasicObjectを継承しているObjectを継承するオブジェクトはmethod_missing()を持っているということになり、もちろんオーバーライドもでき、存在しないメソッドに対するハンドリングもできるということだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
ゴーストメソッド
同じようなメソッドをたくさん定義しなければならないとき、いちいち定義するより、method_missing()を呼び出す方がもっと楽かもしれない。method_missing()での処理は呼び出し側からは通常の呼び出しのように見える。しかし、レシーバに対応するメソッドは見当たらない。これはゴーストメソッドと呼ぶ。上記の例ではhello()がゴーストメソッドなるのだ。
もっとmethod_missing()
メソッド名が衝突したら
- 例
1 2 3 4 5 6 7 8 9 10 11 | |
上記のコードでは
1 2 | |
とプリントされると予想したけど、プリントされずArgumentErrorになってしまった。
これの問題はObjectから継承されたメソッドの中でdisplayというメソッドがあり、method_missing()が呼ばれなかったからだ。
これはは必要ないメソッドを全部削除することで対応できる。メソッドをすべて削除することをブランクスレートと呼ぶ。
- 例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
このコードは予想通りmethod_missing()を呼び出すことができる。
まとめ
- メソッドは
send()でも呼び出せる send()はprivateメソッドも呼び出せるため、public_send()を使うこともできるdefine_method()でメソッドを動的に定義できるmethod_missing()を利用すると存在しないメソッド、ゴーストメソッドに対するハンドリングや処理ができる