【Ruby】【メタプログラミング】callerメソッド。method_missingを使ったメソッド呼び出しのトレーシング
■topic summary
study about meta-programming with Ruby.
- 作者: まつもとゆきひろ,David Flanagan,卜部昌平(監訳),長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2009/01/26
- メディア: 大型本
- 購入: 21人 クリック: 356回
- この商品を含むブログ (124件) を見る
分かるかな。。
callerメソッド
引数なしの場合は、スタックフレームが1個省略された形になる
class Hoge def meth1 meth2 end def meth2 p caller p caller(0) end end Hoge.new.meth1
■実行結果
["C:/Users/Hoge_ADMIN/Desktop/test/fizzbazz.rb:4:in `meth1'", "C:/Users/Hoge_ADMIN/Desktop/test/fizzbazz.rb:12:in `<main>'"] ["C:/Users/Hoge_ADMIN/Desktop/test/fizzbazz.rb:8:in `meth2'", "C:/Users/Hoge_ADMIN/Desktop/test/fizzbazz.rb:4:in `meth1'", "C:/Users/Hoge_ADMIN/Desktop/test/fizzbazz.rb:12:in `<main>'"]
なるほど。
method_missingを使ったメソッド呼び出しのトレーシング
class Object def trace(name, stream=STDOUT) return TraceObject.new(self, name, stream) end end class TraceObject #TraceObjectの既存インスタンスメソッドを消す instance_methods.each do |m| next if m == :inspect || m == :object_id || m == :__id__ || m == :__send__ undef_method m end def initialize(o, name, stream) @o, @n, @trace = o, name, stream end def method_missing(*args, &b) p method_name = args.shift arglist = args.map{|ar| ar.inspect}.join(",") @trace << "Invoking: #{@n}.#{method_name}(#{arglist}) called at #{caller[0]}\r\n" begin result = @o.send(method_name, *args, &b) @trace << "Returning: #{result} from #{@n}.#{method_name}(#{arglist}) called at #{caller[0]}\r\n" result rescue Exception=>e @trace << "Raising: #{e.class}:#{e} from #{@n}.#{method_name}(#{arglist})}\r\n" raise end end def __delegate @o end end a = [1,2,3].trace("target") p a #<= TraceObjectオブジェクトは出力できない p a.__delegate a.<<(4) a.fetch(10)
■実行結果
Invoking: target.inspect() called at fizzbazz.rb:34:in `p' Returning: [1, 2, 3] from target.inspect() called at fizzbazz.rb:34:in `p' [1, 2, 3] #<= 委譲元オブジェクトが出力される [1, 2, 3] Invoking: target.<<(4) called at fizzbazz.rb:36:in `<main>' Returning: [1, 2, 3, 4] from target.<<(4) called at fizzbazz.rb:36:in `<main>' Invoking: target.fetch(10) called at fizzbazz.rb:37:in `<main>' Raising: IndexError:index 10 outside of array bounds: -4...4 from target.fetch(10)}
注意(?)
委譲先オブジェクトを出力したいときは、
pメソッド内で実行されるinspectメソッドを消去対象からはずす。
next if m == :inspect || m == :object_id || m == :__id__ || m == :__send__
■実行結果
#<TraceObject:0x2e3e138 @o=[1, 2, 3], @n="target", @trace=#<IO:<STDOUT>>> [1, 2, 3]
ふむふむ。