8

这是典型的 Ruby on Rails 回溯的最后几帧: 应用程序跟踪

以下是 Python 中典型的 Nevow 回溯的最后几帧: 替代文字

不只是 web 环境,你可以在 ipython 和 irb 之间进行类似的比较。如何在 Ruby 中获得更多此类细节?

4

1 回答 1

7

AFAIK,一旦发现异常,就为时已晚,无法获取引发异常的上下文。如果你捕获异常的新调用,你可以使用 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 回答