[DOC] Adjust documentation related to backtraces (#12420)
This commit is contained in:
parent
3be1baab82
commit
58460b4dbd
Notes:
git
2024-12-24 18:50:15 +00:00
Merged-By: zverok <zverok.offline@gmail.com>
@ -26,7 +26,7 @@ that prints a message and exits the program (or thread):
|
||||
|
||||
```console
|
||||
$ ruby -e "raise"
|
||||
-e:1:in `<main>': unhandled exception
|
||||
-e:1:in '<main>': unhandled exception
|
||||
```
|
||||
|
||||
### Rescued Exceptions
|
||||
@ -201,7 +201,7 @@ Output:
|
||||
|
||||
```
|
||||
#<ZeroDivisionError: divided by 0>
|
||||
["t.rb:2:in `/'", "t.rb:2:in `<main>'"]
|
||||
["t.rb:2:in 'Integer#/'", "t.rb:2:in '<main>'"]
|
||||
```
|
||||
|
||||
##### Cause
|
||||
@ -362,8 +362,8 @@ Output:
|
||||
|
||||
```
|
||||
ruby t.rb
|
||||
t.rb:2:in `/': divided by 0 (ZeroDivisionError)
|
||||
from t.rb:2:in `<main>'
|
||||
t.rb:2:in 'Integer#/': divided by 0 (ZeroDivisionError)
|
||||
from t.rb:2:in '<main>'
|
||||
```
|
||||
|
||||
#### Retrying
|
||||
@ -501,28 +501,21 @@ These methods return backtrace information:
|
||||
of Thread::Backtrace::Location objects or `nil`.
|
||||
Each Thread::Backtrace::Location object gives detailed information about a called method.
|
||||
|
||||
An `Exception` object stores its backtrace value as one of:
|
||||
By default, Ruby sets the backtrace of the exception to the location where it
|
||||
was raised.
|
||||
|
||||
- An array of Thread::Backtrace::Location objects;
|
||||
this is the common case: the exception was raised by the Ruby core or the Ruby standard library.
|
||||
In this case:
|
||||
The developer might adjust this by either providing +backtrace+ argument
|
||||
to Kernel#raise, or using Exception#set_backtrace.
|
||||
|
||||
- Exception#backtrace_locations returns the array of Thread::Backtrace::Location objects.
|
||||
- Exception#backtrace returns the array of their string values
|
||||
(`Exception#backtrace_locations.map {|loc| loc.to_s }`).
|
||||
|
||||
- An array of strings;
|
||||
this is an uncommon case: the user manually set the backtrace to an array of strings;
|
||||
In this case:
|
||||
|
||||
- Exception#backtrace returns the array of strings.
|
||||
- Exception#backtrace_locations returns `nil`.
|
||||
|
||||
- `nil`, in which case both methods return `nil`.
|
||||
|
||||
These methods set the backtrace value:
|
||||
|
||||
- Exception#set_backtrace: sets the backtrace value to an array of strings, or to `nil`.
|
||||
- Kernel#raise: sets the backtrace value to an array of Thread::Backtrace::Location objects,
|
||||
or to an array of strings.
|
||||
Note that:
|
||||
|
||||
- by default, both +backtrace+ and +backtrace_locations+ represent the same backtrace;
|
||||
- if the developer sets the backtrace by one of the above methods to an array of
|
||||
Thread::Backtrace::Location, they still represent the same backtrace;
|
||||
- if the developer sets the backtrace to a string or an array of strings:
|
||||
- by Kernel#raise: +backtrace_locations+ become +nil+;
|
||||
- by Exception#set_backtrace: +backtrace_locations+ preserve the original
|
||||
value;
|
||||
- if the developer sets the backtrace to +nil+ by Exception#set_backtrace,
|
||||
+backtrace_locations+ preserve the original value; but if the exception is then
|
||||
reraised, both +backtrace+ and +backtrace_locations+ become the location of reraise.
|
||||
|
187
error.c
187
error.c
@ -1706,16 +1706,16 @@ check_order_keyword(VALUE opt)
|
||||
* Output:
|
||||
*
|
||||
* "divided by 0"
|
||||
* ["t.rb:3:in `/': divided by 0 (ZeroDivisionError)",
|
||||
* "\tfrom t.rb:3:in `baz'",
|
||||
* "\tfrom t.rb:10:in `bar'",
|
||||
* "\tfrom t.rb:11:in `foo'",
|
||||
* "\tfrom t.rb:12:in `<main>'"]
|
||||
* ["t.rb:3:in `/': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
|
||||
* "\tfrom t.rb:3:in `baz'",
|
||||
* "\tfrom t.rb:10:in `bar'",
|
||||
* "\tfrom t.rb:11:in `foo'",
|
||||
* "\tfrom t.rb:12:in `<main>'"]
|
||||
* ["t.rb:3:in 'Integer#/': divided by 0 (ZeroDivisionError)",
|
||||
* "\tfrom t.rb:3:in 'Object#baz'",
|
||||
* "\tfrom t.rb:10:in 'Object#bar'",
|
||||
* "\tfrom t.rb:11:in 'Object#foo'",
|
||||
* "\tfrom t.rb:12:in '<main>'"]
|
||||
* ["t.rb:3:in 'Integer#/': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
|
||||
* "\tfrom t.rb:3:in 'Object#baz'",
|
||||
* "\tfrom t.rb:10:in 'Object#bar'",
|
||||
* "\tfrom t.rb:11:in 'Object#foo'",
|
||||
* "\tfrom t.rb:12:in '<main>'"]
|
||||
*
|
||||
* An overriding method should be careful with ANSI code enhancements;
|
||||
* see {Messages}[rdoc-ref:exceptions.md@Messages].
|
||||
@ -1864,26 +1864,31 @@ exc_inspect(VALUE exc)
|
||||
* call-seq:
|
||||
* backtrace -> array or nil
|
||||
*
|
||||
* Returns a backtrace value for +self+;
|
||||
* the returned value depends on the form of the stored backtrace value:
|
||||
* Returns the backtrace (the list of code locations that led to the exception),
|
||||
* as an array of strings.
|
||||
*
|
||||
* - \Array of Thread::Backtrace::Location objects:
|
||||
* returns the array of strings given by
|
||||
* <tt>Exception#backtrace_locations.map {|loc| loc.to_s }</tt>.
|
||||
* This is the normal case, where the backtrace value was stored by Kernel#raise.
|
||||
* - \Array of strings: returns that array.
|
||||
* This is the unusual case, where the backtrace value was explicitly
|
||||
* stored as an array of strings.
|
||||
* - +nil+: returns +nil+.
|
||||
* Example (assuming the code is stored in the file named <tt>t.rb</tt>):
|
||||
*
|
||||
* Example:
|
||||
* def division(numerator, denominator)
|
||||
* numerator / denominator
|
||||
* end
|
||||
*
|
||||
* begin
|
||||
* 1 / 0
|
||||
* rescue => x
|
||||
* x.backtrace.take(2)
|
||||
* division(1, 0)
|
||||
* rescue => ex
|
||||
* p ex.backtrace
|
||||
* # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
|
||||
* loc = ex.backtrace.first
|
||||
* p loc.class
|
||||
* # String
|
||||
* end
|
||||
* # => ["(irb):132:in `/'", "(irb):132:in `<top (required)>'"]
|
||||
*
|
||||
* The value returned by this method migth be adjusted when raising (see Kernel#raise),
|
||||
* or during intermediate handling by #set_backtrace.
|
||||
*
|
||||
* See also #backtrace_locations that provide the same value, as structured objects.
|
||||
* (Note though that two values might not be consistent with each other when
|
||||
* backtraces are manually adjusted.)
|
||||
*
|
||||
* see {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
|
||||
*/
|
||||
@ -1930,20 +1935,37 @@ rb_get_backtrace(VALUE exc)
|
||||
* call-seq:
|
||||
* backtrace_locations -> array or nil
|
||||
*
|
||||
* Returns a backtrace value for +self+;
|
||||
* the returned value depends on the form of the stored backtrace value:
|
||||
* Returns the backtrace (the list of code locations that led to the exception),
|
||||
* as an array of Thread::Backtrace::Location instances.
|
||||
*
|
||||
* - \Array of Thread::Backtrace::Location objects: returns that array.
|
||||
* - \Array of strings or +nil+: returns +nil+.
|
||||
* Example (assuming the code is stored in the file named <tt>t.rb</tt>):
|
||||
*
|
||||
* Example:
|
||||
* def division(numerator, denominator)
|
||||
* numerator / denominator
|
||||
* end
|
||||
*
|
||||
* begin
|
||||
* 1 / 0
|
||||
* rescue => x
|
||||
* x.backtrace_locations.take(2)
|
||||
* division(1, 0)
|
||||
* rescue => ex
|
||||
* p ex.backtrace_locations
|
||||
* # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
|
||||
* loc = ex.backtrace_locations.first
|
||||
* p loc.class
|
||||
* # Thread::Backtrace::Location
|
||||
* p loc.path
|
||||
* # "t.rb"
|
||||
* p loc.lineno
|
||||
* # 2
|
||||
* p loc.label
|
||||
* # "Integer#/"
|
||||
* end
|
||||
* # => ["(irb):150:in `/'", "(irb):150:in `<top (required)>'"]
|
||||
*
|
||||
* The value returned by this method might be adjusted when raising (see Kernel#raise),
|
||||
* or during intermediate handling by #set_backtrace.
|
||||
*
|
||||
* See also #backtrace that provide the same value as an array of strings.
|
||||
* (Note though that two values might not be consistent with each other when
|
||||
* backtraces are manually adjusted.)
|
||||
*
|
||||
* See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
|
||||
*/
|
||||
@ -1985,15 +2007,100 @@ rb_check_backtrace(VALUE bt)
|
||||
* call-seq:
|
||||
* set_backtrace(value) -> value
|
||||
*
|
||||
* Sets the backtrace value for +self+; returns the given +value:
|
||||
* Sets the backtrace value for +self+; returns the given +value+.
|
||||
*
|
||||
* x = RuntimeError.new('Boom')
|
||||
* x.set_backtrace(%w[foo bar baz]) # => ["foo", "bar", "baz"]
|
||||
* x.backtrace # => ["foo", "bar", "baz"]
|
||||
* The +value+ might be:
|
||||
*
|
||||
* The given +value+ must be an array of strings, a single string, or +nil+.
|
||||
* - an array of Thread::Backtrace::Location;
|
||||
* - an array of String instances;
|
||||
* - a single String instance; or
|
||||
* - +nil+.
|
||||
*
|
||||
* Does not affect the value returned by #backtrace_locations.
|
||||
* 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}[rdoc-ref:exceptions.md@Backtraces].
|
||||
*/
|
||||
|
35
eval.c
35
eval.c
@ -782,16 +782,37 @@ rb_f_raise(int argc, VALUE *argv)
|
||||
*
|
||||
* See {Messages}[rdoc-ref:exceptions.md@Messages].
|
||||
*
|
||||
* Argument +backtrace+ sets the stored backtrace in the new exception,
|
||||
* which may be retrieved by method Exception#backtrace;
|
||||
* the backtrace must be an array of strings or +nil+:
|
||||
* Argument +backtrace+ might be used to modify the backtrace of the new exception,
|
||||
* as reported by Exception#backtrace and Exception#backtrace_locations;
|
||||
* the backtrace must be an array of Thread::Backtrace::Location, an array of
|
||||
* strings, a single string, or +nil+.
|
||||
*
|
||||
* Using the array of Thread::Backtrace::Location instances is the most consistent option
|
||||
* and should be preferred when possible. The necessary value might be obtained
|
||||
* from #caller_locations, or copied from Exception#backtrace_locations of another
|
||||
* error:
|
||||
*
|
||||
* begin
|
||||
* raise(StandardError, 'Boom', %w[foo bar baz])
|
||||
* rescue => x
|
||||
* p x.backtrace
|
||||
* do_some_work()
|
||||
* rescue ZeroDivisionError => ex
|
||||
* raise(LogicalError, "You have an error in your math", ex.backtrace_locations)
|
||||
* end
|
||||
*
|
||||
* The ways, both Exception#backtrace and Exception#backtrace_locations of the
|
||||
* raised error are set to the same backtrace.
|
||||
*
|
||||
* 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 Exception#backtrace is set:
|
||||
*
|
||||
* begin
|
||||
* raise(StandardError, 'Boom', %w[dsl.rb:3 framework.rb:1])
|
||||
* rescue => ex
|
||||
* p ex.backtrace
|
||||
* # => ["dsl.rb:3", "framework.rb:1"]
|
||||
* p ex.backtrace_locations
|
||||
* # => nil
|
||||
* end
|
||||
* # => ["foo", "bar", "baz"]
|
||||
*
|
||||
* If argument +backtrace+ is not given,
|
||||
* the backtrace is set according to an array of Thread::Backtrace::Location objects,
|
||||
|
Loading…
x
Reference in New Issue
Block a user