Ricerca…


Osservazioni

Un'eccezione è un oggetto che rappresenta il verificarsi di una condizione eccezionale. In altre parole, indica che qualcosa è andato storto.

In Ruby, le eccezioni sono spesso definite errori . Questo perché la classe Exception base esiste come elemento di un oggetto di eccezione di livello superiore, ma le eccezioni di esecuzione definite dall'utente sono generalmente StandardError o discendenti.

Alzare un'eccezione

Per generare un'eccezione usa Kernel#raise passando la classe di eccezione e / o il messaggio:

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

Puoi anche semplicemente passare un messaggio di errore. In questo caso, il messaggio è avvolto in un RuntimeError :

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

Ecco un esempio:

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"

Creazione di un tipo di eccezione personalizzato

Un'eccezione personalizzata è qualsiasi classe che estende Exception o una sottoclasse di Exception .

In generale, si dovrebbe sempre estendere l'errore StandardError o un discendente. La famiglia Exception è in genere per errori di macchina virtuale o di sistema, il loro salvataggio può impedire un'interruzione forzata di funzionare come previsto.

# 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

È comune denominare le eccezioni aggiungendo il suffisso Error alla fine:

  • ConnectionError
  • DontPanicError

Tuttavia, quando l'errore è autoesplicativo, non è necessario aggiungere il suffisso Error perché sarebbe ridondante:

  • FileNotFound vs FileNotFoundError
  • DatabaseExploded vs DatabaseExplodedError

Gestire un'eccezione

Usa il blocco begin/rescue per rilevare (salvare) un'eccezione e gestirla:

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

Una clausola di rescue è analoga a un blocco catch in un linguaggio di parentesi graffa come C # o Java.

Un semplice rescue come questo salva StandardError .

Nota: fare attenzione ad evitare l'intercettazione di Exception anziché l'errore StandardError predefinito. La classe Exception include SystemExit e NoMemoryError e altre eccezioni serie che di solito non si desidera NoMemoryError . Considerare sempre la cattura di StandardError (il valore predefinito).

È inoltre possibile specificare la classe di eccezioni da salvare:

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

Questa clausola di salvataggio non catturerà alcuna eccezione che non sia un'eccezione CustomError .

È inoltre possibile memorizzare l'eccezione in una variabile specifica:

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

Se non si è riusciti a gestire un'eccezione, è possibile aumentarla in qualsiasi momento in un blocco di salvataggio.

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

Se si desidera ripetere la begin blocco, chiamare retry :

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

Puoi essere bloccato in un ciclo se rilevi un'eccezione in ogni nuovo tentativo. Per evitare ciò, limita il tuo retry_count a un certo numero di tentativi.

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

Puoi anche fornire un blocco else o un blocco di ensure . Un else blocco sarà eseguito quando il begin blocco completa senza eccezione generata. Un blocco di ensure verrà sempre eseguito. Un ensure blocco è analogo ad un finally blocco in una lingua parentesi graffa come C # o 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

Se si è all'interno di un def , module o blocco di class , non è necessario utilizzare l'istruzione begin.

def foo
    ...
rescue
    ...
end

Gestire più eccezioni

È possibile gestire più errori nella stessa dichiarazione di rescue :

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

Puoi anche aggiungere più dichiarazioni di 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

L'ordine dei blocchi di rescue è rilevante: la prima partita è quella eseguita. Pertanto, se si imposta StandardError come prima condizione e tutte le eccezioni ereditate da StandardError , le altre istruzioni di rescue non verranno mai eseguite.

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

Alcuni blocchi hanno una gestione delle eccezioni implicita come def , class e module . Questi blocchi ti consentono di saltare l'istruzione di begin .

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

Aggiunta di informazioni a eccezioni (personalizzate)

Potrebbe essere utile includere informazioni aggiuntive con un'eccezione, ad esempio per la registrazione o per consentire la gestione condizionale quando viene rilevata l'eccezione:

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

Sollevare l'eccezione:

raise CustomError.new(true)

Cattura l'eccezione e l'accesso alle informazioni aggiuntive fornite:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow