AFAIK, una vez que se ha capturado una excepción, es demasiado tarde para captar el contexto en el que surgió. Si trampa nueva llamada de excepción, se puede usar Binding.of_caller de evil.rb para agarrar el ámbito global del script, y hacer
eval("local_variables.collect { |l| [l, eval(l)] }", Binding.of_caller)
Pero eso es todo un gran truco. La respuesta correcta es probablemente extender Ruby para permitir una cierta inspección de la pila de llamadas. No estoy seguro de si algunas de las nuevas implementaciones de Ruby lo permitirán, pero sí recuerdo una reacción contra Binding.of_caller porque hará las optimizaciones mucho más difíciles.
(Para ser honesto, no entiendo esta reacción:., Siempre y cuando el intérprete registra información suficiente acerca de las optimizaciones realizadas, Binding.of_caller debe ser capaz de trabajar, aunque tal vez poco a poco)
actualización
Ok, lo descubrí. El código de Longish sigue:
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
Oye, los enlaces de imagen están rotos. – alanjds