класс Exception
Класс Exception и его подклассы используются для взаимодействия между операторами Kernel#raise и rescue в блоках begin ... end.
Объект 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:
-
fatal
Методы публичного класса
Без аргумента или если аргумент совпадает с получателем, возвращается получатель. В противном случае создается новый объект исключения того же класса, что и получатель, но с сообщением, равным string.to_str.
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);
} Создает новый объект Exception, необязательно передавая сообщение.
static VALUE
exc_s_to_tty_p(VALUE self)
{
return rb_stderr_tty_p() ? Qtrue : Qfalse;
} Возвращает 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 || obj == Qundef) {
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 (mesg == Qundef) return Qfalse;
backtrace = rb_check_funcall(obj, id_backtrace, 0, 0);
if (backtrace == Qundef) 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;
if (!rb_equal(exc_backtrace(exc), backtrace))
return Qfalse;
return Qtrue;
} Равенство — Если obj не является Exception, возвращает false. В противном случае возвращает true , если exc и obj имеют один и тот же класс, сообщения и стек вызовов.
# File ext/json/lib/json/add/exception.rb, line 18
def as_json(*)
{
JSON.create_id => self.class.name,
'm' => message,
'b' => backtrace,
}
end Возвращает словарь, который будет преобразован в объект JSON и представлять этот объект.
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;
} Возвращает любой стек вызовов, связанный с исключением. Стек вызовов — это массив строк, каждая из которых содержит либо «имя_файла:номер_строки: в `метод''' либо «имя_файла:номер_строки».
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_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;
} Возвращает любой стек вызовов, связанный с исключением. Этот метод аналогичен Exception#backtrace, но стек вызовов — это массив Thread::Backtrace::Location.
Этот метод не зависит от Exception#set_backtrace().
static VALUE
exc_cause(VALUE exc)
{
return rb_attr_get(exc, id_cause);
} Возвращает предыдущее исключение ($!) на момент возникновения этого исключения. Это полезно для обертывания исключений и сохранения информации об исходном исключении.
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;
} Без аргумента или если аргумент совпадает с получателем, возвращается получатель. В противном случае создается новый объект исключения того же класса, что и получатель, но с сообщением, равным string.to_str.
static VALUE
exc_full_message(int argc, VALUE *argv, VALUE exc)
{
VALUE opt, str, emesg, errat;
enum {kw_highlight, kw_order, kw_max_};
static ID kw[kw_max_];
VALUE args[kw_max_] = {Qnil, Qnil};
rb_scan_args(argc, argv, "0:", &opt);
if (!NIL_P(opt)) {
if (!kw[0]) {
#define INIT_KW(n) kw[kw_##n] = rb_intern_const(#n)
INIT_KW(highlight);
INIT_KW(order);
#undef INIT_KW
}
rb_get_kwargs(opt, kw, 0, kw_max_, args);
switch (args[kw_highlight]) {
default:
rb_raise(rb_eArgError, "expected true or false as "
"highlight: %+"PRIsVALUE, args[kw_highlight]);
case Qundef: args[kw_highlight] = Qnil; break;
case Qtrue: case Qfalse: case Qnil: break;
}
if (args[kw_order] == Qundef) {
args[kw_order] = Qnil;
}
else {
ID id = rb_check_id(&args[kw_order]);
if (id == id_bottom) args[kw_order] = Qtrue;
else if (id == id_top) args[kw_order] = Qfalse;
else {
rb_raise(rb_eArgError, "expected :top or :bottom as "
"order: %+"PRIsVALUE, args[kw_order]);
}
}
}
str = rb_str_new2("");
errat = rb_get_backtrace(exc);
emesg = rb_get_message(exc);
rb_error_write(exc, emesg, errat, str, args[kw_highlight], args[kw_order]);
return str;
} Возвращает отформатированную строку исключения. Возвращаемая строка отформатирована так же, как Ruby форматирует неперехваченные исключения для stderr.
Если highlight true, обработчик ошибок по умолчанию отправит сообщения в терминал.
order должен быть либо :top, либо :bottom, и размещает сообщение об ошибке и самый внутренний стек вызовов вверху или внизу.
Значения параметров по умолчанию зависят от $stderr и его tty? на момент вызова.
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);
rb_str_buf_cat(str, ": ", 2);
rb_str_buf_append(str, exc);
rb_str_buf_cat(str, ">", 1);
return str;
} Возвращает имя класса и сообщение об этом исключении.
static VALUE
exc_message(VALUE exc)
{
return rb_funcallv(exc, idTo_s, 0, 0);
} Возвращает результат вызова exception.to_s. Обычно возвращает сообщение или имя исключения.
static VALUE
exc_set_backtrace(VALUE exc, VALUE bt)
{
return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
} Устанавливает информацию о стеке вызовов, связанную с exc. Стек вызовов должен быть массивом объектов String или одним объектом String в формате, описанном в Exception#backtrace.
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);
} Возвращает сообщение об исключении (или имя исключения, если сообщение не задано).
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.