[루비 사용자 가이드] 예외 처리: rescue

루비/레일스 프로그래밍/루비 사용자 가이드 2009.02.06 10:41

프로그램을 실행하다 보면 예기치 못한 문제에 부딪칠 경우가 있습니다. 읽고자 하는 파일이 존재하지 않거나, 데이터를 저장하려 했는데 디스크가 꽉 차 있을 수도 있습니다. 또, 사용자가 잘못된 입력을 프로그램에 넣을 수도 있습니다.

ruby> file = open("some_file")
ERR: (eval):1:in `open': No such file or directory - some_file

튼튼한 프로그램은 이러한 상황을 민감하게 처리하면서 부드럽게 처리할 수 있어야 할 것입니다. 이런 요구 사항을 만족시키는 것은 고생스럽고 귀찮은 일일 수 있습니다. C프로그래머는 실패할 수 있는 모든 시스템 호출의 반환값을 체크해서 어떤 처리를 할지 결정해야만 합니다.

FILE *file = fopen("some_file", "r");
if (file == NULL) {
  fprintf( stderr, "File doesn't exist.\n" );
  exit(1);
}
bytes_read = fread( buf, 1, bytes_desired, file );
if (bytes_read != bytes_desired ) {
  /* do more error handling here ... */
}
...

이러한 작업은 성가시기 때문에, 프로그래머들은 점점 이런 처리를 무시하거나 부주의하게 되기 쉽습니다. 그 결과 프로그램은 예외상황을 제대로 처리하지 못하게 됩니다. 한편, 이런 예외에 대한 처리를 철저히 제대로 하게 되면 예외사항을 처리하는 코드가 너무 많이 여기저기 있어서, 프로그램을 읽기가 어려워집니다.

많은 현대 언어와 마찬가지로, 루비에서는 코드 덩어리에 대한 예외사항을 프로그램 본래 흐름과 별개의 부분으로 구성된 코드로 처리할 수 있습니다. 따라서 오류를 다루는 것이 효과적으로 이루어지면서도, 프로그램을 작성하는 사람이나 나중에 작성된 코드를 읽는 사람에게 과도한 짐을 지우지 않게 됩니다. begin으로 시작하는 코드 덩어리는 예외사항이 발생할 때 까지 실행되며, 예외가 발생하면 컨트롤이 에러 처리 코드쪽으로 넘어가게 됩니다. 이 에러 처리 코드는 rescue로 표시됩니다. 만약 아무 예외사항도 발생하지 않는다면 rescue 코드는 사용(실행)되지 않습니다. 다음 메소드는 텍스트파일에서 첫번째 줄을 읽어서 반환하며, 예외가 발생하면 nil을 반환합니다.

def first_line( filename )
  begin
    file = open("some_file")
    info = file.gets
    file.close
    info  # Last thing evaluated is the return value
  rescue
    nil   # Can't read the file? then don't return a string
  end
end

때로 문제가 발생하면 창의적으로 작업을 진행해야 할 경우가 있습니다. 아래 예에서는 대상 파일이 없는 경우에 표준 입력을 대신 사용합니다.

begin
  file = open("some_file")
rescue
  file = STDIN
end

begin
  # ... process the input ...
rescue
  # ... and deal with any other exceptions here.
end

retryrescue 코드 내부에서 begin 코드를 다시 시작하고 싶을 경우 사용합니다. retry를 사용해서 위 코드는 다음과 같이 더 단순하게 표현할 수 있습니다.

fname = "some_file"
begin
  file = open(fname)
  # ... process the input ...
rescue
  fname = "STDIN"
  retry
end

하지만, 위 코드에는 한가지 단점이 있습니다. 잘못해서 fname에 존재하지 않는 이름을 지정한다면 위 코드는 무한루프를 돌게 됩니다. 예외 처리시 retry를 사용할 때는 이런 함정에 빠지지 않도록 주의를 기울여야 합니다.

모든 루비 라이브러리는 오류가 발생시 예외를 발생시킵니다. 여러분도 자신의 코드에서 예외를 명시적으로 발생시킬 수 있습니다. 예외를 발생시키기 위해서는 raise를 사용합니다.  raise는 인자로 예외를 설명하는 스트링을 하나 받도록 되어 있습니다. 이 인자는 생략할 수 있긴 하지만, 생략해서는 안될 것입니다. 특수 전역 변수인 $!를 사용하면 맨 마지막에 raise에 전달된 인자값을 알 수 있습니다.

ruby> raise "test error"
   test error
ruby> begin
    |   raise "test2"
    | rescue
    |   puts "An error occurred: #{$!}"
    | end
An error occurred: test2
   nil
신고
Trackback 1 : Comment 0

티스토리 툴바