DRY 방식으로 루비의 구조 절에 여러 오류 클래스 전달


100

루비에서 여러 유형의 예외를 구해야하는 코드가 있습니다.

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue FooException, BarException
  puts "rescued!"
end

내가하고 싶은 것은 어떻게 든 어딘가에 구출하려는 예외 유형 목록을 저장하고 해당 유형을 rescue 절에 전달하는 것입니다.

EXCEPTIONS = [FooException, BarException]

그리고:

rescue EXCEPTIONS

이것이 가능 eval할까요 , 그리고 실제로 해킹 호출없이 가능 합니까? 나는 TypeError: class or module required for rescue clause위의 시도를 할 때 내가 보고 있다는 것을 감안할 때 희망적이지 않습니다 .


2
구조 * EXCEPTIONS는 어떻습니까?
Roman

답변:


197

splat 연산자와 함께 배열을 사용할 수 있습니다 *.

EXCEPTIONS = [FooException, BarException]

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue *EXCEPTIONS
  puts "rescued!"
end

위와 같이 배열에 상수를 사용하려는 경우 (와 함께 EXCEPTIONS) 정의 내에서 정의 할 수 없으며 다른 클래스에서 정의하는 경우에도 해당 네임 스페이스로 참조해야합니다. 실제로 상수 일 필요는 없습니다.


표시 연산자

표시 연산자 *는 해당 위치에서 배열을 "압축 해제"하여

rescue *EXCEPTIONS

같은 의미

rescue FooException, BarException

배열 리터럴 내에서 다음과 같이 사용할 수도 있습니다.

[BazException, *EXCEPTIONS, BangExcepion]

이것은

[BazException, FooException, BarException, BangExcepion]

또는 인수 위치

method(BazException, *EXCEPTIONS, BangExcepion)

method(BazException, FooException, BarException, BangExcepion)

[] 공허로 확장 :

[a, *[], b] # => [a, b]

루비 1.8과 루비 1.9의 차이점 중 하나는 nil.

[a, *nil, b] # => [a, b]       (ruby 1.9)
[a, *nil, b] # => [a, nil, b]  (ruby 1.8)

다음과 같은 경우에 적용될 것이므로 to_a정의 된 객체에주의하십시오 to_a.

[a, *{k: :v}, b] # => [a, [:k, :v], b]

다른 유형의 개체와 함께 자신을 반환합니다.

[1, *2, 3] # => [1, 2, 3]

2
이것은 루비 1.8.7에서도 작동하는 것으로 보입니다. EXCEPTIONS이 경우 앞에 '*'문자를 사용하는 용어는 무엇입니까 ? 조금 더 배우고 싶습니다.
apb 2011

2
@Andy 그것은 표시라고합니다. 일반적으로 배열을 쉼표로 구분 된 개체로 분해하는 효과가 있습니다. 메서드 정의의 위치를받는 인수에 사용하면 다른 방식으로 인수를 배열에 함께 넣습니다. 다양한 경우에 매우 유용합니다. 1.8.7에서 작동한다는 것을 알아두면 좋습니다. 그에 따라 내 대답을 편집했습니다.
sawa 2011

20
예외 인스턴스에 액세스하려면 다음 구문을 사용 rescue InvalidRequestError, CardError => e하십시오 . ( mikeferrier.com/2012/05/19/… 참조 )
Peter Ehrlich

이 구문은 잘 작동합니다 : rescue *EXCEPTIONS => e, 여기서는 EXCEPTIONS예외 클래스 이름의 배열입니다.
aks

3

하지만 대답 @sawa에 의해 주어진 기술적 맞다, 나는 그것이 루비의 예외 처리 메커니즘을 오용 생각합니다.

Peter Ehrlich 의 의견이 암시 하듯이 ( Mike Ferrier 의 오래된 블로그 게시물 을 가리킴 ) Ruby는 이미 DRY 예외 처리기 메커니즘을 갖추고 있습니다.

puts 'starting up'
begin
  case rand(3)
  when 0
    ([] + '')
  when 1
    (foo)
  when 2
    (3 / 0)
  end
rescue TypeError, NameError => e
  puts "oops: #{e.message}"
rescue Exception => e
  puts "ouch, #{e}"
end
puts 'done'

이 기술을 사용하면 일반적으로 중요한 정보가 들어있는 예외 개체에 액세스 할 수 있습니다.


1

방금이 문제가 발생하여 대체 솔루션을 찾았습니다. 경우에 당신 FooExceptionBarException모든 사용자 정의 예외 클래스가 될 것 그리고 그들은 모든 주제별로 관련이 특히 경우, 당신은 그들이 모든 같은 부모 클래스에서 상속은 부모 클래스를 구출 것입니다 귀하의 상속 계층 구조는 구조 할 수 있습니다.

예를 들어 FileNamesMissingError, 세 가지 예외가있었습니다 : InputFileMissingError,, 그리고 OutputDirectoryError한 문장으로 구출하고 싶었습니다. 라는 또 다른 예외 클래스를 만든 FileLoadError다음 위의 세 가지 예외를 설정하여 상속했습니다. 그때 나는 구출 만했다 FileLoadError.

이렇게 :

class FileLoadError < StandardError
end

class FileNamesMissingError < FileLoadError
end

class InputFileMissingError < FileLoadError
end

class OutputDirectoryError < FileLoadError
end

[FileNamesMissingError,
 InputFileMissingError,
 OutputDirectoryError].each do |error| 
   begin  
     raise error
   rescue FileLoadError => e
     puts "Rescuing #{e.class}."
   end 
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.