Rubyで呼ばれたメソッドを列挙するやつ作った
2017-05-27
Techこの記事を読んで、TracePointで同じことができないかと考えた。TracePointはRuby 2.0からある機能で、Rubyのメソッド呼び出しなどのイベントをフックできる。(昔のset_trace_funcに相当する)
とりあえず動いたのでgithubに置いた。
こういう適当なa.rbがあるとする。
class A
def self.asdf
end
def foo
p yield
end
def bar
# do nothing
end
end
A.new.foo{ 1 }
A.new.bar{ 1 }
A.asdf
これをruby -r ./trace_method_call.rb examples/a.rb
のようにして動かすと以下のように、本体を実行した後に呼ばれたメソッドの一覧が出る。
1
--- Called Methods ---
A#bar
A#foo
A.asdf
実行例
このブログのテスト(rspec)に適用してみたのがこれ。
生成にはけっこう時間がかかる。通常は6秒で終わるのが27秒かかっている。
% time bundle exec rspec
...............................
Finished in 2.71 seconds (files took 2.21 seconds to load)
31 examples, 0 failures
bundle exec rspec 4.57s user 0.61s system 85% cpu 6.028 total
% time bundle exec rspec -r ~/proj/lang/ruby/MethodCallTracer/trace_method_call.rb > calls.txt
bundle exec rspec -r ~/proj/lang/ruby/MethodCallTracer/trace_method_call.rb > 25.12s user 0.89s system 96% cpu 27.021 total
用途
例えば冒頭のブログ記事のように、メソッドが使われたかどうか判定するのに使えそうだ。ただしTracePointだと全部のメソッド呼び出しでフックが走るので遅い。okurubito gemの方は事前にメソッド名の一覧を用意して、それらに対してラップしたメソッドを生成するような感じっぽくて、それだとずっと速そう。
実装
見れば分かるが中身は50行弱しかない。TracePointでcallイベントをフックしているだけ。ただ実際のコードで試してみたらメタプログラミングで作られた変なクラス名が大量にヒットしたので、そういうのは除外するようにしている。
https://github.com/yhara/MethodCallTracer/blob/master/trace_method_call.rb