Cómo depurar scripts de Ruby [cerrado]

153

Copié el siguiente código Ruby de Internet e hice algunos cambios pero no funciona.

¿Qué puedo hacer para depurar el programa yo solo?

Andrew Grimm
fuente
1
Votación para reabrir. OP claramente quiere una depuración de pasos similar a GDB.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

145

Usa Pry ( GitHub ).

Instalar a través de:

$ gem install pry
$ pry

Luego añade:

require 'pry'; binding.pry

en su programa

A partir de pry0.12.2 sin embargo, existen comandos no de navegación tales como next, break, etc. Algunas otras gemas, además, proporcionar esto, véase por ejemplo pry-byedebug.

horseyguy
fuente
10
También recomiendo usar Pry (¡definitivamente un cambio de vida!). Una vez instalado y requerido en su programa, establecer un punto de interrupción es tan fácil como escribir binding.pry. También viene con finalización de color, búsqueda de documentación y posibilidad de editar y recargar dinámicamente un método ..
Andrea Fiore
55
La página de inicio de Pry está disponible aquí: pryrepl.org .
shadowbq
44
Pry/ byebugson geniales, pero no como su primer paso al depurar. En la mayoría de los casos, generar una excepción raise object.inspectresolverá su problema más rápido que abrir una sesión irb. Recomiendo usar solo los depuradores de consola una vez más, las soluciones simples, como generar una excepción, no pueden resolver su problema.
Kelsey Hannan
3
¿Hay alguna forma de código de un solo paso con pry? No pude encontrar cómo hacerlo; y eso es lo que espero de un depurador.
jpetazzo
2
@jpetazzo sí, escribiendo 'next'
marcbest
114
  1. En rubí:

    ruby -rdebug myscript.rb 

    luego,

    • b <line>: poner punto de quiebre
    • y n(ext)o s(tep)yc(ontinue)
    • p(uts) para mostrar

    (como depuración perl)

  2. En Rails: inicie el servidor con

    script/server --debugger

    y agregue debuggerel código.

germanlinux
fuente
77
-Rdebug es basura. Y sin mantenimiento. Usa Pry (mira la otra respuesta).
Snowcrash
3
@SnowCrash - ¿Por qué dices que eso -r debuges basura?
sid smith
8
con -rdebug: no es necesario cambiar el archivo fuente para depurar
germanlinux el
2
Para una nueva aplicación Ruby / Rails, Pry es la respuesta correcta. Pero pasé más de una hora tratando de encontrar una versión antigua de Pry para ejecutar en una aplicación Rails 2.2 con una versión específica de facetslos requisitos de gemas, y no tuve éxito. Para las aplicaciones antiguas de Rails ruby-debuges un poco desagradable, pero hace el trabajo.
Abe Voelker
56

Como la barandilla recomendada: ¡usa la palanca! Solo puedo estar de acuerdo en esto.

Pry es una respuesta mucho mejor que irb.

Necesitas agregar

require 'pry'

a su archivo fuente y luego inserte un punto de interrupción en su código fuente agregando

binding.pry

en el lugar donde desea ver las cosas (esto es como activar un punto de interrupción en un entorno IDE clásico)

Una vez que su programa llegue al

binding.pry

línea, se lo arrojará directamente a la respuesta de palanca, con todo el contexto de su programa al alcance de la mano, para que pueda explorar todo, investigar todos los objetos, cambiar el estado e incluso cambiar el código sobre la marcha.

Creo que no puede cambiar el código del método en el que se encuentra actualmente, por lo que lamentablemente no puede cambiar la siguiente línea que se ejecutará. Pero un buen código ruby ​​tiende a ser una sola línea de todos modos ;-)

edx
fuente
30

La depuración mediante excepciones es mucho más fácil que entrecerrar los ojos a través de lasprintdeclaraciones de registro, y para la mayoría de los errores, generalmente es mucho más rápido que abrir un depurador irb comopryobyebug. Esas herramientas no siempre deberían ser su primer paso.


Depuración de Ruby / Rails rápidamente:

1. Método rápido: elevar un Exceptionentonces y .inspectsu resultado

La forma más rápida de depurar el código Ruby (especialmente Rails) es raiseuna excepción a lo largo de la ruta de ejecución de su código al invocar .inspectel método u objeto (por ejemplo foo):

raise foo.inspect

En el código anterior, raiseactiva un Exceptionque detiene la ejecución de su código y devuelve un mensaje de error que contiene convenientemente .inspectinformación sobre el objeto / método (es decir foo) en la línea que está tratando de depurar.

Esta técnica es útil para examinar rápidamente un objeto o método ( por ejemplo, nil¿ lo es ? ) Y para confirmar de inmediato si una línea de código se está ejecutando en un contexto determinado.

2. Fallback: utilice un depurador IRB ruby como byebugopry

Solo después de tener información sobre el estado del flujo de ejecución de sus códigos, debería considerar pasar a un depurador de ruby ​​gem irb como pryo byebugdonde puede profundizar en el estado de los objetos dentro de su ruta de ejecución.


Consejos generales para principiantes

Cuando intenta depurar un problema, un buen consejo es siempre: Leer el mensaje de error! @ # $ Ing (RTFM)

Eso significa leer los mensajes de error cuidadosa y completamente antes de actuar para que comprenda lo que está tratando de decirle. Cuando depure, haga las siguientes preguntas mentales, en este orden , cuando lea un mensaje de error:

  1. ¿A qué clase hace referencia el error? (es decir, ¿tengo la clase de objeto correcta o es mi objeto nil? )
  2. ¿A qué método hace referencia el error? ( es decir, es un tipo en el método; ¿puedo llamar a este método en este tipo / clase de objeto? )
  3. Finalmente, usando lo que puedo inferir de mis dos últimas preguntas, ¿qué líneas de código debo investigar? (recuerde: la última línea de código en el seguimiento de la pila no es necesariamente el problema).

En el seguimiento de la pila, preste especial atención a las líneas de código que provienen de su proyecto (por ejemplo, líneas que comienzan con app/...si está utilizando Rails). El 99% de las veces el problema es con su propio código.


Para ilustrar por qué es importante interpretar en este orden ...

Por ejemplo, un mensaje de error de Ruby que confunde a muchos principiantes:

Ejecutas código que en algún momento se ejecuta como tal:

@foo = Foo.new

...

@foo.bar

y obtienes un error que dice:

undefined method "bar" for Nil:nilClass

Los principiantes ven este error y piensan que el problema es que el método nobar está definido . No es. En este error, la parte real que importa es:

for Nil:nilClass

for Nil:nilClasssignifica que @fooes nulo! @foono es una Foovariable de instancia! Tienes un objeto que es Nil. Cuando vea este error, es simplemente que Ruby intenta decirle que el método barno existe para los objetos de la clase Nil. (bueno duh! ya que estamos tratando de usar un método para un objeto de la clase Foono Nil).

Desafortunadamente, debido a cómo se escribe este error ( undefined method "bar" for Nil:nilClass) es fácil dejarse engañar para que piense que este error tiene que ver con barser undefined. Cuando no se lee con cuidado, este error hace que los principiantes vayan a cavar por error en los detalles del barmétodo Foo, omitiendo por completo la parte del error que sugiere que el objeto es de la clase incorrecta (en este caso: nulo). Es un error que se evita fácilmente al leer los mensajes de error en su totalidad.

Resumen:

Siempre lea cuidadosamente el mensaje de error completo antes de comenzar cualquier depuración. Eso significa: Siempre verifique primero el tipo de clase de un objeto en un mensaje de error , luego sus métodos , antes de comenzar a buscar en cualquier stacktrace o línea de código donde cree que puede estar ocurriendo el error. Esos 5 segundos pueden ahorrarte 5 horas de frustración.

tl; dr: No entrecerre los ojos en los registros de impresión: aumente las excepciones o use un depurador irb en su lugar. Evite las madrigueras de conejo leyendo los errores cuidadosamente antes de depurar.

Kelsey Hannan
fuente
3
Si bien estoy de acuerdo con usted en que leer los registros de impresión es tedioso, creo que recomendar no usar un depurador en primer lugar es un muy mal consejo. Agregar un punto de interrupción y activarlo es exactamente el mismo esfuerzo que generar una excepción, pero le brinda una vista completa del estado actual de la aplicación. Si surgen más preguntas como resultado de la inspección del estado dudoso, puede profundizar interactivamente en lugar de agregar otra excepción y reiniciar la aplicación.
Patrick R.
2
@PatrickR. En mi experiencia, los depuradores IRB no son un buen primer paso cuando todavía estás tratando de profundizar exactamente dónde está un problema en tu código. Agregar y eliminar muchos puntos de interrupción IRB lleva más tiempo que agregar excepciones, y no brinde respuestas definitivas sobre el flujo de control de su código de la misma manera que las excepciones pueden hacerlo con los principiantes para eliminar las suposiciones erróneas. Los puntos de interrupción de IRB también son fáciles de olvidar, lo que causa confusión cuando las solicitudes se bloquean. Si sabe exactamente dónde está un problema y necesita depurar su estado, entonces, seguro, comience con un depurador IRB. Pero a menudo eso no es cierto.
Kelsey Hannan
1
Ja! Leer los mensajes de error es útil para Ruby, pero ¿ otros lenguajes de script? No puedo culpar al OP por ni siquiera molestarme.
kayleeFrye_onDeck
1
Mi reacción inicial fue similar a @PatrickR., Pero intenté esto de todos modos. Al final, creo que esto es un mal consejo, o tal vez en la mejor luz, consejos adaptados a un caso de uso diferente al que tengo. En particular, un caso en el que (a) no usa Rails y (b) tiene un resultado incorrecto pero no se generan errores ni excepciones, es decir, el código calcula un número, es solo el número incorrecto. Intentar adivinar de forma iterativa dónde hacer un programa que de otro modo ejecutaría el bloqueo es una estrategia, pero es más trabajo ya que tengo que seguir reiniciando y volviendo a ejecutar. Cada ciclo tiene su propio tiempo de arranque que se desperdicia.
Ladrillo
20
  1. Imprima las variables siempre que sea posible. (Esto se denomina depuración de printf) Puede hacerlo ejecutando

    STDERR.puts x.inspect

    o

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

    Si desea que sea más fácil de escribir, puede utilizar la gema de ejemplo .

  2. Encienda las advertencias. Si está ejecutando ruby, ejecútelo con el -winterruptor (por ejemplo ruby -w script.rb). Si lo está ejecutando desde irb y está utilizando una versión de ruby ​​anterior a 1.9.2, escriba $VERBOSE = trueal comienzo de su sesión. Si escribe mal una variable de instancia, una vez que las advertencias estén activadas, obtendrá

    advertencia: variable de instancia @valeusno inicializada

  3. Comprender el concepto de un corte binario (la siguiente cita es de Prácticas de un desarrollador ágil )

    Divida el espacio del problema por la mitad y vea qué mitad contiene el problema. Luego divida esa mitad por la mitad nuevamente y repita.

  4. Si tiene éxito con un corte binario, puede encontrar que hay una sola línea que no hace lo que espera que haga. Por ejemplo

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

    da un valor de false, aunque creas que volvería true. En ese caso, es posible que desee ver la documentación. Los sitios web de documentación incluyen ruby-doc.org o APIdock . En el último caso, escribiría include?junto a la lupa cerca de la esquina superior derecha, elegiría la include?que tiene Arraydebajo (si no sabe qué clase [1, 2, 3]es, escriba [1, 2, 3].classirb), y podrá incluir. (Array) , que describe lo que hace.

    Sin embargo, si la documentación no ayuda, es más probable que obtenga una buena respuesta si puede hacer una pregunta sobre cómo una línea específica no está haciendo lo que debería, en lugar de por qué un guión completo no está haciendo lo que debería.

Andrew Grimm
fuente
7

borra todas las cosas

Bienvenido a 2017 ^ _ ^

De acuerdo, si no te opones a probar un nuevo IDE, puedes hacer lo siguiente de forma gratuita .

Instrucciones rápidas

  1. Instalar vscode
  2. Instala Ruby Dev Kit si aún no lo has hecho
  3. Instalar extensiones Ruby, ruby-linter y ruby-rubocop para vscode
  4. Instale manualmente las gemas que rubyide / vscode-ruby especifique , si es necesario
  5. Configure su launch.jsonuso "cwd"y y "program" campos utilizando la {workspaceRoot}macro
  6. Agregue un campo llamado "showDebuggerOutput"y configúrelo entrue
  7. Habilite puntos de interrupción en todas partes en sus preferencias de depuración como "debug.allowBreakpointsEverywhere": true

Instrucciones detalladas

  1. Descargar Visual Studio Code aka vscode; Esto no es lo mismo que Visual Studio . Es gratis, liviano y generalmente considerado positivamente.
  2. Instale el kit Ruby Dev; debe seguir las instrucciones en su repositorio aquí: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
  3. A continuación, puede instalar extensiones a través de un navegador web o dentro del IDE; esto es para dentro del IDE. Si elige el otro, puede ir aquí . Navegue a la parte Extensiones de vscode; puede hacer esto de dos maneras, pero el método más a prueba de futuro probablemente será golpear F1y escribir exthasta que esté disponible una opción llamada Extensiones: Instalar extensiones . Las alternativas son CtrlShiftxy desde la barra de menú superior,View->Extensions
  4. A continuación, querrá las siguientes extensiones; estos no son 100% necesarios, pero te dejaré decidir qué guardar después de haber retocado algunos:
    • Rubí; autor de la extensión Peng Lv
    • rubí-rubocop; autor de la extensión misogi
    • ruby-linter; autor de la extensión Cody Hoover
  5. Dentro del directorio de su script de ruby, vamos a hacer un directorio a través de la línea de comando llamado .vscodey allí solo un archivo llamado launch.jsondonde vamos a almacenar algunas opciones de configuración.
    • launch.json contenido

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

  1. Siga las instrucciones de los autores de la extensión para la instalación manual de gemas. Se encuentra aquí por ahora: https://github.com/rubyide/vscode-ruby#install-ruby-dependencies
  2. Probablemente querrás la posibilidad de poner puntos de interrupción donde quieras; no tener esta opción habilitada puede causar confusión. Para hacer esto, iremos a la barra de menú superior y seleccionaremos File->Preferences->Settings(o Ctrl,) y nos desplazaremos hasta llegar a la Debugsección. Expanda y busque un campo llamado "debug.allowBreakpointsEverywhere": seleccione ese campo y haga clic en el pequeño icono con aspecto de lápiz y configúrelo true.

Después de hacer todas esas cosas divertidas, debería poder establecer puntos de interrupción y depurar en un menú similar a este para mediados de 2017 y un tema más oscuro: ingrese la descripción de la imagen aquícon todas las cosas divertidas como su pila de llamadas, visor variable, etc.

El mayor PITA es 1) instalar los requisitos previos y 2) Recordar configurar el .vscode\launch.jsonarchivo. Solo el n. ° 2 debería agregar equipaje a proyectos futuros, y puede copiar una configuración lo suficientemente genérica como la que se menciona arriba. Probablemente haya una ubicación de configuración más general, pero no lo sé.

kayleeFrye_onDeck
fuente
Ahora es 2018, 😉 pero desafortunadamente, aún no puede depurar una prueba unitaria utilizando los complementos que enumeró aquí ... 😕 Muy triste.
MonsieurDart
1
@MonsieurDart Cuando escribí esto, estaba destinado a la depuración básica de los scripts ruby. No estoy familiarizado con nada específicamente sobre pruebas unitarias. Si esta respuesta es incorrecta u obsoleta, avíseme qué necesita atención y cualquier información que pueda ayudar a acelerar ese proceso.
kayleeFrye_onDeck
¡Hola, @kayleeFrye_onDeck! Tu respuesta es genial, te lo doy totalmente. Pero, la última vez que revisé el complemento Ruby de Peng Lv para VSC, no fue capaz de establecer puntos de interrupción dentro de una prueba unitaria (o cualquier otra prueba). Era una de las limitaciones conocidas del complemento. Creo que la gente necesita saber esto antes de intentar configurar su instancia de VSC: lleva tiempo y, para muchas personas, ejecutar pruebas es la forma número uno de escribir y depurar código. 😊
MonsieurDart
6

Recomiendo este video para elegir la herramienta adecuada en este momento para depurar nuestro código.

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

Personalmente, destacaría dos grandes temas en este video.

  • Pry es impresionante para depurar datos, "Pry es un explorador de datos" (sic)
  • El depurador parece ser mejor depurar paso a paso.

¡Esos son mis dos centavos!

DavidSilveira
fuente
6

Todas las demás respuestas ya dan casi todo ... Solo una pequeña adición.

Si desea más depurador tipo IDE (no CLI) y no tiene miedo de usar Vim como editor, le sugiero el complemento Vim Ruby Debugger para él.

Su documentación es bastante sencilla, así que siga el enlace y vea. En resumen, le permite establecer el punto de interrupción en la línea actual en el editor, ver las variables locales en una ventana ingeniosa en pausa, pasar / entrar, casi todas las características habituales del depurador.

Para mí fue bastante divertido usar este depurador vim para depurar una aplicación Rails, aunque las ricas capacidades de registro de Rails casi eliminan la necesidad de ello.

NIA
fuente
6

Acabo de descubrir esta gema (convierte a Pry en un depurador para MRI Ruby 2.0+)

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

Instalar con:

gem install pry-byebug

luego use exactamente como pry, marque la línea en la que desea romper:

require 'pry'; binding.pry

Sin embargo, a diferencia de Vanilla Pry, esta gema tiene algunos comandos clave de navegación tipo GDB como next, stepy 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.
nurettin
fuente
5
  1. Puede imprimir sus variables en el camino
  2. Encienda la -wbandera (advertencias)
  3. Use una herramienta como ruby-debug
ghostdog74
fuente
2
Agregaré que irbes un excelente punto de partida. Intente usar irb con pequeños trozos cuestionables. Me encanta ruby-debug (ruby-debug19 para Ruby 1.9+) porque hace que sea más fácil detener el programa en ejecución, examinar variables, ingresar a irb y luego continuar ejecutándolo.
The Tin Man
5

Para depurar fácilmente el script de shell Ruby, simplemente cambie su primera línea de:

#!/usr/bin/env ruby

a:

#!/usr/bin/env ruby -rdebug

Luego, cada vez que se muestre la consola del depurador, puede elegir:

  • cpara Continuar (hasta la próxima Excepción, punto de interrupción o línea con:) debugger,
  • n para la siguiente línea,
  • w/ whereMostrar marco / pila de llamadas,
  • l para mostrar el código actual,
  • cat para mostrar puntos de captura.
  • h para más ayuda

Ver también: Depuración con ruby-debug , atajos de teclado para ruby-debug gem .


En caso de que el script simplemente se cuelgue y necesite una traza inversa, intente usar lldb/ gdblike:

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

y luego verifique su proceso en primer plano.

Reemplazar lldbcon gdbsi funciona mejor. Prefijo con sudopara depurar procesos no propios.

kenorb
fuente
1
ruby-debug se ve bastante anticuado. El repositorio de git para ruby-debug solo tiene una confirmación para este año: ¿se mantiene activamente?
Andrew Grimm
También parece venir empaquetado con rubí, lo cual es genial cuando estás en apuros. ¡Gran respuesta!
Breedly
5

A partir de Ruby 2.4.0, es más fácil iniciar una sesión REPL de IRB en medio de cualquier programa de Ruby. Coloque estas líneas en el punto del programa que desea depurar:

require 'irb'
binding.irb

Puede ejecutar el código Ruby e imprimir variables locales. Escriba Ctrl + D o quitpara finalizar REPL y dejar que el programa Ruby siga ejecutándose.

También puede usar putse pimprimir valores de su programa mientras se ejecuta.

David Grayson
fuente
4

Si está utilizando RubyMine , depurar scripts de ruby ​​es simple y directo.

Supongamos que tiene un script Ruby hello_world.rb

1. Establecer puntos de interrupción

Establezca un punto de interrupción en la línea 6 como se muestra a continuación.

ingrese la descripción de la imagen aquí

2. Comience a depurar

Ahora puede iniciar el depurador para ejecutar el script:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

3. Inspeccionar variables, etc.

Luego, cuando la ejecución llegue a un punto de interrupción, podrá inspeccionar variables, etc.

ingrese la descripción de la imagen aquí

Más información para su referencia.

  1. Si desea utilizar RubyMine para realizar la depuración remota , puede hacerlo.
  2. Si desea utilizar RubyMine para eliminar rieles remotos que se ejecutan dentro de una ventana acoplable , también es sencillo.
Yuci
fuente
¿Tenemos una manera de depurar bibliotecas externas en RubyMine?
Am33d
2

depuración de printf

Siempre ha habido una controversia en torno a las técnicas de depuración, a algunas personas les gusta depurar mediante declaraciones impresas, a otras les gusta profundizar con un depurador.

Te sugiero que pruebes ambos enfoques.

En realidad, uno de los viejos hombres de Unix dijo recientemente que la depuración de printf era una forma más rápida de conseguirlo en algunos puntos.

Pero si eres nuevo en algún trabajo y necesitas entender una gran cantidad de código, entonces es realmente útil dar un paso adelante, poner algunos puntos de interrupción aquí y allá, y seguir cómo funciona.

Debería darte una idea de cómo se teje el código.

Si usted es nuevo en el software de otras personas, podría ayudarlo a avanzar.

Descubrirá rápidamente si lo organizaron de una manera inteligente, o si eso es solo un montón de mierda.

edx
fuente
esta es sin duda la mejor respuesta, depende
menriquez
1

La madre de todos los depuradores es la simple pantalla de impresión antigua. La mayoría de las veces, probablemente solo desee inspeccionar algunos objetos simples, una forma rápida y fácil es así:

@result = fetch_result

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

Esto imprimirá el contenido de @result a STDOUT con una línea en el frente para una fácil identificación.

Bonificación si usa un marco capaz de cargar / cargar automáticamente como Rails, ni siquiera necesitará reiniciar su aplicación. (A menos que el código que está depurando no se vuelva a cargar debido a la configuración específica del marco)

Creo que esto funciona para el 90% del caso de uso para mí. También puede usar ruby-debug, pero me parece excesivo la mayor parte del tiempo.

Aaron Qian
fuente
1

Hay muchos depuradores con diferentes características, en función de los cuales eliges. Mis prioridades estaban satisfechas con movimientos de palanca que eran:

  • información rápidamente comprensible sobre cómo usar
  • pasos intuitivos (como entrar fácilmente en bloques)
  • "dar un paso atrás" (los movimientos de palanca satisfacen parcialmente la necesidad)
Daniel Garmoshka
fuente