Exception 클래스

Exception 클래스 (Exception)

Exception 클래스와 그 서브클래스들은 오류나 다른 문제가 발생했음을 나타내고, 처리할 필요가 있을 수 있음을 알려줘요. Kernel#raisebegin ... endrescue 사이에서 정보를 주고받는 데 쓰이죠.

Exception 객체는 특정 정보를 담아요.

  • 타입 — 예외의 클래스. 보통 StandardError, RuntimeError, 또는 이 둘 중 하나의 서브클래스예요.
  • 선택적인 설명 메시지::new, message 메서드 참고.
  • 선택적인 백트레이스 정보backtrace, backtrace_locations, set_backtrace 메서드 참고.
  • 선택적인 cause(원인)cause 메서드 참고.

출처: Ruby 4.0 API

본문

내장 예외 클래스 계층 (Built-In Exception Class Hierarchy)

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 (and its subclasses, representing system errors)
  ThreadError
  TypeError
  ZeroDivisionError
SystemExit
SystemStackError
fatal

::exception (Public Class Method)

exception(message = nil) → self 또는 new_exception — self와 같은 클래스의 예외 객체를 돌려줘요. 비슷한 예외를 다른 메시지로 만들 때 유용하죠.

메시지가 nil이면 self를 그대로 돌려줘요.

x0 = StandardError.new('Boom') # => #<StandardError: Boom>
x1 = x0.exception              # => #<StandardError: Boom>
x0.__id__ == x1.__id__         # => true

문자열로 변환 가능한 객체 메시지를 주면(원래 메시지와 같아도) self와 같은 클래스에 그 메시지를 가진 새 예외 객체를 돌려줘요.

x1 = x0.exception('Boom') # => #<StandardError: Boom>
x0..equal?(x1)            # => false

::json_create (Public Class Method)

json_create(object)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

::new (Public Class Method)

new(message = nil) → exception — 새 예외 객체를 만들어요. 주어진 message는 문자열로 변환 가능한 객체여야 해요. 메시지를 주지 않으면 메시지는 새 인스턴스의 클래스 이름(서브클래스 이름일 수도 있음)이 돼요.

Exception.new         # => #<Exception: Exception>
LoadError.new         # => #<LoadError: LoadError> # Subclass of Exception.
Exception.new('Boom') # => #<Exception: Boom>

::to_tty? (Public Class Method)

to_tty? → true 또는 false — 예외 메시지가 단말(terminal) 장치로 보내질 것이라면 true를 돌려줘요.

#== (Public Instance Method)

self == object → true 또는 false — objectself와 같은 클래스이고 메시지와 백트레이스가 self의 것과 같으면 true를 돌려줘요.

#as_json (Public Instance Method)

as_json(*)Exception#as_jsonException.json_createException 객체를 직렬화·역직렬화할 수 있어요(Marshal 참고). as_jsonself를 직렬화해 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>

#backtrace (Public Instance Method)

backtrace → array 또는 nil — 예외로 이어진 코드 위치 목록(백트레이스)을 문자열 배열로 돌려줘요.

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

이 메서드가 돌려주는 값은 raise(see Kernel#raise) 때나 set_backtrace로 처리하는 중에 조정될 수 있어요. 같은 값을 구조화된 객체로 제공하는 backtrace_locations도 참고하세요. 다만 백트레이스를 수동으로 조정하면 두 값은 서로 일치하지 않을 수 있어요.

#backtrace_locations (Public Instance Method)

backtrace_locations → array 또는 nil — 예외로 이어진 코드 위치 목록을 Thread::Backtrace::Location 인스턴스 배열로 돌려줘요.

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

#cause (Public Instance Method)

cause → exception 또는 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 (Public Instance Method)

detailed_message(highlight: false, **kwargs) → string — 향상된 메시지 문자열을 돌려줘요. 첫 줄에 예외 클래스 이름을 포함하고, 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"

이 메서드는 표준 라이브러리의 몇몇 젬들이 정보를 추가하려고 오버라이드해요 — DidYouMean::Correctable#detailed_message, ErrorHighlight::CoreExt#detailed_message, SyntaxSuggest#detailed_message가 그렇죠. 오버라이드하는 메서드는 전달되는 키워드 인자에 관대해야 해요(:highlight, :did_you_mean, :error_highlight, :syntax_suggest 등). ANSI 코드 향상에도 주의해야 합니다.

#exception (Public Instance Method)

exception(message = nil) → self 또는 new_exception — ::exception 클래스 메서드와 동일하게 동작해요. 메시지가 없거나 receiver와 같으면 self를, 그 외에는 같은 클래스에 새 메시지를 가진 새 예외를 돌려줘요.

#full_message (Public Instance Method)

full_message(highlight: true, order: :top) → string — 향상된 메시지 문자열을 돌려줘요. 예외 클래스 이름을 포함하고, highlighttrue면 굵게 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

#inspect (Public Instance Method)

inspect → string — self의 문자열 표현을 돌려줘요.

x = RuntimeError.new('Boom')
x.inspect # => "#<RuntimeError: Boom>"
x = RuntimeError.new
x.inspect # => "#<RuntimeError: RuntimeError>"

#message (Public Instance Method)

message → string — to_s를 돌려줘요.

#set_backtrace (Public Instance Method)

set_backtrace(value) → value — self의 백트레이스 값을 설정하고 주어진 value를 돌려줘요. valueThread::Backtrace::Location 배열, String 배열, 단일 String, 또는 nil일 수 있어요.

Thread::Backtrace::Location 배열을 쓰는 것이 가장 일관적인 옵션이에요. backtracebacktrace_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"')

원하는 위치 스택을 구할 수 없어 처음부터 만들어야 한다면 문자열 배열이나 단일 문자열을 쓸 수 있어요. 이 경우 backtrace만 영향을 받아요. nil로 호출하면 backtrace는 비워지지만 backtrace_locations는 영향받지 않아요. 그리고 그런 예외를 다시 던지면(raise) 둘 다 다시 던진 지점으로 설정돼요.

#to_json (Public Instance Method)

to_json(*args)self를 나타내는 JSON 문자열을 돌려줘요.

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

출력:

{"json_class":"Exception","m":"Foo","b":null}

#to_s (Public Instance Method)

to_s → string — self의 문자열 표현을 돌려줘요.

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