類別 Exception

類別 Exception 及其子類別用於在 Kernel#raisebegin ... end 區塊中的 rescue 陳述式之間進行溝通。

一個 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([字串]) → an_exception 或 exc

如果沒有參數,或參數與接收者相同,則傳回接收者。否則,建立一個與接收者同類別的新例外物件,但訊息等於 字串.to_str

new(msg = nil) → exception 按一下以切換來源
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 或 false 按一下以切換來源

如果例外訊息將傳送到 tty,則傳回 true

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

公開實例方法

exc == obj → true 或 false 按一下以切換來源

相等性—如果 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 → 陣列或 nil 按一下以切換來源

傳回與例外狀況關聯的任何追蹤記錄。追蹤記錄是一個字串陣列,每個字串都包含「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 → 陣列或 nil 按一下以切換來源

傳回與例外狀況關聯的任何追蹤記錄。此方法類似於 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 → 例外狀況或 nil 按一下以切換來源

傳回此例外狀況引發時先前的例外狀況 ($!)。這對於包裝例外狀況和保留原始例外狀況資訊很有用。

static VALUE
exc_cause(VALUE exc)
{
    return rb_attr_get(exc, id_cause);
}
detailed_message(highlight: bool, **opt) → 字串 按一下以切換來源

處理 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));
}
exception([字串]) → 例外狀況或 exc 按一下以切換來源

如果沒有參數,或參數與接收者相同,則傳回接收者。否則,建立一個與接收者同類別的新例外物件,但訊息等於 字串.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 或 :bottom]) → string 按一下以切換來源

傳回格式化的 exception 字串。傳回的字串會使用 Ruby 在將未捕捉的例外狀況列印到 stderr 時使用的相同格式進行格式化。

如果 highlighttrue,預設錯誤處理常式會將訊息傳送至 tty。

order 必須為 :top:bottom 之一,並將錯誤訊息和最內層的 backtrace 放在頂端或底部。

這些選項的預設值取決於 $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 按一下以切換來源

傳回此例外狀況的類別名稱和訊息。

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 資訊。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);
}