Come eseguire il debug degli script Ruby [chiuso]


153

Ho copiato il seguente codice Ruby da Internet e ho apportato alcune modifiche, ma non funziona.

Cosa posso fare per eseguire il debug del programma da solo?


1
Votazione per riaprire. OP chiaramente vuole un debug di tipo GDB.
Ciro Santilli 15 冠状 病 六四 事件 法轮功

Risposte:


145

Usa Pry ( GitHub ).

Installa tramite:

$ gem install pry
$ pry

Poi aggiungi:

require 'pry'; binding.pry

nel tuo programma.

Al pry0.12.2 tuttavia, ci sono i comandi non navigazione quali next, breakecc Alcune altre gemme inoltre fornire questo, si veda ad esempio pry-byedebug.


10
Consiglio anche di usare Pry (sicuramente un cambio di vita!) .. Una volta installato e richiesto nel programma, impostare un breakpoint è facile come scrivere binding.pry. Viene fornito anche con il completamento del colore, la ricerca della documentazione e la possibilità di modificare e ricaricare dinamicamente un metodo.
Andrea Fiore,

5
La homepage di Pry è disponibile qui: pryrepl.org .
Shadowbq

4
Pry/ byebugsono fantastici, ma non come il primo passo durante il debug. Nella maggior parte dei casi, sollevare un'eccezione con raise object.inspectrisolverà il problema più rapidamente dell'apertura di una sessione IRB. Consiglio di utilizzare i debugger della console solo una volta che soluzioni più semplici come la creazione di un'eccezione non sono in grado di risolvere il problema.
Kelsey Hannan,

3
C'è un modo per codificare in un solo passaggio pry? Non riuscivo a trovare come farlo; ed è quello che mi aspetto da un debugger.
jpetazzo,

2
@jpetazzo sì, digitando 'next'
marcbest

114
  1. In Ruby:

    ruby -rdebug myscript.rb 

    poi,

    • b <line>: inserire il punto di interruzione
    • e n(ext)o s(tep)ec(ontinue)
    • p(uts) per la visualizzazione

    (come perl debug)

  2. In Rails: avvia il server con

    script/server --debugger

    e aggiungi debuggeril codice.


7
-rdebug è spazzatura. E non mantenuto. Usa Pry (vedi l'altra risposta).
Snowcrash,

3
@SnowCrash - Perché dici che -r debugè spazzatura?
Sid Smith il

8
con -rdebug: non è necessario modificare il file sorgente per eseguire il debug
germanlinux,

2
Per una nuova applicazione Ruby / Rails, Pry è la risposta corretta. Ma ho trascorso più di un'ora a cercare una versione antica di Pry da eseguire su un'app Rails 2.2 con una versione specifica dei facetsrequisiti gemma e non ho avuto successo. Per le app Rails antiche ruby-debugè un po 'brutto, ma fa il lavoro.
Abe Voelker,

56

Come raccomandato dalla ringhiera: usa la leva! Posso solo essere d'accordo su questo.

pry è un sostituto molto migliore di irb.

Devi aggiungere

require 'pry'

nel file sorgente e quindi inserire un punto di interruzione nel codice sorgente aggiungendo

binding.pry

nel punto in cui si desidera dare un'occhiata alle cose (è come innescare un punto di interruzione in un ambiente IDE classico)

Una volta che il programma ha colpito il

binding.pry

linea, verrai gettato direttamente nella riserva, con tutto il contesto del tuo programma a portata di mano, in modo da poter semplicemente esplorare tutto intorno, investigare tutti gli oggetti, cambiare stato e persino cambiare il codice al volo.

Credo che non sia possibile modificare il codice del metodo in cui ci si trova attualmente, quindi purtroppo non è possibile modificare la riga successiva da eseguire. Ma un buon codice rubino tende comunque ad essere una riga singola ;-)


30

Il debug aumentando le eccezioni è molto più semplice dello strabismo attraverso leprintistruzioni di registro e, per la maggior parte dei bug, è generalmente molto più veloce dell'apertura di un debugger irb comepryobyebug. Questi strumenti non dovrebbero sempre essere il tuo primo passo.


Debug rapido di Ruby / Rails:

1. Metodo veloce: solleva un Exceptionallora e il .inspectsuo risultato

Il modo più veloce per eseguire il debug del codice Ruby (in particolare Rails) è raiseun'eccezione lungo il percorso di esecuzione del codice mentre si chiama .inspectil metodo o l'oggetto (ad es. foo):

raise foo.inspect

Nel codice sopra, raiseattiva un metodo Exceptionche interrompe l'esecuzione del codice e restituisce un messaggio di errore che contiene convenientemente .inspectinformazioni sull'oggetto / metodo (ad es.foo ) sulla riga che si sta tentando di eseguire il debug.

Questa tecnica è utile per esaminare rapidamente un oggetto o un metodo ( ad esempio, è nil? ) E per confermare immediatamente se una riga di codice viene persino eseguita in un determinato contesto.

2. Fallback: utilizzare un debugger IRB rubino comebyebug opry

Solo dopo aver ottenuto informazioni sullo stato del flusso di esecuzione dei codici, è possibile passare a un debugger ruby ​​gem irb come pryo byebugdove è possibile approfondire lo stato degli oggetti all'interno del percorso di esecuzione.


Consigli generali per principianti

Quando si tenta di eseguire il debug di un problema, un buon consiglio è sempre: leggere il messaggio di errore! @ # $ Ing (RTFM)

Ciò significa leggere attentamente e completamente i messaggi di errore prima di agire in modo da capire cosa sta cercando di dirti. Quando esegui il debug, fai le seguenti domande mentali, in questo ordine , quando leggi un messaggio di errore:

  1. A quale classe fa riferimento l'errore? (cioè ho la classe oggetto corretta o è il mio oggetto nil? )
  2. Quale metodo fa riferimento all'errore? (cioè è un tipo nel metodo; posso chiamare questo metodo su questo tipo / classe di oggetto? )
  3. Infine, usando ciò che posso dedurre dalle mie ultime due domande, quali righe di codice dovrei investigare? (ricorda: l'ultima riga di codice nella traccia dello stack non è necessariamente dove si trova il problema.)

Nella traccia dello stack presta particolare attenzione alle righe di codice che provengono dal tuo progetto (ad esempio le righe che iniziano con app/...se stai usando Rails). Il 99% delle volte il problema riguarda il tuo codice.


Per illustrare perché l'interpretazione in questo ordine è importante ...

Ad esempio un messaggio di errore Ruby che confonde molti principianti:

Esegui codice che a un certo punto viene eseguito come tale:

@foo = Foo.new

...

@foo.bar

e viene visualizzato un errore che indica:

undefined method "bar" for Nil:nilClass

I principianti vedono questo errore e pensano che il problema sia che il metodo nonbar è definito . Non è. In questo errore la parte reale che conta è:

for Nil:nilClass

for Nil:nilClasssignifica che @fooè zero! @foonon è una Foovariabile di istanza! Hai un oggetto che è Nil. Quando vedi questo errore, è semplicemente ruby ​​che prova a dirti che il metodo barnon esiste per gli oggetti della classe Nil. (beh duh! dato che stiamo provando a usare un metodo per un oggetto della classe Foono Nil).

Sfortunatamente, a causa di come viene scritto questo errore ( undefined method "bar" for Nil:nilClass) è facile indurlo a pensare che questo errore abbia a che fare con l' baressere undefined. Se non letto attentamente, questo errore fa sì che i principianti vadano erroneamente a scavare nei dettagli del barmetodo Foo, perdendo completamente la parte dell'errore che suggerisce che l'oggetto è della classe sbagliata (in questo caso: zero). È un errore che può essere facilmente evitato leggendo i messaggi di errore nella loro interezza.

Sommario:

Leggere sempre attentamente l' intero messaggio di errore prima di iniziare qualsiasi debug. Ciò significa: controllare sempre il codice categoria tipo di un oggetto in un messaggio di errore prima , poi i suoi metodi , prima di iniziare sleuthing in qualsiasi stacktrace o riga di codice in cui si pensa l'errore può essere che si verificano. Quei 5 secondi possono farti risparmiare 5 ore di frustrazione.

tl; dr: non strizzare gli occhi nei registri di stampa: solleva eccezioni o usa invece un debugger irb. Evita le tane del coniglio leggendo attentamente gli errori prima del debug.


3
Mentre sono d'accordo con te sul fatto che leggere i log di stampa sia noioso, penso che raccomandare di non utilizzare un debugger sia in primo luogo un pessimo consiglio. L'aggiunta di un punto di interruzione e l'attivazione è esattamente lo stesso sforzo di sollevare un'eccezione, ma offre una visione completa dello stato corrente dell'applicazione. Se sorgono ulteriori domande a seguito dell'ispezione dello stato dubbioso, è possibile eseguire il drill down interattivo anziché aggiungere un'altra eccezione e riavviare l'applicazione.
Patrick R.

2
@PatrickR. Nella mia esperienza, i debugger IRB non sono un buon primo passo quando stai ancora cercando di capire esattamente dove si trova un problema nel tuo codice. L'aggiunta e la rimozione di molti breakpoint IRB richiede più tempo rispetto all'aggiunta di eccezioni e non fornisce risposte precise sul flusso di controllo del codice nel modo in cui le eccezioni possono consentire ai principianti di eliminare le ipotesi errate. I punti di interruzione IRB sono anche facili da dimenticare, causando confusione quando le richieste si bloccano. Se sai esattamente dove si trova un problema e devi eseguire il debug del suo stato, allora sicuramente, inizia con un debugger IRB. Ma spesso non è vero.
Kelsey Hannan,

1
Hah! La lettura dei messaggi di errore è utile per Ruby, ma altri linguaggi di scripting? Non posso incolpare l'OP per non aver nemmeno disturbato.
kayleeFrye_onDeck

1
La mia reazione iniziale è stata simile a @PatrickR., Ma l'ho provato comunque. Alla fine, trovo che questo sia un cattivo consiglio, o forse nella migliore luce, un consiglio su misura per un caso d'uso diverso da quello che ho. In particolare un caso in cui (a) non si utilizza Rails e (b) si ottengono risultati errati ma non si generano errori o eccezioni, ovvero il codice calcola un numero, è solo il numero sbagliato. Cercare di indovinare in modo iterativo dove fare un programma che altrimenti eseguirà crash è una strategia, ma è più lavoro poiché devo continuare a riavviare e rieseguire. Ogni ciclo ha il suo tempo di avvio che è sprecato.
Brick

20
  1. Stampa le variabili quando possibile. (Si chiama debug printf) È possibile farlo eseguendo

    STDERR.puts x.inspect

    o

    STDERR.puts "Variable x is #{x.inspect}"

    Se si vuole fare questo più facile da digitare, quindi si consiglia di utilizzare l'exemplor gemma.

  2. Attiva gli avvisi. Se stai correndo, rubyeseguilo con l' -winterruttore (ad es ruby -w script.rb.). Se lo stai eseguendo da IRB e stai utilizzando una versione di ruby ​​precedente alla 1.9.2, digita $VERBOSE = trueall'inizio della sessione. Se si scrive erroneamente una variabile di istanza, una volta attivati ​​gli avvisi si otterrà

    attenzione: variabile di istanza @valeusnon inizializzata

  3. Comprendi il concetto di un taglio binario (la seguente citazione è tratta da Practices of a Agile Developer )

    Dividi lo spazio del problema a metà e vedi quale metà contiene il problema. Quindi dividi di nuovo quella metà a metà e ripeti.

  4. Se hai successo con un taglio binario, potresti scoprire che esiste una sola riga che non fa ciò che ti aspetti che faccia. Per esempio

    [1, 2, 3].include?([1,2])

    dà un valore di false, anche se pensi che sarebbe tornato true. In tal caso, potresti voler consultare la documentazione. I siti Web per la documentazione includono ruby-doc.org o APIdock . In quest'ultimo caso, dovresti digitare include?accanto alla lente d'ingrandimento vicino all'angolo in alto a destra, scegliere quello include?che ha Arraysotto di essa (se non sai che classe [1, 2, 3]è, digitare [1, 2, 3].classirb) e potresti includere? (Array) , che descrive cosa fa.

    Tuttavia, se la documentazione non aiuta, è più probabile che tu ottenga una buona risposta se puoi porre una domanda su come una riga specifica non sta facendo ciò che dovrebbe, piuttosto che perché un intero script non sta facendo cosa dovrebbe.


7

elimina tutte le cose

Benvenuti nel 2017 ^ _ ^

Bene, quindi se non ti opponi a provare un nuovo IDE puoi fare quanto segue gratuitamente .

Istruzioni rapide

  1. Installa vscode
  2. Installa Ruby Dev Kit se non l'hai già fatto
  3. Installa le estensioni Ruby, Ruby-Linter e Ruby-Rubocop per vscode
  4. Installa manualmente qualsiasi gemma rubyide / vscode-ruby specifica , se necessario
  5. Configurare i campi launch.jsonda utilizzare "cwd"e e "program" utilizzando il{workspaceRoot} macro
  6. Aggiungi un campo chiamato "showDebuggerOutput"e impostalo sutrue
  7. Abilita punti di interruzione ovunque nelle preferenze di debug come "debug.allowBreakpointsEverywhere": true

Istruzioni dettagliate

  1. Scarica Visual Studio Code aka vscode; questo non è lo stesso di Visual Studio . È gratuito, leggero e generalmente considerato positivamente.
  2. Installa il kit Ruby Dev; dovresti seguire le istruzioni nel loro repository qui: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
  3. Successivamente è possibile installare le estensioni tramite un browser Web o all'interno dell'IDE; questo è per l'IDE interno. Se scegli l'altro, puoi andare qui . Passa alla parte Estensioni di vscode; puoi farlo in un paio di modi, ma probabilmente il metodo più a prova di futuro sarà quello di colpireF1 e scrivere extfino a quando non sarà disponibile un'opzione chiamata Extensions: Install Extensions . Le alternative sono CtrlShiftxe dalla barra dei menu in alto,View->Extensions
  4. Successivamente vorrai le seguenti estensioni; questi non sono necessari al 100%, ma ti lascerò decidere cosa tenere dopo aver armeggiato:
    • Rubino; autore estensione Peng Lv
    • rubino rubocop; autore dell'estensione misogi
    • rubino Linter; autore estensione Cody Hoover
  5. All'interno della directory del tuo script ruby, creeremo una directory tramite la riga di comando chiamata .vscode e lì dentro ci sarà un file chiamato launch.jsondove memorizzeremo alcune opzioni di configurazione.
    • launch.json Contenuti

{ "version": "0.2.0", "configurations": [ { "name": "Debug Local File", "type":"Ruby", "request": "launch", "cwd": "${workspaceRoot}", "program": "{workspaceRoot}/../script_name.rb", "args": [], "showDebuggerOutput": true } ] }

  1. Seguire le istruzioni degli autori delle estensioni per le installazioni manuali di gemme. Si trova qui per ora: https://github.com/rubyide/vscode-ruby#install-ruby-dependencies
  2. Probabilmente vorrai la possibilità di posizionare i punti di interruzione ovunque tu voglia; la mancata abilitazione di questa opzione può causare confusione. Per fare ciò, andremo nella barra dei menu in alto e selezioneremo File->Preferences->Settings(o Ctrl,) e scorreremo fino a raggiungere la Debugsezione. Espandilo e cerca un campo chiamato "debug.allowBreakpointsEverywhere": seleziona quel campo e fai clic sulla piccola icona a forma di matita e impostalo su true.

Dopo aver fatto tutte quelle cose divertenti, dovresti essere in grado di impostare punti di interruzione e debug in un menu simile a questo per la metà del 2017 e un tema più scuro: inserisci qui la descrizione dell'immaginecon tutte le cose divertenti come il tuo stack di chiamate, il visualizzatore di variabili, ecc.

Il PITA più grande è 1) l'installazione dei pre-req e 2) ricordando di configurare il .vscode\launch.jsonfile. Solo il numero 2 dovrebbe aggiungere qualsiasi bagaglio a progetti futuri e puoi semplicemente copiare una configurazione abbastanza generica come quella sopra elencata. Probabilmente c'è una posizione di configurazione più generale, ma non lo so dalla cima della mia testa.


È il 2018 ora, 😉 ma sfortunatamente, non è ancora possibile eseguire il debug di un test unit utilizzando i plugin elencati qui ... 😕 Abbastanza triste.
Monsieur,

1
@MonsieurDart Quando ho scritto questo, era pensato per il debug di base degli script ruby. Non ho familiarità con nulla di specifico sui test unitari. Se questa risposta è errata o obsoleta, per favore fatemi sapere cosa richiede attenzione e qualsiasi informazione che possa aiutare ad accelerare tale processo.
kayleeFrye_onDeck

Ehi @kayleeFrye_onDeck! La tua risposta è fantastica, te lo do totalmente. Ma, l'ultima volta che ho controllato il plug-in Ruby di Peng Lv per VSC, non è stato in grado di impostare punti di interruzione all'interno di un test unitario (o di qualsiasi altro test). Era una delle limitazioni conosciute del plugin. Penso che le persone debbano saperlo prima di provare a configurare la propria istanza di VSC: ci vuole tempo e, per molte persone, eseguire un test è il modo numero uno per scrivere ed eseguire il debug del codice. 😊
MonsieurDart

6

Consiglio vivamente questo video, al fine di scegliere lo strumento giusto al momento per eseguire il debug del nostro codice.

https://www.youtube.com/watch?v=GwgF8GcynV0

Personalmente, vorrei evidenziare due grandi argomenti in questo video.

  • Pry è fantastico per i dati di debug, "pry is a data explorer" (sic)
  • Il debugger sembra essere meglio eseguire il debug passo dopo passo.

Sono i miei due centesimi!


6

Tutte le altre risposte danno già quasi tutto ... Solo una piccola aggiunta.

Se vuoi un altro debugger simile a IDE (non CLI) e non hai paura di usare Vim come editor, suggerisco Vim Ruby Debugger plugin .

La sua documentazione è piuttosto semplice, quindi segui il link e vedi. In breve, ti consente di impostare il punto di interruzione nella riga corrente nell'editor, visualizzare le variabili locali in una finestra elegante in pausa, passare / entrare - quasi tutte le solite funzionalità di debugger.

Per me è stato abbastanza divertente utilizzare questo debugger vim per il debug di un'app Rails, anche se le ricche capacità di logger di Rails ne eliminano quasi la necessità.


6

Ho appena scoperto questo gioiello (trasforma Pry in un debugger per MRI Ruby 2.0+)

https://github.com/deivid-rodriguez/pry-byebug

Installa con:

gem install pry-byebug

quindi usa esattamente come pry, segna la linea che vuoi interrompere:

require 'pry'; binding.pry

A differenza della leva vaniglia, tuttavia, questo gioiello ha alcuni comandi di navigazione simili a GDB come next, stepe break:

break SomeClass#run            # Break at the start of `SomeClass#run`.
break Foo#bar if baz?          # Break at `Foo#bar` only if `baz?`.
break app/models/user.rb:15    # Break at line 15 in user.rb.
break 14                       # Break at line 14 in the current file.

5
  1. Puoi stampare le tue variabili lungo la strada
  2. Attiva la -wbandiera (avvisi)
  3. Utilizzare uno strumento come ruby-debug

2
Aggiungo che irbè un ottimo punto di partenza. Prova a usare irb con piccoli pezzi discutibili. Adoro ruby-debug (ruby-debug19 per Ruby 1.9+) perché semplifica l'arresto del programma in esecuzione, l'esame delle variabili, il rilascio in irb, quindi continua l'esecuzione.
Tin Man,

5

Per eseguire facilmente il debug dello script della shell Ruby, basta cambiare la sua prima riga da:

#!/usr/bin/env ruby

per:

#!/usr/bin/env ruby -rdebug

Quindi ogni volta che viene visualizzata la console di debugger, puoi scegliere:

  • c per Continua (alla prossima eccezione, punto di interruzione o linea con: debugger ,
  • n per la riga successiva,
  • w/where per visualizzare frame / stack di chiamate,
  • l per mostrare il codice corrente,
  • cat per mostrare punti di cattura.
  • h per ulteriore aiuto.

Vedi anche: Debug con ruby-debug , scorciatoie da tastiera per gemma ruby-debug .


Se lo script si blocca e hai bisogno di un backtrace, prova a usare lldb/ gdblike:

echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -nf ruby)

e quindi controlla il tuo processo in primo piano.

Sostituire lldbcon gdbse funziona meglio. Prefisso con sudoper eseguire il debug di processi non di proprietà.


1
ruby-debug sembra piuttosto datato. Il repository git per ruby-debug ha un solo commit per quest'anno - è ancora attivamente mantenuto?
Andrew Grimm,

Sembra anche confezionato con rubino, il che è fantastico quando sei in un pizzico. Bella risposta!
Breedly,

5

A partire da Ruby 2.4.0, è più facile avviare una sessione REPL IRB nel mezzo di qualsiasi programma Ruby. Inserisci queste righe nel punto in cui vuoi eseguire il debug del programma:

require 'irb'
binding.irb

È possibile eseguire il codice Ruby e stampare le variabili locali. Digitare Ctrl + D o quitper terminare il REPL e lasciare che il programma Ruby continui a funzionare.

Puoi anche usare putse pstampare valori dal tuo programma mentre è in esecuzione.


4

Se si utilizza RubyMine , il debug degli script ruby ​​è semplice e diretto.

Supponiamo di avere uno script Ruby hello_world.rb

1. Impostare i punti di interruzione

Impostare un punto di interruzione alla riga 6 come di seguito.

inserisci qui la descrizione dell'immagine

2. Inizia il debug

Ora puoi semplicemente avviare il debugger per eseguire lo script:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

3. Ispezionare le variabili, ecc.

Quindi quando l'esecuzione raggiunge un punto di interruzione, sarai in grado di ispezionare le variabili, ecc.

inserisci qui la descrizione dell'immagine

Ulteriori informazioni per il vostro riferimento

  1. Se si desidera utilizzare RubyMine per eseguire il debug remoto , è possibile farlo.
  2. Se si desidera utilizzare RubyMine per le guide di debug remote in esecuzione all'interno di una finestra mobile , è anche semplice.

Abbiamo un modo per eseguire il debug di librerie esterne in RubyMine?
Am33d,

2

debug di printf

C'è sempre stata una controversia sulle tecniche di debug, ad alcune persone piace eseguire il debug con le dichiarazioni stampate, altre come scavare a fondo con un debugger.

Suggerirei di provare entrambi gli approcci.

In realtà uno dei vecchi uomini di Unix ha recentemente affermato che il debugging di printf è stato un modo più veloce di procedere per lui in alcuni punti.

Ma se sei nuovo in qualche posto di lavoro e hai bisogno di capire una grossa quantità di codice, è davvero utile spostarti dappertutto, mettendo alcuni punti di interruzione qua e là, andando avanti con esso come funziona.

Dovrebbe darti una certa comprensione di come è intessuto il codice.

Se non conosci il software di altre persone, potrebbe esserti di aiuto.

Scoprirai rapidamente se l'hanno organizzato in modo intelligente o se è solo un mucchio di merda.


questa è senza dubbio la migliore risposta ,, dipende
menriquez,


1

La madre di tutti i debugger è una semplice schermata di stampa. Il più delle volte, probabilmente vuoi solo ispezionare alcuni oggetti semplici, un modo semplice e veloce è così:

@result = fetch_result

p "--------------------------"
p @result

Questo stamperà il contenuto di @result su STDOUT con una riga davanti per una facile identificazione.

Bonus se usi un framework con caricamento automatico / ricarica come Rails, non dovrai nemmeno riavviare la tua app. (A meno che il codice di cui si sta eseguendo il debug non venga ricaricato a causa di impostazioni specifiche del framework)

Trovo che questo funzioni per il 90% del caso d'uso per me. Puoi anche usare ruby-debug, ma lo trovo eccessivo per la maggior parte del tempo.


1

Esistono molti debugger con funzionalità diverse, in base alla quale fai la scelta. Le mie priorità erano soddisfatte con le mosse di leva che erano:

  • informazioni rapidamente comprensibili su come utilizzare
  • passaggi intuitivi (come passare facilmente in blocchi)
  • "fare un passo indietro" (i movimenti di leva soddisfano parzialmente la necessità)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.