Debugging

Bugs are an everyday occurrence

Therefore, the simplest definition of hacking is the process by which you discover the difference between what something was designed to do and what it is capable of doing.

More often than not you will find yourself wondering why your program does not work or works in a way you did not expect it to work. Programmers call those cases “bugs” and you have probably heard the term already. The arcane art of tracking down bugs and fixing them is called “debugging” and you will probably perform it more often than writing code in the beginning.

In this chapter I’m going to show you a small program which has a bug. Fixing this bug is not point here. Instead I want you to focus on the process we used to determine what the bug is.

As far as I am concerned there are three main ways of finding the root of the bug:

  1. printf debugging
  2. using a debugger
  3. reading the stacktrace

printf debugging

printf debugging is really simple: insert a print statement before the line where you think the problem is and see if you’re right. Consider the following program:

puts "Please enter your name."
name = gets
puts "Hi, #{name}! I'm Ruby!"

Once we run it, type in our name we might get the following

Please enter your name.
Michał
Hi, Michał
! I'm Ruby!

I imagine the output is totally different from what you expected. While the technique is called printf, the Ruby “command” to print text on screen is called print. Applying printf debugging here is pretty straightforward:

puts "Please enter your name."
name = gets
puts "Variable name is #{name.inspect}"
puts "Hi, #{name}! I'm Ruby!"

You will notice that I used something called inspect here. Think of it as way to see internals of a given thing in Ruby. If we ran the following program we would get this:

Please enter your name.
Michał
variable name is: "Michał\n"
Hi, Michał
! I'm Ruby!

We can see that our variable holds the name and a ‘\n’ which is the computers equivalent of “next symbol should be put on a new line”.

Let’s see how can we get the same result by using a debugger.

Using a debugger

First off, we need to install a debugger. I recommend using Pry. We can install Pry using a command called gem. Gems are Ruby name for libraries, which basically means programs someone else wrote and made available for us to use.

$ gem install pry pry-byebug
Fetching pry-0.14.0.gem
Fetching pry-byebug-3.9.0.gem
Successfully installed pry-0.14.0
Successfully installed pry-byebug-3.9.0
2 gems installed

Now you should be able to run pry in your terminal:

$ pry
[1] pry(main)>

If this works then we can start using Pry in our programs. We will need to modify our program a little bit:

require "pry"
puts "Please enter your name."
name = gets
binding.pry
puts "Hi, #{name}! I'm Ruby!"

Once we run our program, input our name and press Enter we should get dropped into a Pry session. You should see something similar to the output below

Please enter your name.
Michał

From: /home/quintasan/sauce/ruby.guide/scripts/pry_debugging.rb:5 :

    1: require "pry"
    2: puts "Please enter your name."
    3: name = gets
    4: binding.pry
 => 5: puts "Hi, #{name}! I'm Ruby!"

[1] pry(main)> name.inspect
"\"Michał\\n\""

As you can see, Pry shows us the source code of our program and the => arrow shows us which line will be executed next. I have typed name.inspect in the prompt and pressed Enter which allowed me to inspect the name variable.

Which should I use?

Short answer: both.

Long answer: Sometimes a simple print statement is all you need but sometimes you will want to inspect the state of your program in greater detail. You can use Pry in those cases. Pry has the advantage that you can execute ANY Ruby code in real time and you don’t have to restart your program to see the output.

Now that we have a text editor, Ruby interpreter and a decent debugger we can start learning programming using Ruby.