To help deal with bugs, the standard distribution of Ruby includes a debugger. In order to start the Ruby debugger, load the debug library using the command-line option -r debug. The debugger stops before the first line of executable code and asks for the input of user commands.
Use Pry (GitHub).
Install via:
$ gem install pry
$ pry
Then add:
require 'pry'; binding.pry
into your program.
As of pry
0.12.2 however, there are no navigation commands such as next
, break
, etc. Some other gems additionally provide this, see for example pry-byebug
.
In Ruby:
ruby -rdebug myscript.rb
then,
b <line>
: put break-point n(ext)
or s(tep)
and c(ontinue)
p(uts)
for display(like perl debug)
In Rails: Launch the server with
script/server --debugger
and add debugger
in the code.
As banister recommended: use pry! I can only agree on this.
pry is a much better repl than irb.
You need to add
require 'pry'
to your source file and then insert a breakpoint in your source code by adding
binding.pry
at the place where you want to have a look at the things (this is like triggering a breakpoint in a classic IDE environment)
Once your program hits the
binding.pry
line, you'll be thrown right into the pry repl, with all the context of your program right at hand, so that you can simply explore everything around, investigate all objects, change state, and even change code on the fly.
I believe you can not change the code of the method that you are currently in, so you can sadly not change the next line to be executed. But good ruby code tends to be single line anyway ;-)
Debugging by raising exceptions is far easier than squinting through print
log statements, and for most bugs, its generally much faster than opening up an irb debugger like pry
or byebug
. Those tools should not always be your first step.
Exception
then and .inspect
its resultThe fastest way to debug Ruby (especially Rails) code is to raise
an exception along the execution path of your code while calling .inspect
on the method or object (e.g. foo
):
raise foo.inspect
In the above code, raise
triggers an Exception
that halts execution of your code, and returns an error message that conveniently contains .inspect
information about the object/method (i.e. foo
) on the line that you're trying to debug.
This technique is useful for quickly examining an object or method (e.g. is it nil
?) and for immediately confirming whether a line of code is even getting executed at all within a given context.
byebug
or pry
Only after you have information about the state of your codes execution flow should you consider moving to a ruby gem irb debugger like pry
or byebug
where you can delve more deeply into the state of objects within your execution path.
When you are trying to debug a problem, good advice is to always: Read The !@#$ing Error Message (RTFM)
That means reading error messages carefully and completely before acting so that you understand what it's trying to tell you. When you debug, ask the following mental questions, in this order, when reading an error message:
nil
?) In the stack trace pay particular attention to lines of code that come from your project (e.g. lines starting with app/...
if you are using Rails). 99% of the time the problem is with your own code.
To illustrate why interpreting in this order is important...
You execute code that at some point executes as such:
@foo = Foo.new
...
@foo.bar
and you get an error that states:
undefined method "bar" for Nil:nilClass
Beginners see this error and think the problem is that the method bar
is undefined. It's not. In this error the real part that matters is:
for Nil:nilClass
for Nil:nilClass
means that @foo
is Nil! @foo
is not a Foo
instance variable! You have an object that is Nil
. When you see this error, it's simply ruby trying to tell you that the method bar
doesn't exist for objects of the class Nil
. (well duh! since we are trying to use a method for an object of the class Foo
not Nil
).
Unfortunately, due to how this error is written (undefined method "bar" for Nil:nilClass
) its easy to get tricked into thinking this error has to do with bar
being undefined
. When not read carefully this error causes beginners to mistakenly go digging into the details of the bar
method on Foo
, entirely missing the part of the error that hints that the object is of the wrong class (in this case: nil). It's a mistake that's easily avoided by reading error messages in their entirety.
Summary:
Always carefully read the entire error message before beginning any debugging. That means: Always check the class type of an object in an error message first, then its methods, before you begin sleuthing into any stacktrace or line of code where you think the error may be occurring. Those 5 seconds can save you 5 hours of frustration.
tl;dr: Don't squint at print logs: raise exceptions or use an irb debugger instead. Avoid rabbit holes by reading errors carefully before debugging.
Print out the variables whenever possible. (This is called printf debugging) You can do this by running
STDERR.puts x.inspect
or
STDERR.puts "Variable x is #{x.inspect}"
If you want to make this easier to type, then you may want to use the exemplor gem.
Turn warnings on. If you're running ruby
then run it with the -w
switch (eg ruby -w script.rb
). If you're running it from irb, and you're using a version of ruby prior to 1.9.2, type $VERBOSE = true
at the start of your session. If you misspell an instance variable, once warnings are on you'll get
warning: instance variable
@valeus
not initialized
Understand the concept of a binary chop (the following quote is from Practices of an Agile Developer)
Divide the problem space in half, and see which half contains the problem. Then divide that half in half again, and repeat.
If you're successful with a binary chop, you may find that there's a single line that doesn't do what you expect it to do. For example
[1, 2, 3].include?([1,2])
gives a value of false
, even though you'd think it'd return true
. In that case, you may want to look at the documentation. Web sites for documentation include ruby-doc.org, or APIdock. In the latter case, you'd type include?
next to the magnifying glass near the top right corner, choose the include?
which has Array
underneath it (if you don't know what class [1, 2, 3]
is, type [1, 2, 3].class
in irb), and you get to include? (Array), which describes what it does.
However, if the documentation doesn't help, you're more likely to get a good answer if you can ask a question on how a specific line isn't doing what it should, rather than why an entire script isn't doing what it should.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With