Kinetic's Intro to Ruby-Debugging 1

Posted by Justin Reagor Fri, 16 Nov 2007 03:35:00 GMT

Galvanize your debugging skills, Rails 2.0 cometh. With its optimized breakpointing we will all soon find ourselves wanting to be thrown into the console. If your up to it that is, and consoles don’t scare you. This quickie guidebook demonstrates some current features of the ‘ruby-debug’ gem and how you can start getting into the mindset of live debugging your Rails code.

At the conclusion of this article I will provide several useful links for other resources into Ruby-debug.

Warning: This stuff tends to be only for real Ruby hackers that like to follow live execution of their applications and frameworks, demystifying the magical and generally understanding exactly whats going on during execution.

Get the Goods

Start-up your terminal of choice and do the old…

# sudo gem install ruby-debug -y

You’ll of course want to choose either Win32 or the more fashionable Ruby version, depending on your platform.

You may also want to install Wirble. Wirble gives you helpful IRB syntax highlighting which can come into so much handiness that you might just pee your pants.

# sudo gem install wirble
...for wet pants.

Next, visit our old friend ‘development.rb’ and add the following line at the bottom of this file…

# require 'ruby-debug'

If your using the current Edge Rails, 2.0 RC1, you should not need to do any of this as the new version of Rails will be using this by default. This is from my own hear-say, so I’ve installed it anyway, and using it in Rails 1.2.5 as well.

The Pay Dirt

Fire up your Rails application in your terminal, head over to a controller and add the following line as the first call in any action. Preferrably one with some instance variable assignments like a POST/UPDATE…

debugger

You can place this where ever you like when debugging this way, but for the article you might find my controller placement idea good for your first use (where the ACTION is).

Your going to now navigate to this action from within your web browser. Your browser should stall (what looks to be a stall), and your browser may be still be trying to load the page. Apple-Tab over to your Terminal, where you ran script/server, and you should see…

./script/..config/../app/controllers/pirates_controller.rb:8 @pirate = Pirate.find(params[:id]) if params[:treasure]
(rdb:1)

Take notice to the first line will be the last line executed before hitting your ‘debugger’ line. As well as your new friend, the ruby-debug prompt.

Help

(rdb:1) help
ruby-debug help v0.9.3
Type 'help <command-name>' for help on a specific command

Available commands:
backtrace break catch cont delete display down eval exit finish frame 
help irb list method next p pp quit reload restart save script set 
step thread tmate trace undisplay up var where 

(rdb:1) help var
ruby-debug help v0.9.3
v[ar] c[onst] <object>          show constants of object
v[ar] g[lobal]                  show global variables
v[ar] i[nstance] <object>       show instance variables of object
v[ar] l[ocal]                   show local variables

List and Where

Now try “list”ing out your source, and finding out “where” you are in a stack trace (if this was an error we’d see a nice long trace).

(rdb:1) list =
    5            def ensure_booty
    6                debugger
=>    8                @pirate = Pirate.find(params[:id]) if params[:treasure]
    9                if @pirate.update_attributes(:booty => params[:treasure])
    10                    redirect_to :action => :set_sail
    11                else
    12                    redirect_back_or_default(raid_island_path)
    13                end
    14            end
(rdb:1) where
--> #0 /Users/padiomonk/rails/piratr/app/controllers/pirates_controller.rb:8 in 'ensure_booty'

You can list as many times as you want to follow down your source. Using the ”=” symbol will always return you to where you are in the current source.

Next and Step

You can use the “step” command to make a single step, while the “next” command will move you to the next line of execution without descending inside methods (I haven’t gotten the full hang of this yet).

(rdb:1) next
Processing PiratesController#ensure_booty (for 127.0.0.1 at 1505-11-15 23:38:35) [GET]
  Session ID: 03411cca0de2164ecb751116ae19d948
  Parameters: {"action"=>"ensure_booty", "controller"=>"pirate", "id" => "23", "treasure" => "women's panties"}
  SQL (0.000214)   SET SQL_AUTO_IS_NULL=0
  Pirate Columns (0.004699)   SHOW FIELDS FROM pirates
  Pirate Load (0.001597)   SELECT * FROM pirate WHERE (pirates.`id` = 23) LIMIT 1
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.5/lib/action_controller/base.rb:1102 render unless performed?

Break and Continue

Breakpoints are instances where you are thrown back into your debugger when a certain method is called, a certain line is reached or a certain condition occurs. Mostly a fine-art of development, good breakpointing skills can definitely take a while to grow into your personal development cycle.

(rdb:1) b 9
Set breakpoint 1 at ./script/.../controllers/pirates_controller.rb:9
(rdb:1) b Booty.find
Set breakpoint 2 at Booty.find
(rdb:1) b 12 if params[:treasure].nil?
Set breakpoint 3 at 12
(rdb:1) b
Breakpoints:
    1 pirates_controller.rb:9
    2 Booty.find
    3 pirates_controller.rb:12 if params[:treasure].nil?
(rdb:1) cont

You will now be thrown back into the debugger when any of these breakpoints are “met”. Taking a look up above, this should throw us right at the redirect_back_or_default if I’m correct.

RDebug

Now that you know some about breakpoints, you might find the time where you just want to load up the debugger before running Rails… set some breakpoints in places you already know of, or need to investigate… then run your script/server. Without placing a “debugger” call anywhere.

# rdebug script/server

Open With Your Mate

Something that I caught onto very quickly, was the ability to open up the current file into TextMate at any time. This comes in handy when exploring the Rails source, being swung into one file after another.

Simply use the “tmate” command!

IRB

The great thing about ruby-debug is that it gives you the current state of your app loaded into an irb session to mess around with. Sometimes I tend to use this more, to checkout my constants and instance variables…

(rdb:73) irb
>> self.class
=> PirateController
>> instance_variables
=> ["@response", "@assigns", "@template", "@_session", "@params", "@_request", "@pirate", "@before_filter_chain_aborted", "@headers", "@flash", "@cookies", "@_response", "@request_origin", "@variables_added", "@_flash", "@action_name", "@session", "@_cookies", "@performed_redirect", "@sailboat", "@_headers", "@current_user", "@url", "@request", "@_params", "@performed_render"]
>> @pirate.is_a?(Person)
=> true
>> quit
(rdb:73)

Outro

This tool might not be for you, but I’ve been learning more and more as I use this. I also don’t feel there is a better development utility if you intend to truly understand the under pinnings of the Rails source and wield its magical Ruby wisdom (pppfffffttt).

Anyway, here’s are a couple links for more information…

Datanoise: Ruby-debug homepage

Datanoise: Debugging in Rails

Datanoise: Tutorial on Ruby-debug

Misc Praise with Link to Railscast video