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
Xin chào, các liên kết hình ảnh bị hỏng. – alanjds