Szukaj…


Uwagi

Wyjątkiem jest obiekt reprezentujący wystąpienie wyjątkowego warunku. Innymi słowy, oznacza to, że coś poszło nie tak.

W Rubim wyjątki są często nazywane błędami . Wynika to z faktu, że podstawowa klasa Exception istnieje jako element obiektu wyjątku najwyższego poziomu, ale wyjątki wykonania zdefiniowane przez użytkownika to na ogół błąd StandardError lub elementy potomne.

Zgłaszanie wyjątku

Aby zgłosić wyjątek, użyj Kernel#raise przekazując klasę wyjątku i / lub komunikat:

raise StandardError # raises a StandardError.new
raise StandardError, "An error" # raises a StandardError.new("An error")

Możesz także po prostu przekazać komunikat o błędzie. W takim przypadku komunikat jest pakowany w RuntimeError :

raise "An error" # raises a RuntimeError.new("An error")

Oto przykład:

def hello(subject)
  raise ArgumentError, "`subject` is missing" if subject.to_s.empty?
  puts "Hello #{subject}"
end

hello # => ArgumentError: `subject` is missing
hello("Simone") # => "Hello Simone"

Tworzenie niestandardowego typu wyjątku

Wyjątkiem niestandardowym jest każda klasa, która rozszerza Exception lub podklasę Exception .

Ogólnie rzecz biorąc, zawsze powinieneś rozszerzać StandardError lub potomek. Rodzina Exception zwykle dotyczy błędów maszyny wirtualnej lub błędów systemu, ich uratowanie może zapobiec wymuszonemu zakłóceniu działania zgodnie z oczekiwaniami.

# Defines a new custom exception called FileNotFound
class FileNotFound < StandardError
end

def read_file(path)
  File.exist?(path) || raise(FileNotFound, "File #{path} not found")
  File.read(path)
end

read_file("missing.txt")  #=> raises FileNotFound.new("File `missing.txt` not found")
read_file("valid.txt")    #=> reads and returns the content of the file

Często nazywa się wyjątki, dodając na końcu sufiks Error :

  • ConnectionError
  • DontPanicError

Jednak gdy błąd jest oczywisty, nie trzeba dodawać sufiksu Error ponieważ byłby nadmiarowy:

  • FileNotFound vs FileNotFoundError
  • DatabaseExploded vs DatabaseExplodedError

Obsługa wyjątku

Użyj bloku begin/rescue , aby złapać (uratować) wyjątek i obsłużyć go:

begin
  # an execution that may fail
rescue
  # something to execute in case of failure
end

Klauzula rescue jest analogiczna do bloku catch w języku nawiasów klamrowych, takim jak C # lub Java.

Nagły rescue taki jak ten ratuje StandardError .

Uwaga: Uważaj, aby nie wychwycić Exception zamiast domyślnego StandardError . Exception klasa obejmuje SystemExit i NoMemoryError i innych poważnych wyjątki, które zwykle nie chcą złapać. Zamiast tego zawsze rozważ złapanie StandardError (domyślnie).

Możesz także określić klasę wyjątków, które należy uratować:

begin
  # an excecution that may fail
rescue CustomError
  # something to execute in case of CustomError
  # or descendant
end

Ta klauzula ratunkowa nie przechwytuje żadnego wyjątku, który nie jest CustomError .

Możesz także zapisać wyjątek w określonej zmiennej:

begin
  # an excecution that may fail
rescue CustomError => error
  # error contains the exception
  puts error.message # provide human-readable details about what went wrong.
  puts error.backtrace.inspect # return an array of strings that represent the call stack
end

Jeśli nie udało Ci się obsłużyć wyjątku, możesz go podnieść w dowolnym momencie w bloku ratunkowym.

begin
   #here goes your code
rescue => e
    #failed to handle 
    raise e
end

Jeśli chcesz, aby ponowić próbę begin blok, call retry :

begin
   #here goes your code
rescue StandardError => e
   #for some reason you want to retry you code
   retry
end

Możesz utknąć w pętli, jeśli złapiesz wyjątek przy każdej próbie. Aby tego uniknąć, ogranicz retry_count do określonej liczby prób.

retry_count = 0
begin
      # an excecution that may fail
rescue
    if retry_count < 5
        retry_count = retry_count + 1
        retry
    else
        #retry limit exceeds, do something else
    end

Możesz także podać blok else lub blok ensure . else blok zostanie wykonany, gdy begin ukończone, blokowe bez wyjątku rzucony. Blok ensure zawsze będzie wykonywany. Blok ensure jest analogiczny do bloku finally w języku nawiasów klamrowych, takim jak C # lub Java.

begin
  # an execution that may fail
rescue
  # something to execute in case of failure
else
  # something to execute in case of success
ensure
  # something to always execute
end

Jeśli jesteś w bloku def , module lub class , nie musisz używać instrukcji start.

def foo
    ...
rescue
    ...
end

Obsługa wielu wyjątków

W tej samej deklaracji rescue można obsłużyć wiele błędów:

begin
  # an execution that may fail
rescue FirstError, SecondError => e
  # do something if a FirstError or SecondError occurs
end

Możesz także dodać wiele deklaracji rescue :

begin
  # an execution that may fail
rescue FirstError => e
  # do something if a FirstError occurs
rescue SecondError => e
  # do something if a SecondError occurs
rescue => e
  # do something if a StandardError occurs
end

Kolejność bloków rescue jest istotna: pierwszy mecz jest wykonywany. Dlatego jeśli ustawisz StandardError jako pierwszy warunek, a wszystkie wyjątki odziedziczą po StandardError , wówczas pozostałe instrukcje rescue nigdy nie zostaną wykonane.

begin
  # an execution that may fail
rescue => e
  # this will swallow all the errors
rescue FirstError => e
  # do something if a FirstError occurs
rescue SecondError => e
  # do something if a SecondError occurs
end

Niektóre bloki mają domyślną obsługę wyjątków, takich jak def , class i module . Te bloki pozwalają pominąć instrukcję begin .

def foo
    ...
rescue CustomError
    ...
ensure
    ...
end

Dodawanie informacji do (niestandardowych) wyjątków

Pomocne może być dołączenie dodatkowych informacji z wyjątkiem, np. Do celów logowania lub umożliwienie obsługi warunkowej w przypadku wychwycenia wyjątku:

class CustomError < StandardError
  attr_reader :safe_to_retry

  def initialize(safe_to_retry = false, message = 'Something went wrong')
    @safe_to_retry = safe_to_retry
    super(message)
  end
end

Zgłaszanie wyjątku:

raise CustomError.new(true)

Złapanie wyjątku i uzyskanie dostępu do dodatkowych informacji:

begin
  # do stuff
rescue CustomError => e
  retry if e.safe_to_retry
end


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow