如何调试Ruby脚本[关闭]


153

我从互联网上复制了以下Ruby代码并进行了一些更改,但是它不起作用。

我该如何自己调试程序?


1
投票重新开放。OP显然希望进行类似GDB的步骤调试。
西罗Santilli郝海东冠状病六四事件法轮功

Answers:


145

使用PryGitHub)。

通过以下方式安装:

$ gem install pry
$ pry

然后加:

require 'pry'; binding.pry

进入您的程序。

作为pry0.12.2然而,没有导航命令,例如nextbreak等。一些其他宝石附加地提供此,参见例如pry-byedebug


10
我还建议您使用Pry(绝对可以改变生活!)。一旦在程序中安装并需要使用它,设置断点就和编写一样容易binding.pry。它还配备了颜色后,文档查询和可能性来动态编辑和重新加载的方法..
安德烈菲奥雷

5
可以在这里找到Pry的主页:pryrepl.org
shadowbq 2013年

4
Pry/ byebug很好,但不是调试时的第一步。在大多数情况下,使用引发例外raise object.inspect会比打开irb会话更快地解决您的问题。我建议仅在更简单的解决方案(例如引发异常)无法解决您的问题时使用控制台调试器。
Kelsey Hannan 2015年

3
有没有一种方法可以单步执行代码pry?我找不到方法。这就是我对调试器的期望。
jpetazzo

2
@jpetazzo是的,通过键入“ next”
marcbest 2016年

114
  1. 在Ruby中:

    ruby -rdebug myscript.rb 

    然后,

    • b <line>:放置断点
    • n(ext)s(tep)c(ontinue)
    • p(uts) 用于显示

    (如perl调试)

  2. 在Rails中:使用以下命令启动服务器

    script/server --debugger

    并添加debugger代码。


7
-rdebug是垃圾。并且没有维护。使用撬动(请参阅其他答案)。
Snowcrash 2013年

3
@SnowCrash-为什么说那-r debug是垃圾?
sid Smith

8
使用-rdebug:无需进行调试即可更改源文件
germanlinux 2014年

2
对于新的Ruby / Rails应用程序,Pry是正确的答案。但是我花了一个多小时试图找到一个古老版本的Pry,使其能够在Rails 2.2应用程序上运行facets,并在gem要求中使用特定版本,但是没有成功。对于古老的Rails应用程序ruby-debug来说有点讨厌,但是可以完成工作。
安倍·沃克

56

正如栏杆建议:使用撬动!我只能同意这一点。

撬动比irb好得多。

您需要添加

require 'pry'

到您的源文件,然后通过添加以下内容在您的源代码中插入一个断点

binding.pry

在您想要查看事物的地方(就像在传统的IDE环境中触发断点一样)

一旦您的程序点击

binding.pry

行,您将立即进入程序的所有上下文,因此您可以轻松浏览周围的所有内容,研究所有对象,更改状态,甚至即时更改代码。

我相信您不能更改当前所用方法的代码,因此可悲的是您不能更改要执行的下一行。但是好的Ruby代码无论如何都倾向于单行;-)


30

通过提高例外调试容易得多不是通过眯眼print日志语句,对于大多数的错误,它通常快得多比打开了一个IRB调试像prybyebug。这些工具并不总是您的第一步。


快速调试Ruby / Rails:

1.快速方法:加一个Exception然后.inspect及其结果

调试Ruby(尤其是Rails)代码的最快方法是raise在调用.inspect方法或对象(例如foo)时沿代码的执行路径出现异常:

raise foo.inspect

在上面的代码中,raise触发一个Exception,以中止代码的执行,并返回一条错误消息,该消息方便地包含.inspect有关foo您要调试的行中的对象/方法(即)的信息。

此技术对于快速检查对象或方法(例如,是否为nil)以及立即确认在给定上下文中是否甚至根本没有执行一行代码很有用。

2.后备:使用ruby IRB调试器,例如byebugpry

仅在获得有关代码执行流状态的信息后,才应考虑使用ruby gem irb调试器,pry或者byebug在该位置可以更深入地研究执行路径中对象的状态。


一般初学者建议

当您尝试调试问题时,始终应遵循以下建议: 阅读!@#$ ing错误消息(RTFM)

这意味着在采取行动之前,请仔细完整阅读错误消息,以使您了解错误要告诉您的内容。 调试时,阅读错误消息时,请按以下顺序依次询问以下心理问题:

  1. 错误引用什么?(即我是否具有正确的对象类或我的对象nil
  2. 错误引用什么方法?(即它们是方法中的类型;我可以在此类型/对象的类上调用此方法吗?
  3. 最后,根据我从前两个问题得出的结论,我应该调查哪些代码行?(请记住:堆栈跟踪中的最后一行代码不一定是问题所在。)

在堆栈跟踪中,应特别注意项目中的代码行(例如,app/...如果您使用的是Rails ,则应以这些行开头)。99%的时间是您自己的代码出问题。


为了说明为什么按此顺序进行翻译很重要...

例如,使许多初学者感到困惑的Ruby错误消息:

您执行某些时候执行的代码,如下所示:

@foo = Foo.new

...

@foo.bar

并且您得到一个错误,指出:

undefined method "bar" for Nil:nilClass

初学者看到这个错误,并认为这个问题是,该方法bar不确定的不是。在此错误中,真正重要的部分是:

for Nil:nilClass

for Nil:nilClass意味着@foo是零! @foo不是Foo实例变量!您有一个对象是Nil。当您看到此错误时,只是红宝石试图告诉您bar该类的对象不存在该方法Nil。(好吧,因为我们正在尝试为Foonot 类的对象使用方法Nil)。

不幸的是,由于此错误的编写方式(undefined method "bar" for Nil:nilClass),很容易使人误以为该错误与barbesing有关undefined。如果不仔细阅读,此错误会导致初学者错误地研究baron上方法的详细信息,从而Foo完全丢失了表明对象属于错误类的错误部分(在本例中为nil)。通过完全读取错误消息可以很容易避免这种错误。

摘要:

在开始任何调试之前,请务必仔细阅读整个错误消息。这意味着:始终检查型的对象的一个错误消息首先,那么它的方法开始侦探到任何堆栈跟踪或代码行,你认为该错误可能发生。那5秒钟可以为您节省5个小时的挫败感。

tl; dr:不要斜视打印日志:引发异常或改用irb调试器。通过在调试之前仔细阅读错误来避免出现兔子洞。


3
尽管我同意阅读打印日志很繁琐,但我认为建议一开始不使用调试器是非常糟糕的建议。添加断点并触发它与引发异常完全相同,但是它可以为您提供应用程序当前状态的完整视图。如果检查可疑状态后还有其他问题,您可以交互式地向下钻取,而不必添加另一个异常并重新启动应用程序。
Patrick R.

2
@PatrickR。以我的经验,当您仍在尝试深入探究代码的问题所在时,IRB调试器并不是一个好的第一步。与添加异常相比,添加和删除许多IRB断点要花费更多的时间,并且无法像初学者一样通过异常排除错误的假设,从而给出关于代码控制流的明确答案。IRB断点也很容易忘记,导致请求挂起时造成混乱。如果您确切地知道问题在哪里并且需要调试其状态,那么可以肯定地说,从IRB调试器开始。但是通常那是不正确的。
Kelsey Hannan

1
哈哈!读取错误消息对于Ruby很有帮助,但是其他脚本语言呢?我不能怪OP没有打扰。
kayleeFrye_onDeck

1
我最初的反应类似于@PatrickR。,但是无论如何我都尝试过。最后,我发现这不是一个好建议,或者按照最好的观点,这是针对与我不同的用例量身定制的建议。特别是在(a)不使用Rails和(b)结果错误但没有引发错误或异常的情况下,即代码计算了一个数字,这就是错误的数字。尝试迭代地猜测在哪里制作要执行崩溃的程序是一种策略,但是由于我必须不断地重新启动并重新运行,因此它的工作量更大。每个周期都有自己的浪费启动时间。

20
  1. 尽可能打印出变量。(这称为printf调试)您可以通过运行

    STDERR.puts x.inspect

    要么

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

    如果要使其更易于键入,则可能要使用示例宝石。

  2. 打开警告。如果您正在运行ruby,请使用-w开关(例如ruby -w script.rb)运行它。如果从irb运行它,并且使用的是1.9.2之前的ruby版本,请$VERBOSE = true在会话开始时键入。如果您拼写错误的实例变量,一旦出现警告,您将得到

    警告:实例变量@valeus未初始化

  3. 了解二进制印章的概念(以下引文来自“敏捷开发人员的实践”

    将问题空间分成两半,然后看看哪一半包含问题。然后再将那一半分成一半,然后重复。

  4. 如果您成功完成了二进制印章,则可能会发现有一行没有完成您期望的操作。例如

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

    给出的值false,即使您认为它会返回true。在这种情况下,您可能需要查看文档。文档网站包括ruby-doc.orgAPIdock。在后一种情况下,您include?可以在右上角附近的放大镜旁边键入内容,然后选择include?其中Array下面的内容(如果您不知道是什么类[1, 2, 3],请输入[1, 2, 3].classirb),然后包括?(数组),它描述了它的作用。

    但是,如果文档无济于事,那么如果您可以问一个问题,即某个特定的行如何不执行应做的事情,而不是为什么整个脚本不执行应做的事情,则您更有可能得到一个很好的答案。这应该。


7

删除所有东西

欢迎来到2017 ^ _ ^

好的,因此,如果您不反对尝试使用新的IDE,则可以免费进行以下操作。

快速说明

  1. 安装vscode
  2. 如果尚未安装Ruby Dev Kit,请安装
  3. 为vscode安装Ruby,ruby-linter和ruby-rubocop扩展
  4. 如果需要,手动安装rubyide / vscode-ruby指定的任何宝石
  5. launch.json使用来配置您要使用的"cwd" "program"字段{workspaceRoot}
  6. 添加一个名为的字段"showDebuggerOutput"并将其设置为true
  7. 在Debug偏好设置中的任何地方启用断点,如下所示: "debug.allowBreakpointsEverywhere": true

详细说明

  1. 下载Visual Studio代码 aka vscode; 这与Visual Studio不同。它是免费的,轻巧的,并且受到普遍好评。
  2. 安装Ruby Dev Kit;您应该在此处按照其仓库中的说明进行操作:https : //github.com/oneclick/rubyinstaller/wiki/Development-Kit
  3. 接下来,您可以通过网络浏览器或在IDE中安装扩展。这是用于IDE内部的。如果选择其他,则可以转到此处。导航到vscode的扩展部分;您可以通过几种方法来执行此操作,但是最适合未来的方法可能是按F1,然后键入ext直到名为Extensions:Install Extensions的选项可用。替代方法是,CtrlShiftx并且从顶部菜单栏中,View->Extensions
  4. 接下来,您将需要以下扩展;这些不是100%必要的,但在您修改了一些内容后,我会让您决定保留什么:
    • 红宝石; 推广作者吕鹏
    • 红宝石色 扩展作者misogi
    • 宝石红宝石 推广作者Cody Hoover
  5. 在您的ruby脚本的目录内,我们将通过名为的命令行创建目录,在该目录.vscode中将有一个名为的文件launch.json,用于存储一些配置选项。
    • launch.json 内容

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

  1. 按照扩展作者的说明进行手动gem安装。它现在位于这里:https : //github.com/rubyide/vscode-ruby#install-ruby-dependencies
  2. 您可能想要将断点放置在任意位置的功能;未启用此选项可能会引起混乱。为此,我们将转到顶部的菜单栏,然后​​选择File->Preferences->Settings(或Ctrl,)并滚动直到找到该Debug部分。展开它并查找一个名为的字段"debug.allowBreakpointsEverywhere"-选择该字段,然后单击带有铅笔外观的小图标并将其设置为true

完成所有有趣的事情之后,您应该能够在类似于2017年中期的菜单中设置断点并进行调试,并且主题更暗:在此处输入图片说明具有所有有趣的东西,例如调用堆栈,变量查看器等。

最大的PITA是1)安装先决条件和2)记住配置.vscode\launch.json文件。只有#2应该在以后的项目中增加任何负担,您只需复制一个足够通用的配置即可,如上面列出的配置。可能有一个更一般的配置位置,但是我不知道该怎么做。


现在是2018年,😉,但不幸的是,您仍然不能使用在此列出的插件调试单元测试。
MonsieurDart '18

1
@MonsieurDart当我写这篇文章时,它是用于Ruby脚本的基本调试。我对单元测试一无所知。如果此答案不正确或过时,请告诉我需要注意的事项以及可以帮助加快处理速度的任何信息。
kayleeFrye_onDeck

嘿@kayleeFrye_onDeck!您的回应很好,我完全同意。但是,上次我检查Peng Lv的VSC Ruby插件时,它无法在单元测试(或任何其他测试)中设置断点。这是该插件的已知限制之一。我认为人们在尝试配置其VSC实例之前需要了解这一点:这需要时间,而且对于许多人而言,运行测试是编写和调试代码的第一方式。😊–
MonsieurDart

6

我强烈推荐该视频,以选择合适的工具来调试我们的代码。

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

我个人将在此视频中重点介绍两个大主题。

  • 撬对调试数据很棒,“撬是数据浏览器”(原文如此)
  • 调试器似乎更好地进行逐步调试。

那是我的两分钱!


6

所有其他答案已经可以提供几乎所有内容……只是一点补充。

如果您想要更多类似IDE的调试器(非CLI)并且不害怕使用Vim作为编辑器,建议您使用Vim Ruby Debugger插件。

它的文档非常简单,因此请点击链接查看。简而言之,它允许您在编辑器中的当前行设置断点,在暂停时在漂亮的窗口中查看局部变量,进入/进入-几乎所有常规调试器功能。

对我来说,使用此vim调试器调试Rails应用程序非常有趣,尽管Rails 丰富的记录器功能几乎消除了对此的需要。


6

我刚刚发现了这个宝石(将Pry变成了MRI Ruby 2.0+的调试器)

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

安装方式:

gem install pry-byebug

然后使用完全一样pry,标记您要在以下位置断开的行:

require 'pry'; binding.pry

与香草撬然而,这种宝石有一些关键的GDB般的导航命令,例如nextstepbreak

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. 您可以一路打印出变量
  2. 打开-w(警告)标志
  3. 使用诸如ruby-debug的工具

2
我要补充一点,这irb是一个很好的起点。尝试将irb与可疑的小块一起使用。我喜欢ruby-debug(Ruby 1.9+的ruby-debug19),因为它可以轻松停止正在运行的程序,检查变量,放入irb,然后继续运行。
Tin Man

5

要轻松调试Ruby Shell脚本,只需将其第一行更改为:

#!/usr/bin/env ruby

至:

#!/usr/bin/env ruby -rdebug

然后,每当显示调试器控制台时,您都可以选择:

  • c对于继续(到下一个异常,断点或以下行:)debugger
  • n 对于下一行,
  • w/ where显示框架/调用堆栈,
  • l 显示当前代码,
  • cat 显示要点。
  • h 寻求更多帮助。

另请参阅:使用ruby-debug进行调试ruby-debug gem的关键快捷方式


如果脚本刚刚挂起并且您需要回溯,请尝试使用lldb/ gdblike:

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

然后检查您的进程前景。

如果效果更好,请替换lldbgdb。带有sudo调试非自有进程的前缀。


1
红宝石调试看起来很陈旧。ruby-debug的git repo 今年只有一次提交-是否仍在积极维护?
Andrew Grimm

它也似乎与红宝石包装在一起,当您处于紧要关头时,这很棒。好答案!
育种的

5

从Ruby 2.4.0开始,在任何Ruby程序的中间启动IRB REPL会话都更加容易。将这些行放在要调试的程序中:

require 'irb'
binding.irb

您可以运行Ruby代码并打印出局部变量。输入Ctrl + D或quit结束REPL,让Ruby程序继续运行。

您还可以在程序运行时使用putsp从程序中打印出值。


4

如果您使用的是RubyMine,则调试ruby脚本非常简单明了。

假设您有一个Ruby脚本hello_world.rb

1.设置断点

在第6行设置一个断点,如下所示。

在此处输入图片说明

2.开始调试

现在,您只需启动调试器即可运行脚本:

在此处输入图片说明

在此处输入图片说明

3.检查变量等

然后,当执行达到断点时,您将能够检查变量等。

在此处输入图片说明

更多信息供您参考

  1. 如果您想使用RubyMine进行远程调试,则可以这样做。
  2. 如果您想使用RubyMine来远程调试在docker内部运行的rails,那么它也很简单。

我们是否可以在RubyMine中调试外部库?
Am33d

2

printf调试

围绕调试技术一直存在争议,有些人喜欢通过打印语句进行调试,另一些人喜欢使用调试器进行深入研究。

我建议您尝试两种方法。

实际上,最近有一位老Unix人说过,在某些时候,printf调试对他来说是一种更快的方法。

但是,如果您是新手,并且需要了解大量的代码,那么遍历整个过程,在其中到处放置一些断点,以及它的工作原理确实很有用。

它应该使您了解如何编织代码。

如果您不熟悉其他人的软件,它可能会帮助您逐步完成。

您会很快发现他们是否以巧妙的方式安排了它,或者仅仅是一堆狗屎。


毫无疑问,这是最好的答案,这取决于
menriquez


1

所有调试器的母亲都是普通的旧印刷屏幕。大多数时候,您可能只想检查一些简单的对象,一种快速简便的方法是这样的:

@result = fetch_result

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

这会将@result的内容打印到STDOUT并在前面加一行以便于识别。

如果使用诸如Rails之类的具有自动加载/重新加载功能的框架,您将无需再重新启动应用程序。(除非由于框架特定的设置而没有重新加载正在调试的代码)

我发现这对我90%的用例有效。您也可以使用ruby-debug,但是我发现大多数时候它都过分杀了。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.