July 07, 2006

Ruby Debug Injection

Rubyでプログラムをよく書くのですが、メソッドの入出力を監視したい、つまりメソッドの引数と返り値が何であるか知りたくなることがあります。
こんなとき、いちいち当該メソッドにいわゆるprintfを仕込んだりするのは面倒なので、何かよい案がないか考えてみました。もしかしたら標準の機能でそういうものがあったかもしれませんが、とりあえず作ってみたので公開してみたいと思います。

module Debugger
    def debug(target_method, do_debug = true)
        if target_method.class != Symbol then
            target_method = target_method.intern
        end
        target_orig = "#{target_method}_orig".intern
        unless self.instance_methods.include?(target_orig.to_s) then
            self.instance_eval{
                alias_method(target_orig, target_method)
            }
        end
        target_debug = "#{target_method}_debug".intern
        unless self.instance_methods.include?(target_debug.to_s) then
            self.module_eval(<<-__EVAL_STRING__)
                def #{target_debug}(*params)
                    params.each_with_index{|param, i|
                        puts 'INPUT' + i.to_s + ': ' + param.inspect
                    }
                    output = #{target_orig}(*params)
                    puts 'OUTPUT: ' + output.inspect
                    return output
                end
            __EVAL_STRING__
        end
        self.instance_eval{
            alias_method(target_method, do_debug ? target_debug : target_orig)
        }
    end
end
使い方としては
class Target
    def a(b, c=nil)
        puts "ARG0: #{b}"
        puts "ARG1: #{c}"
        return c
    end
end

class Target
    extend Debugger
end

Target::new.a(1)    # normal
Target::new.a(1,2)    # normal

Target::debug(:a)    #attach debugger to method :a
Target::new.a(1)    # debugging ...
Target::new.a(1,2)    # debugging ...

Target::debug(:a, false)    #detach debugger from method :a
Target::new.a(1)    # normal
Target::new.a(1,2)    # normal

スクリプト言語だから当たり前といってしまえばそれまでですが、Rubyはリフレクションの機能が強力なので怪しげなことが簡単にできてしまって楽しいです。でも、リフレクションを使いまくると明らかにコードが読みにくくなり、他の人に迷惑がかかるので注意したほうがいいかもしれません。ちなみに僕はリフレクションは好きな方なので、チームで開発した際に他のメンバーに迷惑をかけた記憶があります(笑)。

23:59 fenrir が投稿 : 固定リンク | | このエントリーを含むはてなブックマーク | この記事をdel.icio.usでブックマーク | トラックバック
このエントリーのトラックバックURL: http://fenrir.naruoka.org/mt/mt-tb.cgi/498
コメント
コメントする









名前、アドレスを登録しますか?
(次回以降コメント入力が楽になります)
  • 匿名でのコメントは受け付けておりません。
  • 名前(ハンドル名可)とメールアドレスは必ず入力してください。
  • メールアドレスを表示されたくないときはURLも必ず記入してください。
  • コメント欄でHTMLタグは使用できません。
  • コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
  • コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。