Exception 类
类 Exception
及其子类用于在 Kernel#raise
和 begin ... end
块中的 rescue
语句之间进行通信。
一个 Exception
对象携带有关异常的信息
-
其类型(异常的类)。
-
可选的描述性消息。
-
可选的回溯信息。
某些 Exception
的内置子类具有其他方法:例如,NameError#name
。
默认值¶ ↑
两个 Ruby 语句具有默认异常类
-
raise
:默认为RuntimeError
。 -
rescue
:默认为StandardError
。
全局变量¶ ↑
当异常已引发但尚未处理(在 rescue
、ensure
、at_exit
和 END
块中)时,将设置两个全局变量
-
$!
包含当前异常。 -
$@
包含其回溯。
自定义异常¶ ↑
为了提供其他或备用信息,程序可以创建派生自内置异常类的自定义异常类。
一个好的做法是,库创建一个单一的“通用”异常类(通常是 StandardError
或 RuntimeError
的子类),并让其其他异常类派生自该类。这允许用户捕获通用异常,从而捕获库可能引发的所有异常,即使库的未来版本添加了新的异常子类。
例如
class MyLibrary class Error < ::StandardError end class WidgetError < Error end class FrobError < Error end end
为了处理 MyLibrary::WidgetError 和 MyLibrary::FrobError,库用户可以捕获 MyLibrary::Error。
内置 Exception
类¶ ↑
Exception
的内置子类有
-
-
LoadError
-
-
fatal
公共类方法
如果没有参数,或参数与接收者相同,则返回接收者。否则,创建一个与接收者相同类的新异常对象,但消息等于 string.to_str
。
参见 as_json
。
# 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
构造一个新的 Exception
对象,可以选择传入一条消息。
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); }
如果异常消息将发送到 tty,则返回 true
。
static VALUE exc_s_to_tty_p(VALUE self) { return RBOOL(rb_stderr_tty_p()); }
公共实例方法
相等性——如果 obj 不是 Exception
,则返回 false
。否则,如果 exc 和 obj 共享相同的类、消息和回溯,则返回 true
。
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); }
方法 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>
# File ext/json/lib/json/add/exception.rb, line 29 def as_json(*) { JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace, } end
返回与异常关联的任何回溯。回溯是一个字符串数组,每个字符串包含“filename:lineNo: in ‘method”’或“filename:lineNo”。
def a raise "boom" end def b a() end begin b() rescue => detail print detail.backtrace.join("\n") end
生成
prog.rb:2:in `a' prog.rb:6:in `b' prog.rb:10
如果没有设置回溯,则返回nil
ex = StandardError.new ex.backtrace #=> nil
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; }
返回与异常关联的任何回溯。此方法类似于 Exception#backtrace
,但回溯是 Thread::Backtrace::Location
的数组。
此方法不受 Exception#set_backtrace()
的影响。
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; }
返回引发此异常时之前的异常 ($!)。这对于包装异常和保留原始异常信息很有用。
static VALUE exc_cause(VALUE exc) { return rb_attr_get(exc, id_cause); }
处理由 message
返回的字符串。
它可能会将异常的类名添加到第一行的末尾。此外,当highlight
关键字为 true 时,它会添加 ANSI 转义序列以使消息加粗。
如果您覆盖此方法,它必须容忍未知的关键字参数。传递给 full_message
的所有关键字参数都委托给此方法。
此方法被 did_you_mean 和 error_highlight 覆盖以添加其信息。
用户定义的异常类还可以定义自己的 detailed_message
方法以添加补充信息。当 highlight
为 true 时,它可以返回包含转义序列的字符串,但使用广泛支持的转义序列。建议限制以下代码
-
重置 (
\e[0m
) -
加粗 (
\e[1m
) -
下划线 (
\e[4m
) -
除白色和黑色之外的前景色
-
红色 (
\e[31m
) -
绿色 (
\e[32m
) -
黄色 (
\e[33m
) -
蓝色 (
\e[34m
) -
洋红色 (
\e[35m
) -
青色 (
\e[36m
)
-
即使 highlight
为 true,也要小心使用转义序列。不要使用转义序列来表达基本信息;即使忽略所有转义序列,消息也应该是可读的。
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, const VALUE emesg, int highlight); return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), RTEST(highlight)); }
如果没有参数,或参数与接收者相同,则返回接收者。否则,创建一个与接收者相同类的新异常对象,但消息等于 string.to_str
。
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; }
返回异常的格式化字符串。返回的字符串使用 Ruby 在向 stderr 打印未捕获的异常时使用的相同格式进行格式化。
如果highlight为true
,默认错误处理程序会将消息发送到 tty。
order 必须是 :top
或 :bottom
之一,并将错误消息和最内部的回溯放在顶部或底部。
这些选项的默认值取决于调用时间时的 $stderr
和其 tty?
。
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; }
返回此异常的类名和消息。
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; }
返回调用 exception.to_s
的结果。通常,这会返回异常的消息或名称。
static VALUE exc_message(VALUE exc) { return rb_funcallv(exc, idTo_s, 0, 0); }
设置与 exc
关联的回溯信息。backtrace
必须是一个 String
对象数组或一个 String
,格式如 Exception#backtrace
中所述。
static VALUE exc_set_backtrace(VALUE exc, VALUE bt) { return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt)); }
返回表示 self
的 JSON
字符串
require 'json/add/exception' puts Exception.new('Foo').to_json
输出
{"json_class":"Exception","m":"Foo","b":null}
# File ext/json/lib/json/add/exception.rb, line 46 def to_json(*args) as_json.to_json(*args) end
返回异常的消息(如果没有设置消息,则返回异常的名称)。
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); }