2008-09-20 72 views
7

下面是一個典型的Ruby on Rails的回溯過去的幾幀: application trace http://img444.imageshack.us/img444/8990/rails-lastfew.png如何在ruby回溯中獲取源和變量值?

這裏是Python中的典型Nevow追溯的最後幾幀: alt text http://img444.imageshack.us/img444/9173/nw-lastfew.png

這不僅僅是網絡環境或者,你可以在ipython和irb之間進行類似的比較。我怎樣才能在Ruby中獲得更多這樣的細節?

+0

嘿,圖像鏈接已損壞。 – alanjds 2017-11-01 16:17:26

回答

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應能正常工作,但也許慢)

更新

好吧,我想通了。 Longish代碼如下:

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