diff --git a/ruby/basic_ruby/debugging.md b/ruby/basic_ruby/debugging.md index e2d347441c6..40a772b4869 100644 --- a/ruby/basic_ruby/debugging.md +++ b/ruby/basic_ruby/debugging.md @@ -2,7 +2,7 @@ Tracking down and fixing both errors and unexpected behavior in your code is an inevitable part of being a developer. The art of finding the cause of problems and then fixing them in code is known as **debugging**. The [origin of the term "debugging"](https://en.wikipedia.org/wiki/Debugging#Etymology) is a classic computer science tale worth reading if you haven’t already. -In this lesson, we'll cover all of the main techniques you can use to debug your code when you run into a problem. +In this lesson, we'll cover some of the main techniques you can use to debug your code when you run into a problem. ### Lesson overview @@ -10,7 +10,7 @@ This section contains a general overview of topics that you will learn in this l - What a stack trace is. - Using a stack trace to debug your code. -- Using `puts`, `p`, Pry and debug gem's VSCode integration to debug your code. +- Using `puts`, `p`, and `binding.irb` to debug your code. - How you should decide to start with debugging. ### Reading the stack trace @@ -111,22 +111,18 @@ p "Using p:" p [] ``` -### Debugging with Pry-byebug +### Debugging with binding.irb -[Pry](https://github.com/pry/pry) is a Ruby gem that provides you with an interactive REPL while your program is running. The REPL provided by Pry is very similar to IRB but has added functionality. The recommended Ruby gem for debugging is [Pry-byebug](https://github.com/deivid-rodriguez/pry-byebug) and it includes Pry as a dependency. Pry-byebug adds step-by-step debugging and stack navigation. +You're hopefully familiar with the IRB tool for running a Ruby [REPL](https://www.rubyguides.com/2018/12/what-is-a-repl-in-ruby/) in your terminal. So far, you've probably just used it as a standalone tool to test simple code out, but you can also use it to get an interactive debugging experience with a running Ruby program. To do so, you just need to add a line with `binding.irb` in your script. Let's look at an example. -To use Pry-byebug, you'll first need to install it in your terminal by running `gem install pry-byebug`. You can then make it available in your program by requiring it at the top of your file with `require 'pry-byebug'`. Finally, to use Pry-byebug, you just need to call `binding.pry` at any point in your program. - -To follow along with these examples save the code into a Ruby file (e.g., `script.rb`) and then run the file in your terminal (e.g., `ruby script.rb`) +To follow along with this, save the following code into a Ruby file (e.g., `script.rb`) and then run the file in your terminal (e.g., `ruby script.rb`) ```ruby -require 'pry-byebug' - def isogram?(string) original_length = string.length string_array = string.downcase.split - binding.pry + binding.irb unique_length = string_array.uniq.length original_length == unique_length @@ -135,61 +131,59 @@ end isogram?("Odin") ``` -When your code executes and gets to `binding.pry`, it will open an IRB-like session in your terminal. You can then use that session to check the values of anything within the scope of where you included `binding.pry`. However, keep in mind that any code written *after* the `binding.pry` statement will not have been evaluated during the Pry session. - -For example, here `original_length` and `string_array` are in scope. However, `unique_length` is not in scope, because it is written after `binding.pry` and has not been evaluated yet. +When your code executes and gets to `binding.irb`, it will open an IRB session in your terminal. You can then use that session to check the values of anything within the scope of where you included `binding.irb`. However, keep in mind that any code written *after* the `binding.irb` statement will not have been evaluated yet. -Thus, adding a `binding.pry` line in our code is similar to creating a breakpoint in JavaScript. +For example, here `original_length` and `string_array` are in scope. However, `unique_length` is not in scope, because it is written after `binding.irb`. -To see this point in action, try running the following: +You can add `binding.irb` at multiple points in the execution of your program. To see this in action, try running the following: ```ruby -require 'pry-byebug' - def yell_greeting(string) name = string - binding.pry + binding.irb name = name.upcase greeting = "WASSAP, #{name}!" + + binding.irb + puts greeting end yell_greeting("bob") ``` -During the session, if you check for the value of `name`, you will notice that you get back the value `bob` instead of `BOB`. What value do you think `greeting` will return? Yup, it will be `nil`. This is because `name = name.upcase` and `greeting = "WASSAP, #{name}!"` occurred after the `binding.pry` call and were never evaluated. +During the session, if you check for the value of `name`, you will notice that you get back the value `bob` instead of `BOB`. What value do you think `greeting` will return? Yup, it will be `nil`. This is because `name = name.upcase` and `greeting = "WASSAP, #{name}!"` occurred after the first `binding.irb` call and were never evaluated. -Using the same example above, you can use one of pry-byebug's commands to figure out what `name = name.upcase` will return. You won't need to quit the session or add another `binding.pry` beneath it. Enter `next` to step over to the next line. +To proceed with the program, you can run the `exit` command, which will end the first IRB session and continue execution of the code. Because there's a 2nd `binding.irb`, it stops again. You can now see how `name` has changed and what `greeting` has been defined as. ```ruby -[1] pry(main)> name +[1] irb(main)> name => "bob" -[2] pry(main)> greeting +[2] irb(main)> greeting => nil -[3] pry(main)> next +[3] irb(main)> exit 5: def yell_greeting(string) 6: name = string 7: - 8: binding.pry + 8: binding.irb 9: 10: name = name.upcase - => 11: greeting = "WASSAP, #{name}!" - 12: puts greeting - 13: end - -[4] pry(main)> name + 11: greeting = "WASSAP, #{name}!" + 12: + => 13: binding.irb + 14: + 15: puts greeting + 16: end + +[4] irb(main)> name => "BOB" ``` -It stops after evaluating the next line. `name` now returns `BOB`. Calling `next` again will evaluate the following line. Try it out to know what `greeting` will return. [Pry-byebug has a few more commands](https://github.com/deivid-rodriguez/pry-byebug). Play around with them to get a feel of what they do. - -As you can see, using Pry-byebug for debugging achieves the same outcome as `puts` debugging: it allows you to confirm the assumptions you have about particular parts of your code. If your code is complex, Pry-byebug will probably allow you to debug quicker thanks to its interactive runtime environment. In such scenarios, Pry-byebug will be easier to interact with than having to add `puts` statements everywhere and re-running your code each time. - -There is far, far more that you can do with Pry-byebug, but that's beyond the scope of this lesson. Check out the Assignments and Additional Resources to find out where you can learn more about this useful gem. +As you can see, using `binding.irb` for debugging achieves the same outcome as `puts` debugging: it allows you to confirm the assumptions you have about particular parts of your code. If your code is complex, `binding.irb` may allow you to debug more quickly thanks to its interactive runtime environment. In such scenarios, IRB will be easier to interact with than having to add `puts` statements everywhere and re-running your code each time. ### How to start debugging @@ -199,19 +193,14 @@ Programs generally go wrong due to two main reasons: 1. The program runs but does not work the way you expect. For example, you expect a method to return a `2`, but it actually returns `6` when you run it. In this case, there is no stack trace. -Obviously, if available, the stack trace is the first place you should look when debugging. If there's no stack trace, then `puts` and Pry are the easiest and quickest tools you can use to get yourself back up and running. +Obviously, if available, the stack trace is the first place you should look when debugging. If there's no stack trace, then `puts` and `binding.irb` are the easiest and quickest tools you can use to get yourself back up and running. ### Assignment