Non so voi, ma io quando programmo ogni tanto sbaglio. Non sempre, certo, ma mi capita un errore qua o un errore là ogni tanto. Fortunatamente sono un assiduo divoratore di unit test e quant'altro agevoli il debug.
Se anche a voi capita di sbagliare senz'altro sarà utile imparare a conoscere la stack trace, la traccia delle attività dell'interprete Ruby così come interpretare la backtrace, ovvero la traccia all'indietro a partire da una eccezione Ruby fino al livello più alto.
Innanzi tutto generiamo una eccezione volutamente. Non la lancerà io, farà in modo che venga lanciata da un metodo che sia stato a sua volta invocato da una serie di altri metodi. Per testare l'esperimento, digitate questo codice su IRB.
class GenerateError def initialize() end def crash(number) i_am_sure_you_will_crash(number) end def i_am_sure_you_will_crash(number) return number / 0 end end c = GenerateError.new c.crash(5)
Il risultato dovrebbe essere una risposta simile a questa.
irb(main):013:0> c.crash(5) ZeroDivisionError: divided by 0 from (irb):8:in `/' from (irb):8:in `i_am_sure_you_will_crash' from (irb):5:in `crash' from (irb):13 from :0
Quella che vedete è la risposta dell'interprete quando avete tentato di dividere un numero per 0. La riga più in alto corrisponde al livello più vicino al codice che ha generato l'errore ed indica il file (in questo caso non c'è, sono su IRB) e la riga dell'errore.
Scendendo via via nella lettura vengono visualizzati tutti i livelli delle chiamate attive fino ad arrivare al chiamante che ha interpretato la richiesta, nel mio caso IRB.
In caso di eccezione è quasi fondamentale la lettura della traccia delle attività poiché consente un rapido intervento. Non a caso l'oggetto Exception fornisce il metodo Exception#backtrace
. Ecco un esempio di output restituito che è possibile, ad esempio, salvare in un file di log:
begin c = GenerateError.new c.crash(5) rescue StandardError => e puts e.backtrace().join("\n") end
Ed ecco il risultato:
irb(main):026:0> begin irb(main):027:1* c = GenerateError.new irb(main):028:1> c.crash(5) irb(main):029:1> rescue StandardError => e irb(main):030:1> puts e.backtrace().join("\n") irb(main):031:1> end (irb):8:in `/' (irb):8:in `i_am_sure_you_will_crash' (irb):5:in `crash' (irb):28:in `irb_binding' /opt/local/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding' :0
In questo caso individuare il problema è banale ma fidatevi. Quando lavorerete con librerie complesse, ad esempio in Rails, la stack trace sarà la vostra ancora di salvezza anche se sarà necessario leggere decine di righe con riferimento chiamate di metodi.