yhara.jp

Recent Posts
Edit

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


More posts