Using breakpoint to Inspect and Change the State of Your Application

Problem

You e debugging an application, and would like to be able to stop the program at any point and inspect the applications state (variables, data structures, etc.). Youd also like to be able to modify the applications state before restarting it.

Solution

Use the breakpoint library, available as the ruby-breakpoint gem.

Once you require breakpoint, you can call the breakpoint method from anywhere in your application. When the execution hits the breakpoint call, the application turns into an interactive Ruby session.

Heres a short Ruby program:

#!/usr/bin/ruby -w # breakpoint_test.rb require ubygems require reakpoint class Foo def initialize(init_value) @instance_var = init_value end def bar test_var = @instance_var puts About to hit the breakpoint! breakpoint puts HERE ARE SOME VARIABLES: puts "test_var: #{test_var}, @instance_var: #{@instance_var}" end end f = Foo.new(When in the course) f.bar

When you run the application, you quickly hit the call to breakpoint in Foo#bar. This drops you into an irb session:

$ ruby breakpoint_test.rb About to hit the breakpoint! Executing break point at breakpoint_test.rb:14 in ar irb(#):001:0>

Once you quit the irb session, the program continues on its way:

irb(#):001:0> quit HERE ARE SOME VARIABLES: test_var: When in the course, @instance_var: When in the course

But theres a lot you can do within that irb session before you quit. You can look at the array local_variables, which enumerates all variables local to the current method. You can also look at and modify any of the variables that are currently in scope, including instance variables, class variables, and globals:

$ ruby breakpoint_test.rb About to hit the breakpoint! Executing break point at breakpoint_test.rb:14 in ar irb(#):001:0> local_variables => ["test_var", "_"] irb(#):002:0> test_var => "When in the course" irb(#):003:0> @instance_var => "When in the course" irb(#):004:0> @instance_var = of human events => "of human events"

As before, once you quit the irb session, the program continues running:

irb(#):005:0> quit HERE ARE SOME VARIABLES: test_var: When in the course, @instance_var: of human events

Because we changed the variable @instance_variable within our breakpoint, the puts in the program reports the new value after we leave the breakpoint session.

Discussion

There is another way to access a breakpoint. Instead of calling breakpoint directly, you can pass a code block into assert. If the block evaluates to false, assert executes a breakpoint. Lets say you want to execute a breakpoint only if the instance variable @instance_variable has a certain value. Heres how:

#!/usr/bin/ruby -w # breakpoint_test_2.rb require ubygems require reakpoint class Foo def initialize(init_value) @instance_var = init_value end def bar test_var = @instance_var puts About to hit the breakpoint! (maybe) assert { @instance_var == This is another fine mess } puts HERE ARE SOME VARIABLES: puts "test_var: #{test_var}, @instance_var: #{@instance_var}" end end Foo.new(When in the course).bar # This will NOT cause a breakpoint Foo.new(This is another fine mess).bar # This will NOT cause a breakpoint $ ruby breakpoint_test_2.rb About to hit the breakpoint! (maybe) HERE ARE SOME VARIABLES: test_var: When in the course, @instance_var: When in the course About to hit the breakpoint! (maybe) Assert failed at breakpoint_test_2.rb:14 in ar. Executing implicit breakpoint. irb(#):001:0> @instance_var => "This is another fine mess" irb(#):002:0> quit HERE ARE SOME VARIABLES: test_var: This is another fine mess, @instance_var: This is another fine mess

By using assert, you can enter an interactive irb session only when the state of your application is worth inspecting.

Категории