3章 火曜日: メソッド
動的メソッド
- メソッドを呼び出すというのは、オブジェクトにメッセージを送ること
Object#send
- メソッドを呼び出すには、ドット記法とObject#sendがある
obj.send(:my_method, 3)
-
Object#sendを使うと、どんなメソッドでも呼び出せてしまう
- privateメソッドを呼び出せるからこそ、sendを使う
動的ディスパッチ
-
send
メソッドを使って、呼び出したいメソッド名を引数として、コードの実行時に呼び出すメソッドを決めること
メソッドを動的に定義する
Module#define_method
- 実行時にメソッド名を定義できる
- メソッド名とブロックを渡すことで、ブロックがメソッドの本体となる
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
end
obj = MyClass.new
obj.my_method(2) #=> 6
手順1: 動的ディスパッチを追加する
手順2: メソッドを動的に生成する
手順3: コードにイントロスペクションをふりかける
method_missing
-
BasicObjectクラスの、privateインスタンスメソッド
- NoMethodErrorを返すのが役割
-
指定したメソッドが継承チェーンを遡っても見つからない場合、Rubyは、method_missingを呼び出して負けを認める。
-
method_missingが呼び出されると
hoge.send :method_missing, :my_method => NoMethodError: undefined method 'my_method' for <...>
-
method_missingをオーバーライドすると、実際には存在しないメソッドを呼び出せる
class Lawyer
def method_missing(method, *args)
puts "呼び出した: #{method}(#{args.join(',')})"
puts "(ブロックも渡した)" if block_given?
end
end
bob = Lawyer.new
bob.talk_simple('a', 'b') do
# ブロック
end
=> 呼び出した: talk_simple(a,b)
(ブロックも渡した)
ゴーストメソッド
- method_missingを呼び出す際、通常と同様に見えるが、レシーバ側に対応するメソッドが見当たらないこと。
- 「君が理解できないことを頼まれたら、これをやっておいてね」という感じ
動的プロキシ
- ゴーストメソッドを補足して、他のオブジェクトに転送するオブジェクトのこと。
respond_to_missing?
- Rubyが、respond_to?にゴーストメソッドを認識させる仕組み
- method_missingをオーバーライドしたときには、respond_to_missing?もオーバーライドすること。
const_missing
- 存在しない定数を参照すると、Rubyは定数の名前をconst_missingにシンボルとして渡す。
- クラス名は単なる定数なので、不明な参照はModule#const_missingに渡される
ブランクスレート
- 最小限のメソッドしかない状態のクラスのこと
- ブランクスレートが必要であれば、BasicObjectを直接継承する
まとめ
可能であれば動的メソッドを使い、仕方がなければゴーストメソッドを使う
感想
Object#sendを使って、動的にメソッドを呼び出すこと、Module#define_methodを使って、動的にメソッドを定義する、という動的メソッドの存在を知る。
また、BasicObject#method_missingを上書きし、存在しないメソッドをゴーストメソッドとして生成する方法を知る。
一旦は見た際に気づけるかな、という感覚。実際に自分で使うとなると、もう少し慣れや自信が必要かな、という肌感。