class Exception
类 Exception 及其子类用于指示发生了错误或其他问题,并且可能需要进行处理。请参阅 Exceptions。
一个 Exception 对象携带某些信息
-
类型(异常的类),通常是
StandardError、RuntimeError或两者的子类;请参阅 内置异常类层次结构。 -
可选的回溯信息;请参阅方法
backtrace、backtrace_locations、set_backtrace。 -
可选的原因;请参阅方法
cause。
内置异常类层次结构
类 Exception 的内置子类的层次结构
-
-
-
Errno(及其子类,代表系统错误)
-
Public Class Methods
返回一个与 self 相同类的异常对象;这对于创建具有不同消息的类似异常很有用。
当 message 为 nil 时,返回 self
x0 = StandardError.new('Boom') # => #<StandardError: Boom> x1 = x0.exception # => #<StandardError: Boom> x0.__id__ == x1.__id__ # => true
对于 字符串可转换对象 message(即使与原始消息相同),返回一个新的异常对象,该对象的类与 self 相同,其消息为给定的 message
x1 = x0.exception('Boom') # => #<StandardError: Boom> x0..equal?(x1) # => false
Source
# File ext/json/lib/json/add/exception.rb, line 9 def self.json_create(object) result = new(object['m']) result.set_backtrace object['b'] result end
请参阅 as_json。
Source
static VALUE
exc_initialize(int argc, VALUE *argv, VALUE exc)
{
VALUE arg;
arg = (!rb_check_arity(argc, 0, 1) ? Qnil : argv[0]);
return exc_init(exc, arg);
}
Source
static VALUE
exc_s_to_tty_p(VALUE self)
{
return RBOOL(rb_stderr_tty_p());
}
如果异常消息将被发送到终端设备,则返回 true。
Public Instance Methods
Source
static VALUE
exc_equal(VALUE exc, VALUE obj)
{
VALUE mesg, backtrace;
if (exc == obj) return Qtrue;
if (rb_obj_class(exc) != rb_obj_class(obj)) {
int state;
obj = rb_protect(try_convert_to_exception, obj, &state);
if (state || UNDEF_P(obj)) {
rb_set_errinfo(Qnil);
return Qfalse;
}
if (rb_obj_class(exc) != rb_obj_class(obj)) return Qfalse;
mesg = rb_check_funcall(obj, id_message, 0, 0);
if (UNDEF_P(mesg)) return Qfalse;
backtrace = rb_check_funcall(obj, id_backtrace, 0, 0);
if (UNDEF_P(backtrace)) return Qfalse;
}
else {
mesg = rb_attr_get(obj, id_mesg);
backtrace = exc_backtrace(obj);
}
if (!rb_equal(rb_attr_get(exc, id_mesg), mesg))
return Qfalse;
return rb_equal(exc_backtrace(exc), backtrace);
}
Source
# File ext/json/lib/json/add/exception.rb, line 29 def as_json(*) { JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace, } end
方法 Exception#as_json 和 Exception.json_create 可用于序列化和反序列化 Exception 对象;请参阅 Marshal。
方法 Exception#as_json 序列化 self,返回一个代表 self 的 2 元素哈希
require 'json/add/exception' x = Exception.new('Foo').as_json # => {"json_class"=>"Exception", "m"=>"Foo", "b"=>nil}
方法 JSON.create 反序列化这样的哈希,返回一个 Exception 对象
Exception.json_create(x) # => #<Exception: Foo>
Source
static VALUE
exc_backtrace(VALUE exc)
{
VALUE obj;
obj = rb_attr_get(exc, id_bt);
if (rb_backtrace_p(obj)) {
obj = rb_backtrace_to_str_ary(obj);
/* rb_ivar_set(exc, id_bt, obj); */
}
return obj;
}
以字符串数组的形式返回回溯(导致异常的代码位置列表)。
示例(假设代码存储在名为 t.rb 的文件中)
def division(numerator, denominator) numerator / denominator end begin 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
此方法返回的值在引发时(参见 Kernel#raise)或在 set_backtrace 进行中间处理时可能会被调整。
另请参阅 backtrace_locations,它提供相同的值,作为结构化对象。(但请注意,当回溯被手动调整时,两个值可能不一致。)
另请参阅 Backtraces。
Source
static VALUE
exc_backtrace_locations(VALUE exc)
{
VALUE obj;
obj = rb_attr_get(exc, id_bt_locations);
if (!NIL_P(obj)) {
obj = rb_backtrace_to_location_ary(obj);
}
return obj;
}
以 Thread::Backtrace::Location 实例的数组形式返回回溯(导致异常的代码位置列表)。
示例(假设代码存储在名为 t.rb 的文件中)
def division(numerator, denominator) numerator / denominator end begin 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
此方法返回的值在引发时(参见 Kernel#raise)或在 set_backtrace 进行中间处理时可能会被调整。
另请参阅 backtrace,它以字符串数组的形式提供相同的值。(但请注意,当回溯被手动调整时,两个值可能不一致。)
另请参阅 Backtraces。
Source
static VALUE
exc_cause(VALUE exc)
{
return rb_attr_get(exc, id_cause);
}
返回全局变量 $! 的先前值,该值可能为 nil(请参阅 Global Variables)。
begin raise('Boom 0') rescue => x0 puts "Exception: #{x0}; $!: #{$!}; cause: #{x0.cause.inspect}." begin raise('Boom 1') rescue => x1 puts "Exception: #{x1}; $!: #{$!}; cause: #{x1.cause}." begin raise('Boom 2') rescue => x2 puts "Exception: #{x2}; $!: #{$!}; cause: #{x2.cause}." end end end
输出
Exception: Boom 0; $!: Boom 0; cause: nil. Exception: Boom 1; $!: Boom 1; cause: Boom 0. Exception: Boom 2; $!: Boom 2; cause: Boom 1.
Source
static VALUE
exc_detailed_message(int argc, VALUE *argv, VALUE exc)
{
VALUE opt;
rb_scan_args(argc, argv, "0:", &opt);
VALUE highlight = check_highlight_keyword(opt, 0);
extern VALUE rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight);
return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), RTEST(highlight));
}
返回带有增强的消息字符串
-
第一行包含异常类名。
-
如果关键字
highlight的值为true,则包含粗体和下划线 ANSI 代码(见下文)以增强消息的外观。
示例
begin 1 / 0 rescue => x p x.message p x.detailed_message # Class name added. p x.detailed_message(highlight: true) # Class name, bolding, and underlining added. end
输出
"divided by 0" "divided by 0 (ZeroDivisionError)" "\e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m"
此方法由 Ruby 标准库中的某些 gem 重写,以添加信息
重写的方法必须容忍传入的关键字参数,这些参数可能包括(但不限于)
-
:highlight. -
:did_you_mean. -
:error_highlight. -
:syntax_suggest.
重写的方法也应小心 ANSI 代码增强;请参阅 Messages。
Source
static VALUE
exc_exception(int argc, VALUE *argv, VALUE self)
{
VALUE exc;
argc = rb_check_arity(argc, 0, 1);
if (argc == 0) return self;
if (argc == 1 && self == argv[0]) return self;
exc = rb_obj_clone(self);
rb_ivar_set(exc, id_mesg, argv[0]);
return exc;
}
返回一个与 self 相同类的异常对象;这对于创建具有不同消息的类似异常很有用。
当 message 为 nil 时,返回 self
x0 = StandardError.new('Boom') # => #<StandardError: Boom> x1 = x0.exception # => #<StandardError: Boom> x0.__id__ == x1.__id__ # => true
对于 字符串可转换对象 message(即使与原始消息相同),返回一个新的异常对象,该对象的类与 self 相同,其消息为给定的 message
x1 = x0.exception('Boom') # => #<StandardError: Boom> x0..equal?(x1) # => false
Source
static VALUE
exc_full_message(int argc, VALUE *argv, VALUE exc)
{
VALUE opt, str, emesg, errat;
VALUE highlight, order;
rb_scan_args(argc, argv, "0:", &opt);
highlight = check_highlight_keyword(opt, 1);
order = check_order_keyword(opt);
{
if (NIL_P(opt)) opt = rb_hash_new();
rb_hash_aset(opt, sym_highlight, highlight);
}
str = rb_str_new2("");
errat = rb_get_backtrace(exc);
emesg = rb_get_detailed_message(exc, opt);
rb_error_write(exc, emesg, errat, str, opt, highlight, order);
return str;
}
返回增强的消息字符串
-
包含异常类名。
-
如果关键字
highlight的值为 true(非nil或false),则包含粗体 ANSI 代码(见下文)以增强消息的外观。 -
包含 回溯
-
如果关键字
order的值为:top(默认值),则首先列出错误消息和最内层的回溯条目。 -
如果关键字
order的值为:bottom,则最后列出错误消息和最内层的条目。
-
示例
def baz begin 1 / 0 rescue => x pp x.message pp x.full_message(highlight: false).split("\n") pp x.full_message.split("\n") end end def bar; baz; end def foo; bar; end foo
输出
"divided by 0" ["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>'"]
重写的方法应小心 ANSI 代码增强;请参阅 Messages。
Source
static VALUE
exc_inspect(VALUE exc)
{
VALUE str, klass;
klass = CLASS_OF(exc);
exc = rb_obj_as_string(exc);
if (RSTRING_LEN(exc) == 0) {
return rb_class_name(klass);
}
str = rb_str_buf_new2("#<");
klass = rb_class_name(klass);
rb_str_buf_append(str, klass);
if (RTEST(rb_str_include(exc, rb_str_new2("\n")))) {
rb_str_catf(str, ":%+"PRIsVALUE, exc);
}
else {
rb_str_buf_cat(str, ": ", 2);
rb_str_buf_append(str, exc);
}
rb_str_buf_cat(str, ">", 1);
return str;
}
返回 self 的字符串表示形式。
x = RuntimeError.new('Boom') x.inspect # => "#<RuntimeError: Boom>" x = RuntimeError.new x.inspect # => "#<RuntimeError: RuntimeError>"
Source
static VALUE
exc_message(VALUE exc)
{
return rb_funcallv(exc, idTo_s, 0, 0);
}
Source
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));
}
}
为 self 设置回溯值;返回给定的 value。
value 可能是
-
一个
Thread::Backtrace::Location数组; -
一个
String实例数组; -
一个单独的
String实例;或 -
nil.
使用 Thread::Backtrace::Location 数组是最一致的选择:它同时设置 backtrace 和 backtrace_locations。如果可能,应优先使用它。合适的 Thread::Backtrace::Location 数组可以从 Kernel#caller_locations 获取,从另一个错误复制,或者只是设置为当前错误 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
当所需的调用栈不可用且应从头开始构建时,可以使用字符串数组或单个字符串。在这种情况下,只有 backtrace 会受到影响。
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"')
使用 nil 调用 set_backtrace 会清除 backtrace,但不会影响 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"')
当重新引发此类异常时,backtrace 和 backtrace_locations 都将被设置为重新引发的位置。
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
另请参阅 Backtraces。
Source
# File ext/json/lib/json/add/exception.rb, line 46 def to_json(*args) as_json.to_json(*args) end
返回一个代表 self 的 JSON 字符串
require 'json/add/exception' puts Exception.new('Foo').to_json
输出
{"json_class":"Exception","m":"Foo","b":null}
Source
static VALUE
exc_to_s(VALUE exc)
{
VALUE mesg = rb_attr_get(exc, idMesg);
if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
return rb_String(mesg);
}
返回 self 的字符串表示形式。
x = RuntimeError.new('Boom') x.to_s # => "Boom" x = RuntimeError.new x.to_s # => "RuntimeError"