Larry’s Blog

Use Pry Instead of IRB

| Comments

IRB 作为原生的 Ruby 交互式解释器,给每个 Rubyist 调试程序时都提供了极大的便利,包括 Rails console 都是构建在 IRB 之上。

但是有一款工具功能更加强大使用更加方便,那就是目前 Ruby 社区中很火的 Pry。现在是时候放弃使用 IRB 了。

Installation

Pry 的安装非常简单,因为它本身就是一个 gem. gem install pry (如果使用 rbenv 管理 Ruby 环境的话,别忘记 rbenv rehash)

然后运行 pry, 就可以像 irb 一样执行 Ruby 代码了。

Usage

0. Code Highlight & Indent

使用 irb 时很头疼的一点就是定义一个类/方法时,代码没有缩进,很容易写了好几行代码然后发现写错了不得不重头再写起。

使用 Pry 则完全不用担心这种问题,换行时会自动缩进,而且支持代码高亮。如下图:

1. Changing scope with cd

调试代码时有时需要改变 self, 比如查看某个对象内部没有读写方法的变量或者在类内部定义方法,这个时候就得或者使用 eval 系方法来搞定,或者打开类 class A 然后再执行操作。在 Pry 中,完全可以使用 cd 命令来搞定,就像 *nix shell 一样。

2. ls

另外,就像 *nix shell 一样,你还可以通过 ls 命令来列举当前 context 下的变量与方法。

1
2
3
4
5
6
[15] pry(main)> cd Foo
[16] pry(Foo):1> self
=> Foo
[17] pry(Foo):1> ls
Foo#methods: wtf
locals: _  _dir_  _ex_  _file_  _in_  _out_  _pry_  binding_impl_method

ls -h 可以查看 ls 支持的所有参数及作用。

3. show-method find-method

顾名思义,show-methodfind-method 两个命令一个用来显示某方法的定义,一个用来查找方法的定义。

4. edit-method

edit-method 命令会打开你的编辑器,当你输入完代码退出后,Pry 会将编辑器中的代码 load 进当前环境。这个功能还是相当的方便的,虽然在 Pry 中支持 amend-line 来修改当前的 input buffer,但毕竟还是在自己熟悉的编辑器中修改代码要方便的多。关于在 Pry 中输入这里可以参考 Pry Wiki: User Input

5. User Pry with Rails

在 Rails 项目主目录下,pry -r ./config/environment。如果希望 pry 自动加载 Rails 环境,可以参考 Pry Wiki中的方法,在 Home 目录添加 .pryrc 文件:

.pryrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Load plugins (only those I whitelist)
Pry.config.should_load_plugins = false
Pry.plugins["doc"].activate!

# Launch Pry with access to the entire Rails stack.
# If you have Pry in your Gemfile, you can pass: ./script/console --irb=pry instead.
# If you don't, you can load it through the lines below :)
rails = File.join Dir.getwd, 'config', 'environment.rb'

if File.exist?(rails) && ENV['SKIP_RAILS'].nil?
  require rails

  if Rails.version[0..0] == "2"
    require 'console_app'
    require 'console_with_helpers'
  elsif Rails.version[0..0] == "3"
    require 'rails/console/app'
    require 'rails/console/helpers'
  else
    warn "[WARN] cannot load Rails console commands (Not on Rails2 or Rails3?)"
  end
end

(我已经将 pryrc 放在了我的 dotfiles, check it out.)

6. binding.pry

如果仅仅是这些功能,似乎还不能说 Pry 可以秒杀 IRB。但是了解了 binding.pry 这个功能后,就会明白 Pry 真正的强大之处了。

test_binding.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
require 'pry'

class A
  def hello() puts "hello world!" end
end

a = A.new

# start a REPL session
binding.pry

# program resumes here (after pry session)
puts "program resumes here."

当代码执行到第10行时,会开启一个 Pry session,就像直接在命令行执行 pry 一样,只不过当前的 contextbinding.pry 这行代码所在处的 context。然后我们可以在 Pry 中像下面一样调试:

pry-session
1
2
3
4
5
6
7
8
9
10
11
12
13
pry(main)> a.hello
hello world!
=> nil
pry(main)> def a.goodbye
pry(main)*   puts "goodbye cruel world!"
pry(main)* end
=> nil
pry(main)> a.goodbye
goodbye cruel world!
=> nil
pry(main)> exit

program resumes here.

binding.pry 搭配 Rails 使用时跟上述实例并无太大区别,不同的是如果在 controller 中插入 binding.pry,那么当该 controller 接收到请求时,rails server 会开启一个 Pry session,供开发者调试。

article_controller.rb
1
2
3
4
5
class ArticleController < ApplcationController
  def show
    @article = Article.find(params[:id])
    binding.pry
  end

当浏览器中打开 http://localhost:3000/article/42 时,Pry session 就会被开启,像下面这样:

rails-pry-session
1
2
3
4
5
6
7
8
9
10
11
From: /Users/eifion/blog/app/controllers/articles_controller.rb @ line 8 in ArticlesController#index:

     1: class ArticlesController < ApplicationController
     2:   def index
     3:     @articles = Article.all
     4:   end
     5:
     6:   def show
     7:     @article = Article.find(params[:id])
 =>  8:     binding.pry
     9:   end

这时候我们就可以查看 @article 对象的值了。binding.pry 对于调试的作用不言而喻,省去了在 controller 中污染环境的打印各种变量的代码。

Conclusion

So, time to drop IRB and use Pry instead. It Really Rocks!

相关链接:

Comments