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

Ruby 예외로 객체를 발생시키는 방법

Ruby의 raise 구문은 발생시키려는 오류의 종류를 지정하기 위한 몇 가지 옵션을 제공합니다. 아래 코드에서는 RuntimeError를 발생시키는 세 가지 방법을 보여주었습니다.

raise "hello"
raise RuntimeError, "hello"
raise RuntimeError.new("hello")

# ...all of the above result in "RuntimeError: hello"

좋긴 한데 예외가 아닌 다른 것을 발생시키고 싶을 때 어떻게 됩니까? 숫자를 올리고 싶다면? 글쎄, Ruby는 나를 허용하지 않을 것입니다. 다음과 같은 오류 메시지가 나타납니다.

raise 1
# TypeError: exception class/object expected

이제 이 메시지는 raise가 예외 클래스/객체를 매개변수로 기대한다고 믿게 만들 수 있습니다. 하지만 그건 틀렸어요!

exception 소개 방법

raise foo를 하면 raise 메소드는 foo가 예외 객체가 될 것으로 기대하지 않습니다. foo.exception을 호출할 때마다 예외 객체를 얻을 것으로 예상합니다. .

기억해야 할 점은 예외를 반환하는 exception이라는 메서드가 있는 한 ANYTHING을 전달하여 발생시킬 수 있다는 것입니다.

따라서 원하는 경우 루비의 숫자 클래스를 원숭이 패치하여 숫자를 올릴 수 있습니다. 다음과 같이 보일 수 있습니다.

class Fixnum
  def exception
    RuntimeError.new("I'm number: #{ self }")
  end
end

raise 42
# ...results in raise_number.rb:7:in `<main>': I'm number: 42 (RuntimeError)

이것은 깔끔한 파티 트릭이지만 실생활에서 유용할 수 있을까요? 이 기술의 주요 실제 응용 프로그램은 예외를 발생시키기로 결정한 논리에서 예외를 빌드하는 데 필요한 논리를 분리하는 것입니다. 이것은 확실히 약간의 엣지 케이스입니다. 하지만 어떻게 생겼는지 봅시다.

실용적인 예

어떤 종류의 IO에서 한 줄의 데이터를 읽고 싶다고 가정해 보겠습니다. 네트워크 IO일 수도 있고 파일일 수도 있습니다. 그것은 정말 중요하지 않습니다. 데이터를 읽고 유효한지 확인하고 싶습니다.

내가 읽은 데이터가 유효하지 않으면 예외를 발생시키고 싶습니다. 그러나 예외는 입력에 맞게 조정되어야 합니다. 네트워크 연결에는 로컬 파일과 다른 디버그 정보가 있어야 합니다. 각 종류의 입력 클래스에 대해 사용자 지정 예외 메서드를 제공하여 이를 수행할 수 있습니다. 다음은 그것이 어떻게 생겼는지 보여주는 유사 루비입니다.

# These three classes represent different kinds of IO with different exceptions.
class NetworkConnection
  ...
  def exception
    NetworkConnectionError.new(url: url, ...)
  end
end

class LocalFile
  ...
  def exception
    FileError.new(path: path, ...)
  end
end

class UnixPipe
  ...
  def exception
    PipeError.new(...)
  end
end

def read_all(*items)
  items.each do |item|
    if item.readline != "foo"
      # We raise the item, which causes the appropriate exception class to be used. 
      raise item
    end
  end
end

read_all(NetworkConnection.new(url: "example.com"), LocalFile.new("/something"), UnixPipe.new)