Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Exception# 원인이 있는 Ruby의 중첩 오류

Ruby에서 다른 종류의 예외를 구제하고 예외를 발생시키고 다시 발생시키는 것은 일반적인 패턴입니다. ActionView는 이것에 대한 아주 분명한 예입니다. TracePoint에 대한 이전 블로그 게시물에서 언급했듯이 ActionView는 템플릿에서 발생하는 모든 예외를 삼켜 ActionView::TemplateError로 다시 발생시킵니다. .

때로는 이것이 충분하지 않습니다. 문제를 해결하는 데 도움이 되는 일부 데이터가 포함되어 있기 때문에 원래 예외가 정말 필요합니다. 다행히 Ruby 2.1부터는 Exception#cause 메소드를 사용하여 이를 수행할 수 있습니다.

실제로 어떻게 작동하는지 봅시다. 여기에서 NoMethodError를 발생시킵니다. , 즉시 삼키고 RuntimeError를 발생시킵니다. . 그런 다음 RuntimeError를 포착합니다. 원본 NoMethodError를 가져오려면 #cause를 사용하세요. .

def fail_and_reraise
  raise NoMethodError
rescue
  raise RuntimeError
end

begin
  fail_and_reraise
rescue => e
  puts "#{ e } caused by #{ e.cause }"
end

중첩된 역추적 및 사용자 정의 속성

#Cause 메서드는 실제로 원래 예외 객체를 반환합니다. 즉, 원래 예외의 일부였던 모든 메타데이터에 액세스할 수 있습니다. 원본 역추적도 얻을 수 있습니다.

class EatingError < StandardError
  attr_reader :food
  def initialize(food)
    @food = food
  end
end

def fail_and_reraise
  raise EatingError.new("soup")
rescue
  raise RuntimeError
end

begin
  fail_and_reraise
rescue => e
  puts "#{ e } caused by #{ e.cause } while eating #{ e.cause.food }"
  puts e.cause.backtrace.first
end


무한대 너머로!

위의 예는 한 수준 깊이에 불과하지만 Ruby의 중첩 예외는 여러 수준을 가질 수 있습니다. 4단계 중 3단계 이상으로 진행해야 하는 경우가 발생하면 놀랄 것입니다.

...하지만 그냥 재미로 100레벨의 깊은 중첩 예외를 만들려고 생각했습니다. 이것은 어리석은 작은 코드 조각이며, 프로덕션 환경에서 이러한 코드를 본 적이 없기를 바랍니다.

def recursively_raise(c=0)
  raise "Level #{ c }"
rescue => e
  if c < 100
    recursively_raise(c + 1)
  else
    recursively_print(e)
  end
end

def recursively_print(e)
  if e
    puts e
    recursively_print(e.cause)
  end
end

recursively_raise()

# ... Prints the following:
# Level 100
# Level 99
# Level 98
# etc.