'In Ruby, is there a Binding available that is created at the time of the exception available during the rescue?
The precise pain point I'm having is I am parsing a list of files. Each file has multiple lines. When something goes wrong, I'd like to print out such things as the current file name, the current line number, the current line, and some other interesting variables and then exit in most cases since the error will be in my code that needs to be enhanced.
Most of the variables are local to the #each blocks that are nested. There are multiple places something could go wrong.
What I'd like to do is just have one global begin, rescue, end block and within the rescue have a Binding available to me so I could dig out the various variables I'm interested in printing out.
This seems like a rather obvious Ruby type thing so I find it odd that I'm the first guy who would want such a thing. Yet, I don't see any Binding or closure concepts in the exception handling parts of Ruby's documentation. Usually this means I'm radically misusing the concepts of the language.
Solution 1:[1]
Well, the easiest way is to define all variables that you want to track before your begin ... rescue ... end block.
You can then easily access them within the rescue block:
variable = 0
another_variable = 0
begin
3.times do |a|
variable = a
5.times do |b|
another_variable = b
if a == 2 and b == 4
raise KeyError
end
end
end
at_exit do
puts binding.eval 'variable'
puts binding.eval 'another_variable'
end
rescue KeyError
puts variable
puts another_variable
end
But if you want to get last binding before exception occurs - your solution is to use TracePoint:
https://ruby-doc.org/core-2.5.0/TracePoint.html
This allows u to track bindings where local variable that u need is defined and then get last of them. Of course, if you will use this method it will make your program a little bit slower. The example of usage:
last_binding = nil
trace = TracePoint.new(:b_return) do |tp|
last_binding = tp.binding if tp.binding.local_variable_defined?('variable')
end
trace.enable
begin
3.times do |a|
variable = a
5.times do |b|
another_variable = b
if a == 2 and b == 4
raise KeyError
end
end
end
at_exit do
puts binding.eval 'variable'
puts binding.eval 'another_variable'
end
rescue KeyError
trace.disable
puts last_binding.eval 'another_variable'
end
(The best event for u to track is b_return - it occurs after each block's ending, so this will make your tracking time-optimal)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Leon |
