Debugging and Dissection Dojo – 5 Weapons/Techniques of Choice
When I started with Ruby about a year ago, I felt a little bit lost at first. With a strong Java background I simply wasn’t used to so much meta programming, mixins, and dynamic/duck typing. While learning a lot via pair programming I also started to simply poke around using the IRB and Rails console. Of course, that sort of thing doesn’t come naturally to a Java programmer, but when you find yourself on a bus ride through town with your netbook and no internet connection, IRB is one of the most fun – and geeky looking – ways to stay awake.
But however cool an interactive Ruby shell might be, not every bug or more exotic language construct can be tackled with it. In the process of learning Ruby I kind of collected my weapons of choice for the code battle. Especially while trying to get a grip on Rails with it’s tons of meta programming you can use a good arsenal to win the battle, so I decided to show you five of my favorites.
1. The Bare-Knuckled Fist Punch
First of all there is the all-time favorite of every programming newbie: Classic print debugging.
obj = Dir.new('/usr/bin')
puts obj
=> <Dir:0x94a6470>
# which should be replaced with
puts obj.inspect
=> <Dir:/usr/bin>
# or even shorter
p obj
=> <Dir:/usr/bin>
This technique is easy and it simply works great if your opponent is within reach. On the downside though, your hands will start bleeding after a few strikes aka several puts later and that’s why you should learn to fight with better weapons soon.
2. The Killing Glance
Your eyes turn pitch black while you keep staring at your enemy until, suddenly, he bursts into pieces. I guess we all practiced this when we were little … or I was just a strange kid. However the analogy here would be to keep looking at your problem from all sides and trying to understand every aspect of it. So first of all we should find out more about our opponent.
n = 12 ** 34
n.class
=> Bignum
n.methods.sort
=> [:to_s, :coerce, :-@, :+, :-, :*, :/, :%, :div, :divmod, :modulo, ..., :class, :dup, ...]
Wow these are a lot of methods! But wait :class and :dup? These look familiar and they’re probably inherited from the Object class itself. Maybe we should just look into the methods Bignum has to offer.
n.public_methods(false).sort
=> [:%, :&, :_, :_*, :+, :-, :-@, :/, :<, :<<, :<=, :<=>, :==, :===, :>, :>=, :>>, :[], :^, :abs, :coerce, :div, :divmod, :eql?, :even?, :fdiv, :hash, :magnitude, :modulo, :odd?, :remainder, :size, :to_f, :to_s, :|, :~]
This looks way clearer now. But here’s another tip. Let’s say you’re just interested in all the methods starting with “to_”, you could just do
n.methods.sort.grep /^to_/
=> [:to_c, :to_enum, :to_f, :to_i, :to_int, :to_r, :to_s]
3. Threatening Friends and Family
Now that we know who our enemy is, we should find out more about his friends and family in case we need to threaten the bastard like in a good old mafia movie.
n.class.superclass
=> Integer
Integer.superclass
=> Numeric
n.class.ancestors
=> [Bignum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
AHA! So, Bignum apparently inherits from Integer and Integer from Numeric. Let’s check this real quick.
Integer > Bignum && Numeric > Integer
=> true
OK cool, that makes sense. So we just found out who the parent and grandparent of Bignum are but what about his brothers, uncles or childs? You are probably wondering if there’s something similar to the Class.ancestors method but for traversing the inheritance tree (or graph if you want to be pedantic) in the opposite direction. Short answer: Nope. Long answer: You can build it yourself.
class Class
def descendants
ObjectSpace.each_object(::Class).select { |c| c < self }
end
end
This little trick can come in quite handy if you’re poking around in a strange datamodel of some bigger project. It simply looks at all the classes in the
whole object space and selects the ones that inherit from the class under examination. I know it’s a bit brutish, but it gets the job done. Let’s try it out with our example. We just learned that Integer and Numeric are the parent and grandparent of Bignum. That means we now can ask them about Bignums brothers and uncles and also Bignum about his children.
Integer.descendants
=> [Bignum, Fixnum]
# Bignum has one brother</h1>
Numeric.descendants
=> [Complex, Rational, Bignum, Float, Fixnum, Integer]
# And 3 uncles: Complex, Rational and Float
Bignum.descendants
=> []
# Unfortunately Bignum has no child
4. The Samurai Sword
While being extremely elegant and versatile the Samurai sword or Katana is a powerful weapon. It is razor-sharp and can be unveiled in a split second to place a deadly cut. In our case this would be the debugger which is conveniently built into the Ruby base system. You could just run your script with the debug library
$ ruby -r debug [options] [programfile] [arguments]
or you can place the debug call right in your code
# boring code above
require 'debug'
# interesting code below
But actually you should look into the Gem ‘ruby-debug’ which does everything that the built-in debugger does, only faster and better. Here is an excellent cheat sheet and here is even a whole RailsCasts episode about it. The usage is quite intuitive once you get the grip of using a console based debugger and when you do, you probably don’t want to use anything GUI’ish anymore.
5. The Battleaxe
If all else fails and you still have no idea how to beat your opponent it may be one of these times where violence is the only solution. In this case we grab the battleaxe.
set_trace_func proc { |event, file, line, id, binding, classname|
printf "%8s %s:%-2d %10s %8sn", event, file, line, id, classname
}
This Kernel function is a last resort for debugging since it is able to monitor each and every event that happens during the programs execution. With this thing you can even distinguish between a pure Ruby method call and a native C method call so get ready for some grep’n’read because the output of this little script
set_trace_func proc { |event, file, line, id, binding, classname|
printf "%8s %s:%-2d %10s %8sn", event, file, line, id, classname
}
def foo(bar)
bar / Math::E
end
n = 12 ** 34
puts foo(n)
looks like this
$ ruby test.rb
c-return test.rb:3 set_trace_func Kernel
line test.rb:4
c-call test.rb:4 method_added Module
c-return test.rb:4 method_added Module
line test.rb:5
c-call test.rb:5 ** Fixnum
c-return test.rb:5 ** Fixnum
line test.rb:6
call test.rb:4 foo Object
line test.rb:4 foo Object
c-call test.rb:4 / Bignum
c-return test.rb:4 / Bignum
return test.rb:4 foo Object
c-call test.rb:6 puts Kernel
c-call test.rb:6 puts IO
c-call test.rb:6 to_s Float
c-return test.rb:6 to_s Float
c-call test.rb:6 write IO
1.8107891504915702e+36
c-return test.rb:6 write IO
c-call test.rb:6 write IO
c-return test.rb:6 write IO
c-return test.rb:6 puts IO
c-return test.rb:6 puts Kernel
So you can imagine how anything bigger will look like. But of course you would write a little more selective function and e.g. filter by event type or classname.
Hopefully you enjoyed my first article and some of these weapons will give you an advantage in your next fight. After all, remember what Sky Marshal Tehat Meru said in Starship Troopers: “To fight the bug, we must understand the bug. We can ill afford another Klendathu.”
Feel free to offer any interesting techniques you might have as well. Just post a comment and share them with us!