类 Exception

Exception 及其子类用于在 Kernel#raiserescue 语句(在 begin ... end 代码块中)之间进行通信。

一个 Exception 对象包含有关异常的信息

  • 其类型(异常的类)。

  • 一个可选的描述性消息。

  • 可选的回溯信息。

一些内置的 Exception 子类具有额外的的方法:例如,NameError#name

默认值

两个 Ruby 语句具有默认的异常类

全局变量

当一个异常被抛出但尚未被处理(在 rescueensureat_exitEND 代码块中)时,会设置两个全局变量

  • $! 包含当前异常。

  • $@ 包含其回溯。

自定义异常

为了提供额外的或替代信息,程序可以创建从内置异常类派生的自定义异常类。

一个好的做法是让一个库创建一个单一的“通用”异常类(通常是 StandardErrorRuntimeError 的子类),并让其其他异常类从该类派生。这允许用户救援通用异常,从而捕获库可能抛出的所有异常,即使库的未来版本添加了新的异常子类。

例如

class MyLibrary
  class Error < ::StandardError
  end

  class WidgetError < Error
  end

  class FrobError < Error
  end

end

要处理 MyLibrary::WidgetError 和 MyLibrary::FrobError,库用户可以救援 MyLibrary::Error。

内置 Exception

内置的 Exception 子类是

公共类方法

exception([string]) → an_exception or exc

如果没有参数,或者参数与接收者相同,则返回接收者。否则,创建一个与接收者同类的新异常对象,但其消息等于string.to_str

new(msg = nil) → exception click to toggle source
exception(msg = nil) → exception

构造一个新的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);
}
to_tty? → true or false click to toggle source

如果异常消息将发送到 tty,则返回true

static VALUE
exc_s_to_tty_p(VALUE self)
{
    return RBOOL(rb_stderr_tty_p());
}

公共实例方法

exc == obj → true or false click to toggle source

相等性 - 如果obj不是Exception,则返回false。否则,如果excobj具有相同的类、消息和回溯,则返回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);
}
backtrace → array or nil click to toggle source

返回与异常关联的任何回溯。回溯是一个字符串数组,每个字符串包含“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;
}
backtrace_locations → array or nil click to toggle source

返回与异常关联的任何回溯。此方法类似于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;
}
cause → an_exception or nil click to toggle source

返回此异常引发时之前的异常($!)。这对于包装异常并保留原始异常信息很有用。

static VALUE
exc_cause(VALUE exc)
{
    return rb_attr_get(exc, id_cause);
}
detailed_message(highlight: bool, **opt) → string click to toggle source

处理由 message 返回的字符串。

它可能会将异常的类名添加到第一行的末尾。此外,当 highlight 关键字为真时,它会添加 ANSI 转义序列以使消息变为粗体。

如果您覆盖此方法,它必须容忍未知的关键字参数。传递给 full_message 的所有关键字参数都将委托给此方法。

此方法被 did_you_mean 和 error_highlight 覆盖以添加其信息。

用户定义的异常类也可以定义自己的 detailed_message 方法以添加补充信息。当 highlight 为真时,它可以返回包含转义序列的字符串,但使用广泛支持的转义序列。建议限制以下代码

  • 重置 (\e[0m)

  • 粗体 (\e[1m)

  • 下划线 (\e[4m)

  • 除白色和黑色以外的前景色

    • 红色 (\e[31m)

    • 绿色 (\e[32m)

    • 黄色 (\e[33m)

    • 蓝色 (\e[34m)

    • 洋红色 (\e[35m)

    • 青色 (\e[36m)

即使 highlight 为真,也要谨慎使用转义序列。不要使用转义序列来表达基本信息;即使忽略所有转义序列,消息也应该是可读的。

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));
}
exception([string]) → an_exception or exc click to toggle source

如果没有参数,或者参数与接收者相同,则返回接收者。否则,创建一个与接收者同类的新异常对象,但其消息等于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;
}
full_message(highlight: bool, order: [:top or :bottom]) → string click to toggle source

返回异常的格式化字符串。返回的字符串使用与 Ruby 在将未捕获的异常打印到 stderr 时使用的相同格式进行格式化。

如果highlighttrue,则默认错误处理程序会将消息发送到 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;
}
inspect → string click to toggle 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;
}
message → string 点击切换源代码

返回调用 exception.to_s 的结果。通常情况下,这会返回异常的消息或名称。

static VALUE
exc_message(VALUE exc)
{
    return rb_funcallv(exc, idTo_s, 0, 0);
}
set_backtrace(backtrace) → array 点击切换源代码

设置与 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));
}
to_s → string 点击切换源代码

返回异常的消息(如果未设置消息,则返回异常的名称)。

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);
}