2008-09-20 37 views
7

Dưới đây là vài khung hình cuối cùng của một Ruby điển hình on Rails traceback: application trace http://img444.imageshack.us/img444/8990/rails-lastfew.pngLàm thế nào tôi có thể nhận được giá trị nguồn và biến trong tracebacks ruby?

Và đây là vài khung hình cuối cùng của một traceback Nevow điển hình bằng Python: alt text http://img444.imageshack.us/img444/9173/nw-lastfew.png

Nó không chỉ là môi trường web, hoặc, bạn có thể so sánh tương tự giữa ipython và irb. Làm thế nào tôi có thể nhận được nhiều hơn các loại chi tiết trong Ruby?

+0

Xin chào, các liên kết hình ảnh bị hỏng. – alanjds

Trả lời

7

AFAIK, một khi ngoại lệ đã bị bắt quá muộn để lấy bối cảnh trong đó nó được nâng lên. Nếu bạn bẫy cuộc gọi mới của ngoại lệ, bạn có thể sử dụng Binding.of_caller của evil.rb để lấy phạm vi gọi và thực hiện

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

Nhưng đó thực sự là một hack lớn. Câu trả lời đúng là có lẽ để mở rộng Ruby để cho phép kiểm tra một số ngăn xếp cuộc gọi. Tôi không chắc chắn nếu một số triển khai Ruby mới sẽ cho phép điều này, nhưng tôi nhớ một phản ứng dữ dội chống lại Binding.of_caller bởi vì nó sẽ làm cho tối ưu hóa khó khăn hơn nhiều.

(Thành thật mà nói, tôi không hiểu phản ứng dữ dội này:. Miễn là thông dịch viên ghi đầy đủ thông tin về tối ưu hóa thực hiện, Binding.of_caller nên có thể làm việc, mặc dù có lẽ chậm)

Cập nhật

Ok, tôi đã tìm ra. Mã dài sau:

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 
Các vấn đề liên quan