K.Sasada's Home Page

こめんとのついか

こめんとこめんと!

message

please add long comment :).

_14(Fri)

Ruby VM アドベントカレンダーの 14 日目です.

今日は,最近紹介している TracePoint の細かい使い方の紹介をしようと思います.

昨日の記事では TracePoint.trace を使いました.set_trace_func と同様に,このメソッド終了時から設定したトレースが有効になります.しかし,普通のオブジェクトのように,TracePoint.new によって TracePoint オブジェクトを作成することが出来ます.作成後は,まだ有効ではないので,TracePoint#enable としてトレースを有効にします.ちなみに,TracePoint.new の引数は TracePoint.trace と同じです.

trace = TracePoint.new(events...){|tp| ... trace ... }
... # まだトレースは有効じゃない
trace.enable
... # この範囲のみトレースは有効
trace.disable

つまり,TracePoint.trace というのは,TracePoint.new して,それを enable するところを一息で行う便利メソッドというわけです.

ちなみに TracePoint#enable はブロックを与えることができ,そのブロックを実行中のみトレースを有効にする,という使い方が出来ます.

trace = TracePoint.new(events...){|tp| ... trace ... }
... # まだトレースは有効じゃない
trace.enable{
  ... # この範囲のみトレースは有効
}

TracePoint#disable も,同様にブロックを与えることができ,そのブロックの範囲だけトレースを無効にすることができます.


さて,ではどのイベントがトレースできるか,ですが基本的には set_trace_func でできたトレース+αとなっています.TracePoint の rdoc から引用します.

ここまでは set_trace_func と同じで,

これらが TracePoint から新たに可能になったトレースできるイベントになります.まぁ,意味は読めばわかりますよね.

シンボルで渡せるようにした都合上,"c-call" のようなイベント名は :c_call にようになっています.


さて,次に TracePoint.new のブロックに渡ってくるブロックパラメータは一体なんなのか,ということを調べてみます.まず,クラスを見てみます.

trace = TracePoint.trace{|tp|
  p tp.class
  exit
}
#=> TracePoint

どうやら,これも TracePoint オブジェクトのようです.

inspect して調べてみましょう.

trace = TracePoint.trace{|tp|
  p [:tp, tp.object_id, tp]
}
p [:trace, trace.object_id, trace]
#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
[:tp, 1476430, #<TracePoint:c_return `trace'@t.rb:1>]
[:tp, 1476430, #<TracePoint:line@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `object_id'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `object_id'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `p'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `hash'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `hash'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:trace, 1476430, #<TracePoint:enabled>]
[:tp, 1476430, #<TracePoint:c_return `p'@t.rb:4>]

ちょっとわかりづらくなっちゃってますが,実は TracePoint.new で作成されるオブジェクトとブロックパラメータ(ここでは tp)は同じオブジェクトです(object_id が同じなのがわかると思います).トレース実行ごとに情報へアクセスするためだけのオブジェクトを作成するのは嫌だなぁ,と思ってこういう設計にしています.

同じオブジェクトでありながら,inspect の結果が,トレース実行中と,トレースを実行していない時で違うのがわかります.トレース実行中は,TracePoint#inspect は何のイベントでトレース中であるか,わかりやすく表示しています.トレース実行中でないときは,その TracePoint オブジェクトで指定されるトレースが有効であるかどうかを示しています(この場合,enable と表示していますね).

なお,TracePoint#enabled? メソッドによって,そのトレースが有効であるかどうかを示しています.


最後に,トレース中にどんな情報が取れるかを紹介します.

event から binding までは,set_trace_func で取れた情報とほぼ同じです.

TracePoint#return_value は,:return, :c_return, :b_return イベントの時のみ利用できるメソッドで,return が発生したときの返値を渡します.その他のイベント発生中にこのメソッドを呼んでも例外が発生します.

TracePoint#raised_exception は,:raise イベントの時のみ利用できるメソッドで,どの例外が発生したのかを返します.TracePoint#return_value と同様に,その他のイベント発生中にこのメソッドを呼んでも例外が発生します.

さて,TracePoint#defined_class は,set_trace_func で利用できる klass 情報とは若干違います(上記で「ほぼ」と言ったのはこの点が異なるためです).set_trace_func では,特異メソッドが呼ばれたときに klass にはオリジナルのクラスが渡ってきましたが,TracePoint#defined_class では特異クラスが返るようになっています.これによって,このメソッドが特異クラスかどうかわかるようになっています.

さて,trace = TracePoint.trace{|tp| ...} としたとき,trace と tp が,実は同じということでしたが,では トレースを実行していないときに,trace.event などとするとどうなるでしょうか.答えは例外が発生する,でした.

さて,3 回でトレースポイントを紹介しました.色々と面白い使い方ができる新機能だと思いますので,何かしら使ってみて下さい.

では,今日はこの辺で.


好きなだけ長いコメントをどうぞ。

お名前


back

tton 記述が使えます。YukiWikiな記述してりゃ問題ありません。

「行頭に#code」 と、「行頭に#end」 で挟むと、その間の行は pre で囲まれます。プログラムのソースを書くときに使ってください。

例:

#code

(なんかプログラム書く)

#end

リンクは

[[なまえ|http://www.example.org]]

とか

[[http://www.example.org]]

で貼れます。

$Date: 2003/04/28 10:27:51 $