Debugging with Pry
A PRIMER
Let's start with something simple
$ cat Gemfile
source 'https://rubygems.org'
gem 'pry'
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
class Foo
def bar
puts "Bar!"
end
def self.bar
puts "Baz!"
end
end
a = 2 + 2
binding.pry
ls
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 16 :
11: end
12: end
13:
14: a = 2 + 2
15:
=> 16: binding.pry
[1] pry(main)> ls
self.methods: inspect to_s
locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_ a
[2] pry(main)> a
=> 4
cd
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 16 :
11: end
12: end
13:
14: a = 2 + 2
15:
=> 16: binding.pry
[1] pry(main)> cd Foo
[2] pry(Foo):1> ls
Foo.methods: bar
Foo#methods: bar
locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
show-method
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 16 :
11: end
12: end
13:
14: a = 2 + 2
15:
=> 16: binding.pry
[1] pry(main)> show-method Foo#bar
From: script.rb @ line 6:
Owner: Foo
Visibility: public
Number of lines: 3
def bar
puts "Bar!"
end
[2] pry(main)>
show-method
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 16 :
11: end
12: end
13:
14: a = 2 + 2
15:
=> 16: binding.pry
[1] pry(main)> show-method Foo.bar
From: script.rb @ line 9:
Owner: #<Class:Foo>
Visibility: public
Number of lines: 3
def self.bar
puts "Baz!"
end
show-method
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 16 :
11: end
12: end
13:
14: a = 2 + 2
15:
=> 16: binding.pry
[1] pry(main)> cd Foo
[2] pry(Foo):1> show-method self.bar
From: script.rb @ line 9:
Owner: #<Class:Foo>
Visibility: public
Number of lines: 3
def self.bar
puts "Baz!"
end
show-method -s
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
class Foo
def hello
"Foo"
end
end
class Bar < Foo
def hello
super + " Bar"
end
end
binding.pry
show-method -s
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12: def hello
13: super + " Bar"
14: end
15: end
16:
=> 17: binding.pry
[1] pry(main)> show-method Bar#hello
From: script.rb @ line 12:
Owner: Bar
Visibility: public
Number of lines: 3
def hello
super + " Bar"
end
show-method -s
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12: def hello
13: super + " Bar"
14: end
15: end
16:
=> 17: binding.pry
[1] pry(main)> show-method -s Bar#hello
From: script.rb @ line 6:
Owner: Foo
Visibility: public
Number of lines: 3
def hello
"Foo"
end
wtf?
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
a = [ 1, 2, 3, 4 ]
binding.pry
wtf?
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12:
13: def baz
14: bar
15: end
16:
=> 17: binding.pry
[1] pry(main)> baz
RuntimeError: Error!!!
from script.rb:6:in `foo'
[2] pry(main)> wtf?
Exception: RuntimeError: Error!!!
--
0: script.rb:6:in `foo'
1: script.rb:10:in `bar'
2: script.rb:14:in `baz'
3: (pry):1:in `<main>'
4: /Users/matyas/.rvm/gems/ruby-2.3.3/gems/pry-0.10.4/lib/pry/pry_instance.rb:355:in `eval'
5: /Users/matyas/.rvm/gems/ruby-2.3.3/gems/pry-0.10.4/lib/pry/pry_instance.rb:355:in `evaluate_ruby'
// etc
watch
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
class Foo
attr_reader :counter
def initialize
@counter = 1
end
def add
@counter += 1
end
end
binding.pry
watch
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 15 :
10: def add
11: @counter += 1
12: end
13: end
14:
=> 15: binding.pry
[1] pry(main)> foo = Foo.new
=> #<Foo:0x007fc68fa16410 @counter=1>
[2] pry(main)> watch foo.counter
Watching foo.counter
watch: foo.counter => 1
[3] pry(main)> a = 2 + 2
=> 4
[4] pry(main)> foo.add
watch: foo.counter => 2
=> 2
hist
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
a = [ 1, 2, 3, 4 ]
binding.pry
hist
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4 ]
=> 6: binding.pry
[1] pry(main)> a.map do |value|
[1] pry(main)* value = value * 2
[1] pry(main)* value + 5
[1] pry(main)* end
=> [7, 9, 11, 13]
[2] pry(main)> hist
1: a.map do |value|
2: value = value * 2
3: value + 5
4: end
hist
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4 ]
=> 6: binding.pry
[1] pry(main)> a.map do |value|
[1] pry(main)* value = value * 2
[1] pry(main)* value + 5
[1] pry(main)* end
=> [7, 9, 11, 13]
[2] pry(main)> hist
1: a.map do |value|
2: value = value * 2
3: value + 5
4: end
[3] pry(main)> hist --replay 1..4
=> [8, 9, 10, 11]
hist
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4 ]
=> 6: binding.pry
[1] pry(main)> a.map do |value|
[1] pry(main)* value += 5
[1] pry(main)* end
=> [6, 7, 8, 9]
[2] pry(main)> hist --save 1..3 temp_script.rb
Saving history in /Users/matyas/htdocs/pry-talk/temp_script.rb...
History saved.
[3] pry(main)> exit
$ cat temp_script.rb
a.map do |value|
value += 5
end
shell integration
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4 ]
=> 6: binding.pry
[1] pry(main)> .cat temp_script.rb
a.map do |value|
value += 5
end
[2] pry(main)> .ls
Gemfile Gemfile.lock script.rb temp_script.rb
inline editing
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4 ]
=> 6: binding.pry
[1] pry(main)> edit script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 :
1: require 'bundler/setup'
2: Bundler.setup
3: require 'pry'
4:
5: a = [ 1, 2, 3, 4, 5 ]
=> 6: binding.pry
inline editing
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 9 :
4:
5: def foo
6: puts "Foo!"
7: end
8:
=> 9: binding.pry
[1] pry(main)> edit foo
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 9 :
4:
5: def foo
6: puts "Foobar!"
7: end
8:
=> 9: binding.pry
disabling pry on future calls
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
a = (1...10).to_a
a.map do |a|
a += 1
binding.pry
end
puts a.inspect
disabling pry on future calls
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 :
2: Bundler.setup
3: require 'pry'
4:
5: a = (1..10).to_a
6: a.map do |a|
=> 7: binding.pry
8: a += 1
9: end
10:
11: puts a.inspect
[1] pry(main)> exit
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 :
2: Bundler.setup
3: require 'pry'
4:
// etc
disabling pry on future calls
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 9 :
4:
5: a = (1...10).to_a
6: a.map do |a|
7: a += 1
8: binding.pry
=> 9: end
10:
11: puts a.inspect
[1] pry(main)> disable-pry
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Using pry-byebug
$ cat Gemfile
source 'https://rubygems.org'
gem 'pry'
gem 'pry-byebug'
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
def foo
binding.pry
end
def bar
foo
end
def baz
bar
end
baz
BE CAREFUL!
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
a = 2 + 2
# This will not work properly and will either quit or jump to a frame
# somewhere in pry-byebug code. Always have at least one additional
# line of code after binding.pry when using pry-byebug
binding.pry
Pry-byebug: moving around stacktrace
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 Object#foo:
5: def foo
6: binding.pry
=> 7: end
[1] pry(main)> up
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 10 Object#bar:
9: def bar
=> 10: foo
11: end
[1] pry(main)> down
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 Object#foo:
5: def foo
6: binding.pry
=> 7: end
Pry-byebug: moving around stacktrace
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 Object#foo:
5: def foo
6: binding.pry
=> 7: end
[1] pry(main)> frame 3
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12:
13: def baz
14: bar
15: end
16:
=> 17: baz
[1] pry(main)>
Pry-byebug: stepping through code
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
def foo
binding.pry
a = 0
a += 1
a += 2
a
end
foo
Pry-byebug: stepping through code
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 7 Object#foo:
5: def foo
6: binding.pry
=> 7: a = 0
8: a += 1
9: a += 2
10: a
11: end
[1] pry(main)> a
=> nil
Pry-byebug: stepping through code
[2] pry(main)> step
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 8 Object#foo:
5: def foo
6: binding.pry
7: a = 0
=> 8: a += 1
9: a += 2
10: a
11: end
[2] pry(main)> a
=> 0
Pry-byebug: stepping through code
[3] pry(main)> step
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 9 Object#foo:
5: def foo
6: binding.pry
7: a = 0
8: a += 1
=> 9: a += 2
10: a
11: end
[3] pry(main)> a
=> 1
Pry-byebug: stepping through code
[4] pry(main)> step
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 10 Object#foo:
5: def foo
6: binding.pry
7: a = 0
8: a += 1
9: a += 2
=> 10: a
11: end
[4] pry(main)> a
=> 3
Pry-byebug: breakpoints
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
class Foo
def bar
puts "Bar?"
end
def baz
bar
end
end
binding.pry
foo = Foo.new
foo.baz
Pry-byebug: breakpoints
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12: end
13: end
14:
15: binding.pry
16:
=> 17: foo = Foo.new
18: foo.baz
19:
20:
21:
[1] pry(main)> break Foo#bar
Breakpoint 1: Foo#bar (Enabled)
6: def bar
7: puts "Bar?"
8: end
Pry-byebug: breakpoints
[2] pry(main)> continue
Breakpoint 1. First hit
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 6 Foo#bar:
=> 6: def bar
7: puts "Bar?"
8: end
[2] pry(#<Foo>)>
Pry-byebug: breakpoints
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 17 :
12: end
13: end
14:
15: binding.pry
16:
=> 17: foo = Foo.new
18: foo.baz
[1] pry(main)> break 11
Breakpoint 1: /Users/matyas/htdocs/pry-talk/script.rb @ 11 (Enabled)
8: end
9:
10: def baz
=> 11: bar
12: end
13: end
14:
Pry-byebug: breakpoints
[2] pry(#<Foo>)> break
# Enabled At
-------------
1 Yes /Users/matyas/htdocs/pry-talk/script.rb @ 11
[3] pry(#<Foo>)>
THIS MIGHT BE CONFUSING
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
class Foo
def bar
puts "Bar?"
end
end
binding.pry
true #byebug
THIS MIGHT BE CONFUSING
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 12 :
7: puts "Bar?"
8: end
9: end
10:
11: binding.pry
=> 12: true #byebug
[1] pry(main)> break Foo#bar
Breakpoint 1: Foo#bar (Enabled)
6: def bar
7: puts "Bar?"
8: end
[2] pry(main)> Foo.new.bar
Bar?
=> nil
[3] pry(main)>
# Breakpoints only work if you let the script continue
# not when you're running the code by hand in REPL.
Bonus: pry-inline
$ cat Gemfile
source 'https://rubygems.org'
gem 'pry'
gem 'pry-byebug'
gem 'pry-inline'
$ cat script.rb
require 'bundler/setup'
Bundler.setup
require 'pry'
a = 10
b = a * 2
c = b ** 3
binding.pry
true #byebug
Bonus: pry-inline
$ ruby script.rb
From: /Users/matyas/htdocs/pry-talk/script.rb @ line 10 :
5: a = 10 # a: 10
6: b = a * 2 # b: 20
7: c = b ** 3 # c: 8000
8:
9: binding.pry
=> 10: true #byebug
[1] pry(main)>
There was going to be a slide
explaining why pry-rescue is amazing
Unfortunately it doesn't work correctly
with pry-byebug at the moment :(
If you are OK with this then definitely give it a try though!
Thank you for listening!
@nerdblogpl
http://nerdblog.pl
Debugging with Pry
By Michał Matyas
Debugging with Pry
- 700