@@ -1706,16 +1706,16 @@ check_order_keyword(VALUE opt)
1706
1706
* Output:
1707
1707
*
1708
1708
* "divided by 0"
1709
- * ["t.rb:3:in ` /': divided by 0 (ZeroDivisionError)",
1710
- * "\tfrom t.rb:3:in ` baz'",
1711
- * "\tfrom t.rb:10:in ` bar'",
1712
- * "\tfrom t.rb:11:in ` foo'",
1713
- * "\tfrom t.rb:12:in ` <main>'"]
1714
- * ["t.rb:3:in ` /': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
1715
- * "\tfrom t.rb:3:in ` baz'",
1716
- * "\tfrom t.rb:10:in ` bar'",
1717
- * "\tfrom t.rb:11:in ` foo'",
1718
- * "\tfrom t.rb:12:in ` <main>'"]
1709
+ * ["t.rb:3:in 'Integer# /': divided by 0 (ZeroDivisionError)",
1710
+ * "\tfrom t.rb:3:in 'Object# baz'",
1711
+ * "\tfrom t.rb:10:in 'Object# bar'",
1712
+ * "\tfrom t.rb:11:in 'Object# foo'",
1713
+ * "\tfrom t.rb:12:in ' <main>'"]
1714
+ * ["t.rb:3:in 'Integer# /': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
1715
+ * "\tfrom t.rb:3:in 'Object# baz'",
1716
+ * "\tfrom t.rb:10:in 'Object# bar'",
1717
+ * "\tfrom t.rb:11:in 'Object# foo'",
1718
+ * "\tfrom t.rb:12:in ' <main>'"]
1719
1719
*
1720
1720
* An overriding method should be careful with ANSI code enhancements;
1721
1721
* see {Messages}[rdoc-ref:exceptions.md@Messages].
@@ -1864,26 +1864,31 @@ exc_inspect(VALUE exc)
1864
1864
* call-seq:
1865
1865
* backtrace -> array or nil
1866
1866
*
1867
- * Returns a backtrace value for +self+;
1868
- * the returned value depends on the form of the stored backtrace value:
1867
+ * Returns the backtrace (the list of code locations that led to the exception),
1868
+ * as an array of strings.
1869
1869
*
1870
- * - \Array of Thread::Backtrace::Location objects:
1871
- * returns the array of strings given by
1872
- * <tt>Exception#backtrace_locations.map {|loc| loc.to_s }</tt>.
1873
- * This is the normal case, where the backtrace value was stored by Kernel#raise.
1874
- * - \Array of strings: returns that array.
1875
- * This is the unusual case, where the backtrace value was explicitly
1876
- * stored as an array of strings.
1877
- * - +nil+: returns +nil+.
1870
+ * Example (assuming the code is stored in the file named <tt>t.rb</tt>):
1878
1871
*
1879
- * Example:
1872
+ * def division(numerator, denominator)
1873
+ * numerator / denominator
1874
+ * end
1880
1875
*
1881
1876
* begin
1882
- * 1 / 0
1883
- * rescue => x
1884
- * x.backtrace.take(2)
1877
+ * division(1, 0)
1878
+ * rescue => ex
1879
+ * p ex.backtrace
1880
+ * # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
1881
+ * loc = ex.backtrace.first
1882
+ * p loc.class
1883
+ * # String
1885
1884
* end
1886
- * # => ["(irb):132:in `/'", "(irb):132:in `<top (required)>'"]
1885
+ *
1886
+ * The value returned by this method migth be adjusted when raising (see Kernel#raise),
1887
+ * or during intermediate handling by #set_backtrace.
1888
+ *
1889
+ * See also #backtrace_locations that provide the same value, as structured objects.
1890
+ * (Note though that two values might not be consistent with each other when
1891
+ * backtraces are manually adjusted.)
1887
1892
*
1888
1893
* see {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
1889
1894
*/
@@ -1930,20 +1935,37 @@ rb_get_backtrace(VALUE exc)
1930
1935
* call-seq:
1931
1936
* backtrace_locations -> array or nil
1932
1937
*
1933
- * Returns a backtrace value for +self+;
1934
- * the returned value depends on the form of the stored backtrace value:
1938
+ * Returns the backtrace (the list of code locations that led to the exception),
1939
+ * as an array of Thread::Backtrace::Location instances.
1935
1940
*
1936
- * - \Array of Thread::Backtrace::Location objects: returns that array.
1937
- * - \Array of strings or +nil+: returns +nil+.
1941
+ * Example (assuming the code is stored in the file named <tt>t.rb</tt>):
1938
1942
*
1939
- * Example:
1943
+ * def division(numerator, denominator)
1944
+ * numerator / denominator
1945
+ * end
1940
1946
*
1941
1947
* begin
1942
- * 1 / 0
1943
- * rescue => x
1944
- * x.backtrace_locations.take(2)
1948
+ * division(1, 0)
1949
+ * rescue => ex
1950
+ * p ex.backtrace_locations
1951
+ * # ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
1952
+ * loc = ex.backtrace_locations.first
1953
+ * p loc.class
1954
+ * # Thread::Backtrace::Location
1955
+ * p loc.path
1956
+ * # "t.rb"
1957
+ * p loc.lineno
1958
+ * # 2
1959
+ * p loc.label
1960
+ * # "Integer#/"
1945
1961
* end
1946
- * # => ["(irb):150:in `/'", "(irb):150:in `<top (required)>'"]
1962
+ *
1963
+ * The value returned by this method might be adjusted when raising (see Kernel#raise),
1964
+ * or during intermediate handling by #set_backtrace.
1965
+ *
1966
+ * See also #backtrace that provide the same value as an array of strings.
1967
+ * (Note though that two values might not be consistent with each other when
1968
+ * backtraces are manually adjusted.)
1947
1969
*
1948
1970
* See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
1949
1971
*/
@@ -1985,15 +2007,100 @@ rb_check_backtrace(VALUE bt)
1985
2007
* call-seq:
1986
2008
* set_backtrace(value) -> value
1987
2009
*
1988
- * Sets the backtrace value for +self+; returns the given +value:
2010
+ * Sets the backtrace value for +self+; returns the given +value+.
2011
+ *
2012
+ * The +value+ might be:
2013
+ *
2014
+ * - an array of Thread::Backtrace::Location;
2015
+ * - an array of String instances;
2016
+ * - a single String instance; or
2017
+ * - +nil+.
2018
+ *
2019
+ * Using array of Thread::Backtrace::Location is the most consistent
2020
+ * option: it sets both #backtrace and #backtrace_locations. It should be
2021
+ * preferred when possible. The suitable array of locations can be obtained
2022
+ * from Kernel#caller_locations, copied from another error, or just set to
2023
+ * the adjusted result of the current error's #backtrace_locations:
2024
+ *
2025
+ * require 'json'
2026
+ *
2027
+ * def parse_payload(text)
2028
+ * JSON.parse(text) # test.rb, line 4
2029
+ * rescue JSON::ParserError => ex
2030
+ * ex.set_backtrace(ex.backtrace_locations[2...])
2031
+ * raise
2032
+ * end
2033
+ *
2034
+ * parse_payload('{"wrong: "json"')
2035
+ * # test.rb:4:in 'Object#parse_payload': unexpected token at '{"wrong: "json"' (JSON::ParserError)
2036
+ * #
2037
+ * # An error points to the body of parse_payload method,
2038
+ * # hiding the parts of the backtrace related to the internals
2039
+ * # of the "json" library
2040
+ *
2041
+ * # The error has both #backtace and #backtrace_locations set
2042
+ * # consistently:
2043
+ * begin
2044
+ * parse_payload('{"wrong: "json"')
2045
+ * rescue => ex
2046
+ * p ex.backtrace
2047
+ * # ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
2048
+ * p ex.backtrace_locations
2049
+ * # ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
2050
+ * end
2051
+ *
2052
+ * When the desired stack of locations is not available and should
2053
+ * be constructed from scratch, an array of strings or a singular
2054
+ * string can be used. In this case, only #backtrace is affected:
2055
+ *
2056
+ * def parse_payload(text)
2057
+ * JSON.parse(text)
2058
+ * rescue JSON::ParserError => ex
2059
+ * ex.set_backtrace(["dsl.rb:34", "framework.rb:1"])
2060
+ * # The error have the new value in #backtrace:
2061
+ * p ex.backtrace
2062
+ * # ["dsl.rb:34", "framework.rb:1"]
2063
+ *
2064
+ * # but the original one in #backtrace_locations
2065
+ * p ex.backtrace_locations
2066
+ * # [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
2067
+ * end
2068
+ *
2069
+ * parse_payload('{"wrong: "json"')
1989
2070
*
1990
- * x = RuntimeError.new('Boom')
1991
- * x.set_backtrace(%w[foo bar baz]) # => ["foo", "bar", "baz"]
1992
- * x.backtrace # => ["foo", "bar", "baz"]
2071
+ * Calling #set_backtrace with +nil+ clears up #backtrace but doesn't affect
2072
+ * #backtrace_locations:
1993
2073
*
1994
- * The given +value+ must be an array of strings, a single string, or +nil+.
2074
+ * def parse_payload(text)
2075
+ * JSON.parse(text)
2076
+ * rescue JSON::ParserError => ex
2077
+ * ex.set_backtrace(nil)
2078
+ * p ex.backtrace
2079
+ * # nil
2080
+ * p ex.backtrace_locations
2081
+ * # [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
2082
+ * end
2083
+ *
2084
+ * parse_payload('{"wrong: "json"')
1995
2085
*
1996
- * Does not affect the value returned by #backtrace_locations.
2086
+ * On reraising of such an exception, both #backtrace and #backtrace_locations
2087
+ * is set to the place of reraising:
2088
+ *
2089
+ * def parse_payload(text)
2090
+ * JSON.parse(text)
2091
+ * rescue JSON::ParserError => ex
2092
+ * ex.set_backtrace(nil)
2093
+ * raise # test.rb, line 7
2094
+ * end
2095
+ *
2096
+ * begin
2097
+ * parse_payload('{"wrong: "json"')
2098
+ * rescue => ex
2099
+ * p ex.backtrace
2100
+ * # ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
2101
+ * p ex.backtrace_locations
2102
+ * # ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
2103
+ * end
1997
2104
*
1998
2105
* See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
1999
2106
*/
0 commit comments