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

구조 블록 외부에서 Ruby 예외 작업

코드가 해당 예외의 수명 주기를 제어하지 않는 경우에도 가장 최근의 예외를 가져올 수 있는 것이 종종 유용합니다. 애플리케이션에 기본 충돌 감지를 추가하고 싶다고 상상해 보십시오. 포착되지 않은 예외의 결과로 발생하는 충돌에 대한 추가 정보를 기록하고 싶습니다.

첫 번째 단계는 애플리케이션이 종료될 때마다 실행되는 핸들러를 추가하는 것입니다. Ruby 커널의 at_exit 메소드를 통해 이 작업을 수행하는 것은 매우 쉽습니다.

at_exit
  puts "the app exited"
end

그러나 예외의 결과로 종료 콜백이 호출되었는지 어떻게 알 수 있습니까? 음, Ruby는 암호로 명명된 $!를 제공합니다. 전역 변수. 현재 호출 스택의 어딘가에서 발생한 가장 최근에 발생한 예외를 포함합니다.

$!를 사용하는 것은 간단합니다. 예외로 인해 프로그램이 종료되고 있는지 감지합니다. 다음과 같이 보입니다.

at_exit do
 save_error_to_log($!) if $!         
end

$!의 한계

유감스럽게도 $! 메서드는 현재 호출 스택의 어딘가에서 예외가 발생한 경우에만 작동합니다. 예외를 구한 경우 $!에 액세스하십시오. 구제 조항을 벗어나면 nil이 됩니다.

begin        
 raise "x"       
rescue       
 puts $! # => RuntimeError           
end

puts $! # => nil         

즉, $! IRB와 같은 쉘 내부에서는 거의 쓸모가 없습니다. 종종 IRB에서 메서드를 실행하고 예외를 얻습니다. 때때로 나는 그 예외 객체를 잡고 싶습니다. 하지만 $! 작동하지 않습니다.

irb(main):001:0> 1/0
ZeroDivisionError: divided by 0
    from (irb):1:in `/'
irb(main):002:0> $!
=> nil

$! PRY와 함께

PRY는 $!의 한계를 극복합니다. 자체 로컬 변수 _ex_를 추가하여 . 이 변수는 가장 최근에 포착되지 않은 예외를 포함합니다.

[1] pry(main)> raise "hi"        
RuntimeError: hi         
from (pry):1:in `__pry__'        
[2] pry(main)> _ex_      
=> #<RuntimeError: hi>

PRY가 이것을 할 수 있는 이유는 PRY 또는 IRB 내부에 실제로 포착되지 않은 예외가 없기 때문입니다. 쉘 자체가 예외를 포착하여 멋진 형식의 오류 메시지로 표시합니다.

아래 PRY 소스의 관련 비트를 복사했습니다. 명령을 평가하는 코드가 begin/rescue/end 블록 내부에 래핑된 것을 볼 수 있습니다. 복구 가능한 예외가 발생하면 PRY가 예외를 self.last_exception에 저장하고 나중에 _ex_에 할당됩니다. .

# Excerpted from the PRY source at https://github.com/pry/pry/blob/623306966bfa86890ac182bc8375ec9699abe90d/lib/pry/pry_instance.rb#L273

begin
  if !process_command_safely(line)
    @eval_string << "#{line.chomp}\n" if !line.empty? || !@eval_string.empty?
  end
rescue RescuableException => e
  self.last_exception = e
  result = e

  Pry.critical_section do
    show_result(result)
  end
  return
end

영어 필요

$!와 같은 변수 이름을 찾을 수 있습니다. 눈이 좀 힘든? 다행히 Ruby에는 로봇 낱말처럼 보이는 많은 전역 변수의 영어 버전을 제공하는 "영어"라는 모듈이 포함되어 있습니다.

$!의 동의어 $ERROR_INFO입니다. . 일반적으로 $!를 사용하는 모든 곳에서 사용할 수 있습니다. .

require "English"

begin        
 raise "x"       
rescue       
 puts $ERROR_INFO # => RuntimeError          
end

그리고 대부분의 다른 영어에 해당하는 내용은 이 블로그 게시물의 주제와 아무 관련이 없지만 참고용으로 포함하겠습니다. 영어 변수는 왼쪽에 있습니다. 원본은 오른쪽에 있습니다.

$ERROR_INFO $!
$ERROR_POSITION $@
$FS $;
$FIELD_SEPARATOR $;
$OFS $,
$OUTPUT_FIELD_SEPARATOR $,
$RS $/
$INPUT_RECORD_SEPARATOR $/
$ORS $\
$OUTPUT_RECORD_SEPARATOR $\
$INPUT_LINE_NUMBER $.
$NR $.
$LAST_READ_LINE $_
$DEFAULT_OUTPUT $>
$DEFAULT_INPUT $<
$PID $$
$PROCESS_ID $$
$CHILD_STATUS $?
$LAST_MATCH_INFO $~
$IGNORECASE $=
$ARGV $*
$MATCH $&
$PREMATCH $`
$POSTMATCH $'
$LAST_PAREN_MATCH $+