@@ -1706,16 +1706,16 @@ check_order_keyword(VALUE opt)
17061706 * Output:
17071707 *
17081708 * "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>'"]
17191719 *
17201720 * An overriding method should be careful with ANSI code enhancements;
17211721 * see {Messages}[rdoc-ref:exceptions.md@Messages].
@@ -1864,26 +1864,31 @@ exc_inspect(VALUE exc)
18641864 * call-seq:
18651865 * backtrace -> array or nil
18661866 *
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.
18691869 *
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>):
18781871 *
1879- * Example:
1872+ * def division(numerator, denominator)
1873+ * numerator / denominator
1874+ * end
18801875 *
18811876 * 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
18851884 * 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.)
18871892 *
18881893 * see {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
18891894 */
@@ -1930,20 +1935,37 @@ rb_get_backtrace(VALUE exc)
19301935 * call-seq:
19311936 * backtrace_locations -> array or nil
19321937 *
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.
19351940 *
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>):
19381942 *
1939- * Example:
1943+ * def division(numerator, denominator)
1944+ * numerator / denominator
1945+ * end
19401946 *
19411947 * 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#/"
19451961 * 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.)
19471969 *
19481970 * See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
19491971 */
@@ -1985,15 +2007,100 @@ rb_check_backtrace(VALUE bt)
19852007 * call-seq:
19862008 * set_backtrace(value) -> value
19872009 *
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"')
19892070 *
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:
19932073 *
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"')
19952085 *
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
19972104 *
19982105 * See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
19992106 */
0 commit comments