Method: Exception#set_backtrace
- Defined in:
- error.c
#set_backtrace(value) ⇒ Object
Sets the backtrace value for self
; returns the given value
.
The value
might be:
-
an array of Thread::Backtrace::Location;
-
an array of String instances;
-
a single String instance; or
-
nil
.
Using array of Thread::Backtrace::Location is the most consistent option: it sets both #backtrace and #backtrace_locations. It should be preferred when possible. The suitable array of locations can be obtained from Kernel#caller_locations, copied from another error, or just set to the adjusted result of the current error’s #backtrace_locations:
require 'json'
def parse_payload(text)
JSON.parse(text) # test.rb, line 4
rescue JSON::ParserError => ex
ex.set_backtrace(ex.backtrace_locations[2...])
raise
end
parse_payload('{"wrong: "json"')
# test.rb:4:in 'Object#parse_payload': unexpected token at '{"wrong: "json"' (JSON::ParserError)
#
# An error points to the body of parse_payload method,
# hiding the parts of the backtrace related to the internals
# of the "json" library
# The error has both #backtace and #backtrace_locations set
# consistently:
begin
parse_payload('{"wrong: "json"')
rescue => ex
p ex.backtrace
# ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
p ex.backtrace_locations
# ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
end
When the desired stack of locations is not available and should be constructed from scratch, an array of strings or a singular string can be used. In this case, only #backtrace is affected:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(["dsl.rb:34", "framework.rb:1"])
# The error have the new value in #backtrace:
p ex.backtrace
# ["dsl.rb:34", "framework.rb:1"]
# but the original one in #backtrace_locations
p ex.backtrace_locations
# [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
end
parse_payload('{"wrong: "json"')
Calling #set_backtrace with nil
clears up #backtrace but doesn’t affect #backtrace_locations:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(nil)
p ex.backtrace
# nil
p ex.backtrace_locations
# [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
end
parse_payload('{"wrong: "json"')
On reraising of such an exception, both #backtrace and #backtrace_locations is set to the place of reraising:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(nil)
raise # test.rb, line 7
end
begin
parse_payload('{"wrong: "json"')
rescue => ex
p ex.backtrace
# ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
p ex.backtrace_locations
# ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
end
See Backtraces.
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 |
# File 'error.c', line 2108
static VALUE
exc_set_backtrace(VALUE exc, VALUE bt)
{
VALUE btobj = rb_location_ary_to_backtrace(bt);
if (RTEST(btobj)) {
rb_ivar_set(exc, id_bt, btobj);
rb_ivar_set(exc, id_bt_locations, btobj);
return bt;
}
else {
return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
}
}
|