Perl での print debug の方法の紹介がブーム(?)だったので、自分がよく行ってる Ruby での debug 方法7つについて書いてみます。

p ご存じの人も多い Kernel#p メソッド。これを使うとオブジェクトの内容を見やすい形で出力してくれます。 >> p ({:foobar => :baz}) {:foobar=>:baz} Object#inspect を使うと、p で出力するときと同じ文字列を String として取得できます。 >> puts ({:foobar => :baz}).inspect {:foobar=>:baz} 初心者の頃この p での出力を使う方法がわからなくて困った記憶が…。

pp pp というライブラリを使うと、p より、より見やすい形式で出力してくれます。たとえば >> a = Array.new(10) { {:foobar => :baz} } >> p a [{:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}] な感じで、Array や Hash の内容が大きくなってくると、きれいに折り返しされず見づらくなってしまいますが、pp を使うとこれが解消できます。 >> require 'pp' >> pp a [{:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}] また pp の出力を String として取得したい場合は PP.pp の第一引数に object を、第二引数に空文字列を渡すことで取得できます。 >> str = PP.pp(a,'') >> puts str [{:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}, {:foobar=>:baz}] わりと BK な取得方法ですが、ソースを見た感じではこれ以外の方法が無い気がします。 追記 ruby >= 1.8.5 な添付ライブラリの pp.rb では Kernel#pretty_inspect が追加されており、 str = obj.pretty_inspect で文字列として取得できます。コメントにて教えてもらいました。

y require 'yaml' すると、Kernel#y メソッドが追加され、y obj で YAML 形式で Object の中身を見ることができます。 >> y ({:foobar => :baz}) --- :foobar: :baz pp でいいじゃん、という気がするので個人的にはほとんど使ってませんが、ときたま html 上にオブジェクトの中身を表示させたい時に使うときがあります。なぜなら p/pp では Object#inspect まんまの表示なので、 >> p Object.new #<Object:0x409095bc> とタグで囲まれて出力されるため、HTMLエスケープが必要なのですが、YAMLの場合は >> y Object.new --- !ruby/object {} と必要ないためです。

backtrace を追う いままでプログラムがどうやって実行されてきたのかを追うには backtrace を見るのが一番です。以前は Exception を発生させてその backtrace を見る、というなんとも微妙なことをしていたんですが、ちょうど一年ほど前 id:ha-tan:20051014:1129218253 で教えてもらい、caller を見ればよいことがわかりました。

なので class Foo def foo bar end def bar baz end def baz p caller end end Foo.new.foo な呼び出しは ["call.rb:6:in `bar'", "call.rb:3:in `foo'", "call.rb:13"] と、最初に13行目でメソッドが呼びだされ、次に foo メソッド内部3行目でメソッドが呼び出され、その後 bar メソッド内部の6行目で呼び出され…、と容易に追っかけることができます。

set_trace_func set_trace_func という組み込み関数で、メソッド呼び出しや式の評価など、様々なイベントにフックして手続きオブジェクトを実行可能です。

割と何でもできる強力なリフレクションとして使えますが、重くなるのでデバッグ専用な感じです。

たとえば bar という名前のメソッドが呼び出された時にアクションを起こしたいときはこんな感じに。 class Foo def foo bar end def bar end end class Bar < Foo def bar end end set_trace_func lambda { |event, file, line ,id, binding, klass| if event == 'call' && id == :bar puts "call method bar file:#{file} line:#{line}" end } Foo.new.foo Bar.new.foo 結果は call method bar file:call.rb line:5 call method bar file:call.rb line:10

logger を使う Class を作るときは logger インターフェイスを作っておくと何かと便利です。最近の個人的なスタンダードなテンプレは require 'logger' class Foo def initialize(logger = nil) @logger = logger || Logger.new(STDERR) end attr_reader :logger def foo logger.debug 'call:foo' end end Foo.new.foo #=> D, [2006-10-10T12:33:16.581481 #10500] DEBUG -- : call:foo な感じで initialize でインスタンス変数に logger を入れておき、attr_reader で読み取り用のアクセサに @logger を設定することで、そのクラス内側からはどこからでも logger で参照できるようにしてます。Rails 脳。

またこのクラスを Rails から呼び出して使う時は Foo.new RAILS_DEFAULT_LOGGER で Rails 標準の logger インスタンスを利用してログがはけて便利です。