Spec-Zone.ru › Ruby 4.0

class Exception

Родительский класс:
Object

Класс Exception и его подклассы используются для обозначения произошедшей ошибки или другой проблемы, которую, возможно, необходимо обработать. См. Исключения.

Объект Exception содержит определённую информацию:

  • Тип (класс исключения), обычно StandardError, RuntimeError или подкласс одного из них; см. Иерархия встроенных классов исключений.

  • Необязательное описательное сообщение; см. методы ::new, message.

  • Необязательная информация о трассировке стека; см. методы backtrace, backtrace_locations, set_backtrace.

  • Необязательная причина; см. метод cause.

Иерархия встроенных классов исключений

Иерархия встроенных подклассов класса Exception:

  • NoMemoryError

  • ScriptError

    • LoadError

    • NotImplementedError

    • SyntaxError

  • SecurityError

  • SignalException

    • Interrupt

  • StandardError

    • ArgumentError

      • UncaughtThrowError

    • EncodingError

    • FiberError

    • IOError

      • EOFError

    • IndexError

      • KeyError

      • StopIteration

        • ClosedQueueError

    • LocalJumpError

    • NameError

      • NoMethodError

    • RangeError

      • FloatDomainError

    • RegexpError

    • RuntimeError

      • FrozenError

    • SystemCallError

      • Errno (и его подклассы, представляющие системные ошибки)

    • ThreadError

    • TypeError

    • ZeroDivisionError

  • SystemExit

  • SystemStackError

  • fatal

Открытые методы класса

exception(message = nil) → self or new_exception

Возвращает объект исключения того же класса, что и 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
json_create (object) Показать исходный код
# 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.

new(message = nil) → 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);
}

Возвращает новый объект исключения.

Переданное message должно быть объектом, преобразуемым в строку; см. метод message; если аргумент не задан, сообщением будет имя класса нового экземпляра (которое может быть именем подкласса):

Примеры:

Exception.new         # => #<Exception: Exception>
LoadError.new         # => #<LoadError: LoadError> # Subclass of Exception.
Exception.new('Boom') # => #<Exception: Boom>
to_tty? → true or false Показать исходный код
static VALUE
exc_s_to_tty_p(VALUE self)
{
    return RBOOL(rb_stderr_tty_p());
}

Возвращает true, если сообщения об исключениях будут отправляться на терминальное устройство.

Открытые методы экземпляра

self == object → true or false Показать исходный код
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);
}

Возвращает значение, указывающее, принадлежит ли object тому же классу, что и self, а его message и backtrace совпадают с соответствующими значениями self.

as_json (*) Показать исходный код
# 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:

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>
backtrace → array or 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;
}

Возвращает трассировку стека (список мест в коде, приведших к исключению) в виде массива строк.

Пример (предполагается, что код сохранён в файле с именем 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, который возвращает то же значение в виде структурированных объектов. (Обратите внимание: эти два значения могут не совпадать, если трассировка стека была изменена вручную.)

См. Трассировки стека.

backtrace_locations → array or 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;
}

Возвращает трассировку стека (список мест в коде, приведших к исключению) в виде массива экземпляров 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, который возвращает то же значение в виде массива строк. (Обратите внимание: эти два значения могут не совпадать, если трассировка стека была изменена вручную.)

См. Трассировки стека.

cause → exception or nil Показать исходный код
static VALUE
exc_cause(VALUE exc)
{
    return rb_attr_get(exc, id_cause);
}

Возвращает предыдущее значение глобальной переменной $!, которое может быть nil (см. Глобальные переменные):

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.
detailed_message(highlight: false, **kwargs) → string Показать исходный код
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 переопределяют этот метод, чтобы добавить информацию:

  • DidYouMean::Correctable#detailed_message.

  • ErrorHighlight::CoreExt#detailed_message.

  • SyntaxSuggest#detailed_message.

Переопределяющий метод должен допускать передачу ключевых аргументов, среди которых могут быть (но не обязательно ограничиваться ими):

  • :highlight.

  • :did_you_mean.

  • :error_highlight.

  • :syntax_suggest.

При переопределении метода следует также соблюдать осторожность с улучшениями оформления посредством ANSI-кодов; см. Сообщения.

exception(message = nil) → self or new_exception Показать исходный код
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
full_message(highlight: true, order: :top) → string Показать исходный код
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-кодов; см. Сообщения.

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

Возвращает строковое представление self:

x = RuntimeError.new('Boom')
x.inspect # => "#<RuntimeError: Boom>"
x = RuntimeError.new
x.inspect # => "#<RuntimeError: RuntimeError>"
message → string Показать исходный код
static VALUE
exc_message(VALUE exc)
{
    return rb_funcallv(exc, idTo_s, 0, 0);
}

Возвращает to_s.

См. Сообщения.

set_backtrace(value) → value Показать исходный код
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. По возможности следует отдавать предпочтение этому варианту. Подходящий массив мест можно получить с помощью 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"')

Вызов set_backtrace с аргументом nil очищает 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

См. Трассировки стека.

to_json (*args) Показать исходный код
# File ext/json/lib/json/add/exception.rb, line 46
def to_json(*args)
  as_json.to_json(*args)
end

Возвращает строку JSON, представляющую self:

require 'json/add/exception'
puts Exception.new('Foo').to_json

Вывод:

{"json_class":"Exception","m":"Foo","b":null}
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);
}

Возвращает строковое представление self:

x = RuntimeError.new('Boom')
x.to_s # => "Boom"
x = RuntimeError.new
x.to_s # => "RuntimeError"

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API