8

以下は、典型的な Ruby on Rails トレースバックの最後の数フレームです。 アプリケーション トレース

Python での典型的な Nevow トレースバックの最後の数フレームを次に示します。 代替テキスト

Web環境だけではなく、ipythonとirbでも同様の比較ができます。Ruby でこの種の詳細をさらに取得するにはどうすればよいでしょうか?

4

1 に答える 1

7

私の知る限り、例外がキャッチされると、それが発生したコンテキストを取得するには遅すぎます。例外の新しい呼び出しをトラップする場合は、evil.rb の Binding.of_caller を使用して呼び出しスコープを取得し、次のようにします。

eval("local_variables.collect { |l| [l, eval(l)] }", Binding.of_caller)

しかし、それはかなり大きなハックです。正しい答えは、Ruby を拡張してコール スタックをある程度検査できるようにすることでしょう。新しい Ruby 実装のいくつかがこれを許可するかどうかはわかりませんが、Binding.of_caller に対する反発を覚えています。最適化がはるかに難しくなるからです。

(正直なところ、私はこの反発を理解していません。インタープリターが実行された最適化に関する十分な情報を記録している限り、おそらくゆっくりではありますが、Binding.of_caller は機能するはずです。)

アップデート

わかりました、私はそれを理解しました。長いコードは次のとおりです。

class Foo < Exception
  attr_reader :call_binding

  def initialize
    # Find the calling location
    expected_file, expected_line = caller(1).first.split(':')[0,2]
    expected_line = expected_line.to_i
    return_count = 5  # If we see more than 5 returns, stop tracing

    # Start tracing until we see our caller.
    set_trace_func(proc do |event, file, line, id, binding, kls|
      if file == expected_file && line == expected_line
        # Found it: Save the binding and stop tracing
        @call_binding = binding
        set_trace_func(nil)
      end

      if event == :return
        # Seen too many returns, give up. :-(
        set_trace_func(nil) if (return_count -= 1) <= 0
      end
    end)
  end
end

class Hello
  def a
    x = 10
    y = 20
    raise Foo
  end
end
class World
  def b
    Hello.new.a
  end
end

begin World.new.b
rescue Foo => e
  b = e.call_binding
  puts eval("local_variables.collect {|l| [l, eval(l)]}", b).inspect
end
于 2008-09-20T07:10:39.723 に答える