如何调试 Ruby 脚本

我从互联网上复制了下面的 Ruby 代码,并做了一些修改,但是没有用。

我可以做什么来自己调试程序?

180898 次浏览
  1. 只要有可能就打印出变量(这叫做 printf 调试)

    STDERR.puts x.inspect
    

    或者

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

    如果您想使输入变得更容易,那么您可能需要使用 样本 gem。

  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?,选择下面有 Arrayinclude?(如果你不知道 [1, 2, 3]是什么类,在 irb 中输入 [1, 2, 3].class) ,然后你就可以输入 包括? (数组),它描述了它的功能。

    但是,如果文档没有帮助,那么如果您可以问一个问题,即某一行为什么没有做它应该做的事情,而不是为什么整个脚本没有做它应该做的事情,那么您更有可能得到一个好的答案。

  1. 您可以在这个过程中打印出您的变量
  2. 打开 -w(警告)标志
  3. 使用诸如 Ruby-debug之类的工具
  1. 在 Ruby 中:

    ruby -rdebug myscript.rb
    

    那么,

    • 设置断点
    • 以及 n(ext)s(tep)c(ontinue)
    • p(uts)显示

    (像 perl debug)

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

    script/server --debugger
    

    并在代码中添加 debugger

所有调试器之母是普通的旧打印屏幕。大多数时候,你可能只想检查一些简单的物品,一个快速简单的方法是这样的:

@result = fetch_result


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

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

如果你使用像 Rails 这样的自动加载/重载框架,你甚至不需要重新启动你的应用程序。(除非由于框架特定的设置而没有重新加载正在调试的代码)

我发现90% 的用例都是这样的。您也可以使用 ruby-debug,但是我发现它大多数时候都是过度使用。

使用 窥探(GitHub)。

安装:

$ gem install pry
$ pry

然后加上:

require 'pry'; binding.pry

进入你的程序。

但是,在 pry0.12.2中,没有像 nextbreak等这样的导航命令。其他一些 gem 还提供了这个功能,例如 pry-byebug

所有其他的答案已经给出了几乎所有的东西... 只是一点点补充。

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

它的文档非常简单,请点击链接查看。简而言之,它允许您在编辑器的当前行上设置断点,在暂停时在漂亮的窗口中查看本地变量,单步执行(step over/into)ーー几乎所有常见的调试器特性。

对我来说,使用这个 vim 调试器来调试一个 Rails 应用程序是非常愉快的,尽管 Rails 的 丰富的记录能力几乎消除了对它的需要。

根据栏杆的建议: 使用撬! 我只能同意这一点。

窥探比 IRB 好得多。

你得加上

require 'pry'

你的源文件 然后在源代码中插入断点

binding.pry

在你想看东西的地方 (这就像在经典的 IDE 环境中触发断点一样)

一旦你的程序触发了

binding.pry

你会被直接扔进监听室, 手边有你们节目的全部内容, 这样你就可以简单地探索周围的一切,研究所有的物体, 更改状态,甚至动态更改代码。

我相信你不能改变你现在使用的方法的代码, 所以很遗憾你不能改变下一行要执行的内容。 但是好的 Ruby 代码往往是单行的; -)

Printf 调试

调试技术一直存在争议, 有些人喜欢使用 print 语句进行调试, 还有一些人喜欢用调试器深入挖掘。

我建议你两种方法都试试。

事实上,一个 Unix 的老前辈最近说过, 在某些时候 printf 调试对他来说是更快的方法。

但是,如果您在某个工作中是新手,并且需要理解大量代码, 那么穿过这里真的很有用, 到处设置断点, 顺其自然。

它应该可以让您了解代码是如何编织的。

如果你对其他人的软件是新手, 也许能帮你穿过那里。

你很快就会知道他们是不是巧妙地安排了, 或者那只是一堆狗屎。

我强烈推荐这个视频,以便选择适当的工具,目前调试我们的代码。

Https://www.youtube.com/watch?v=gwgf8gcynv0

就我个人而言,我会在这个视频中强调两大主题。

  • Pry 对于调试数据来说非常棒,“ Pry 是一个数据浏览器”(原文如此)
  • 调试器似乎更适合逐步调试。

这就是我的意见!

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

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

安装:

gem install pry-byebug

然后使用与 pry完全相同的方法,在你想要中断的线上标记:

require 'pry'; binding.pry

然而,与香草撬不同的是,这个 gem 有一些类似于 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.

通过引发异常 进行调试比仔细查看 print日志语句要好,而且对于大多数 bug 来说,它通常比打开像 prybyebug这样的 irb 调试器要好。这些工具不应该总是你的第一步。


快速调试 Ruby/Rails:

1. 快速方法: 提出一个 Exception然后和 .inspect它的结果

调试 Ruby (特别是 Rails)代码的 最快方法是在调用方法或对象(例如 foo)上的 .inspect时,沿着代码的执行路径调用 raise:

raise foo.inspect

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

这种技术对于 快点检查对象或方法(nil吗?)以及立即确认一行代码是否在给定的上下文中执行非常有用。

2. 后备: 使用像 byebugpry这样的 Ruby IRB调试器

只有在您了解了代码执行流的状态之后,您才应该考虑转移到像 prybyebug这样的 ruby gem irb 调试器,在这里您可以更深入地研究执行路径中对象的状态。


一般初学者建议

当您试图调试一个问题时,好的建议是始终: 阅读!@# $ing 错误消息(RTFM)

这意味着在操作之前读取错误消息 小心点彻底的,这样当你调试时,在读取错误消息时问下面的心理问题 按这个顺序:

  1. 错误引用 类别是什么? (即 我有正确的对象类还是我的对象 nil)
  2. 错误引用 方法是什么? (即 它们是否是方法中的类型; 我可以在这个类型/类的对象上调用这个方法吗?)
  3. 最后,根据我最后两个问题的推断,我应该调查什么 代码行?(记住: 堆栈跟踪中的最后一行代码不一定是问题所在。)

在堆栈跟踪中,要特别注意来自项目的代码行(例如,如果使用 Rails,以 app/...开头的行)。99% 的情况下,问题都出在您自己的代码上。


为了说明为什么翻译 按这个顺序很重要..。

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

您执行的代码在某些时候也是这样执行的:

@foo = Foo.new


...


@foo.bar

你会得到一个错误:

undefined method "bar" for Nil:nilClass

初学者看到这个错误,认为问题在于方法 bar未定义。在这个错误中,真正重要的部分是:

for Nil:nilClass

for Nil:nilClass意味着 @foo是零!@foo不是 Foo实例变量!有一个对象是 Nil。当您看到这个错误时,只是 Ruby 试图告诉您类 Nil的对象的方法 bar不存在。(当然!因为我们试图为类 Foo的一个对象而不是 Nil使用一个方法)。

不幸的是,由于这个错误是如何编写的(undefined method "bar" for Nil:nilClass) ,它很容易被欺骗,以为这个错误与 barundefined有关。如果不仔细阅读,这个错误会导致初学者错误地深入研究 Foo上的 bar方法的细节,完全忽略错误提示对象属于错误类(在本例中为 nil)的部分。通过完整地读取错误消息,很容易避免这种错误。

摘要:

在开始任何调试之前都要小心地使用 读取 < em > whole 错误消息。这意味着: 始终在错误消息 第一中检查对象的 类别类型,然后检查它的 方法之前,开始侦查任何你认为可能发生错误的堆栈跟踪或代码行。这5秒钟可以帮你节省5个小时的沮丧。

不要关注打印日志: 引发异常或者使用 irb 调试器。在调试之前仔细阅读错误以避免兔子洞。

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

#!/usr/bin/env ruby

致:

#!/usr/bin/env ruby -rdebug

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

  • c表示继续(到下一个异常、断点或带有: debugger的行) ,
  • 下一行的 n,
  • 显示帧/调用堆栈,
  • 显示当前代码,
  • cat显示捕捉点。
  • h寻求更多帮助。

参见: 使用 ruby-debug 进行调试Ruby-debug gem 的关键快捷方式


如果脚本只是 挂起来,你需要一个回溯,尝试使用 lldb/gdb,比如:

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

然后检查你的过程前景。

如果效果更好的话,用 gdb代替 lldb。前缀用 sudo来调试非自有进程。

Ruby 标准 lib 有一个类似 gdb 的易用控制台调试器: Http://ruby-doc.org/stdlib-2.1.0/libdoc/debug/rdoc/debugger__.html 不需要安装任何额外的 gem。 Rails 脚本也可以这样调试。

例如:。

def say(word)
require 'debug'
puts word
end

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

require 'irb'
binding.irb

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

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

删除所有的东西

欢迎来到2017 ^ _ ^

好的,如果您不反对尝试新的 IDE,那么可以为 自由执行以下操作。

快速说明

  1. 安装 vscode
  2. 如果您还没有安装 Ruby 开发工具包,请安装它
  3. 为 vscode 安装 Ruby、 Ruby-linter 和 Ruby-rubopolice 扩展
  4. 如果需要,手动安装任何宝石 Rubyide/vscode-ruby 指定
  5. 使用 {workspaceRoot}宏将 launch.json配置为使用 "cwd"还有 "program"字段
  6. 添加一个名为 "showDebuggerOutput"的字段,并将其设置为 true
  7. "debug.allowBreakpointsEverywhere": true的形式在“调试”首选项中的所有位置启用断点

详细说明

  1. 下载 VisualStudio 代码又名 vscode; 这和 视觉工作室不一样。它是免费的,轻量级的,并且通常受到正面评价。
  2. 安装 Ruby 开发工具包; 您应该按照他们的回购说明在这里: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
  3. 接下来,您可以通过 Web 浏览器安装扩展,也可以在 IDE 内部安装扩展; 这是针对 IDE 内部的。如果你选择其他,你可以走 给你。导航到 vscode 的扩展部分; 您可以通过几种方法来完成这项工作,但是最适合未来的方法可能是按 F1键,然后键入 ext,直到有一个名为 扩展: 安装扩展的选项可用。可供选择的是 CtrlShiftx和从顶部菜单栏,View->Extensions
  4. 接下来你会想要以下的扩展,这些并不是100% 必要的,但是我会让你在修改之后决定保留什么:
    • Ruby; 扩展作者 Peng Lv
    • Ruby-rubocop. 扩展作者 Misogi
    • 红宝石衬里; 扩展作者科迪胡佛
  5. 在 Ruby 脚本的目录中,我们将通过命令行 .vscode创建一个目录,在这里,我们将创建一个名为 launch.json的文件,在这个文件中我们将存储一些配置选项。
    • launch.json内容物

{ “版本”: “0.2.0” “配置”: [ { “名称”: “调试本地文件”, “ type”“ Ruby” “请求”“发射” “ cwd”: “ ${ workspaceRoot }”, “ program”: “{ workspaceRoot }/. ./script _ name. rb”, “ args”: [] , “ showDebuggerOutput”: true } ] }

  1. 按照扩展作者的说明进行手动 gem 安装
  2. 您可能希望能够将断点放在任何您喜欢的地方; 不启用此选项可能会导致混淆。为此,我们将转到顶部菜单栏,选择 File->Preferences->Settings(或 Ctrl,)并滚动到 Debug部分。展开它,查找一个名为 "debug.allowBreakpointsEverywhere"的字段——选择该字段并单击看起来像铅笔的小图标,将其设置为 true

在做完所有这些有趣的事情之后,你应该能够在一个菜单中设置断点和调试,这个菜单与2017年中期类似,并且有一个更黑暗的主题: < img src = “ https://i.stack.imgur.com/1zCb2.jpg”alt = “ enter image description here”> < img src = “ https://i.stack.imgur.com/1zCb2.jpg”alt = “ enter image description here”> 和所有有趣的东西,比如你的调用堆栈,变量查看器,等等。

最大的 PITA 是1)安装前置要求和2)记住配置 .vscode\launch.json文件。只有 # 2应该为未来的项目添加任何负担,您只需复制一个足够通用的配置,就像上面列出的那样。可能有一个更通用的配置位置,但我不知道我的头顶。

有许多具有不同特性的调试器,您可以根据这些特性进行选择。我对 多管闲事感到满意的优先事项是:

  • 关于如何使用的快速易懂的信息
  • 直观的步骤(如轻松地踏入块)
  • “后退”(窥探动作部分满足需要)

如果您使用的是 RubyMine,那么调试 Ruby 脚本是简单而直接的。

假设您有一个 Ruby 脚本 hello _ world. rb

1. 设置断点

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

enter image description here

2. 开始调试

现在可以启动调试器来运行脚本:

enter image description here

enter image description here

3. 检查变量等。

然后,当执行命中一个断点时,您就可以检查变量,等等。

enter image description here

进一步资料,以供参考

  1. 如果你想要 使用 RubyMine 进行远程调试,你可以这样做。
  2. 如果你想 使用 RubyMine 远程调试码头内部运行的轨道,它也是直接的。