Improvements for Ruby Debugging
The Visual Studio debugger is simply the best in the business. Period. The problem is getting all its features implemented – and for Ruby there are some tricky problems to solve. Over the last few weeks, I’ve been working on filling out the features of the Ruby In Steel debugger.
There are several parts to building a Ruby debugger. First, there’s the fast component written in C (this is the Cylon debugger). Then there’s a component written in Ruby that deals with formatting and sorting: this could be done in C, but it’s just easier to do it in Ruby. Then there’s the C# part which interfaces to the Visual Studio IDE and the Visual Studio debug Session Manager. And lastly, there’s the bit that handles the nifty ‘drill-down’ expansion in the Locals, Autos and Watch windows and the mouse hover in the editor. Incidentally, it’s this last bit - the mouse-hover - that’s the most difficult. I’ll explain why below.
First off, I’ve got the Call Stack window displaying the line numbers and file names. It took a good bit of digging to find out how to get this information displayed; in the new version of Ruby In Steel Developer (currently available as an ’edge release’ to registered users), you can now turn the line numbers and file names on or off as you want. There’s a whole load of other options that Visual Studio provides in there as well, but some of those have been left for later.
Internally, I’ve fixed the Step Into/Step Over mechanism so that it works properly with threads. This is especially important for Rails and Mongrel (which seems to generate Ruby threads like they are going out of fashion). The Cylon debugger also works efficiently with an unlimited number of threads, though there’s no thread ‘garbage collector’ yet.
In the Autos window, I’ve added Class Variables alongside Instance Variables and Global Variables:
And I’ve got debugging of Ruby meta-code working. If you have a string like this:
You can step through it! What you can’t do (yet) is set a breakpoint inside the dynamic string. Instead, you have to set a breakpoint on the ‘instance_eval’ method and step from there. Still, most meta-programs are small so I think that will do for the time being.
I’ve also got the hover to work within the editor. If the debugger can evaluate an expression it will, otherwise it falls back to the non-debugging IntelliSense mode. And yes, the debugger now works on X64 systems as well.
Lastly, I’ve been putting a considerable amount of effort into getting the drill-down to work reliably. The drill down expands a Ruby object, so that you can see that it is composed of an array of hashes of arrays … and so on. The problem has been that it has turned out to be very difficult to do this reliably. At first, I thought it was me – I just kept getting errors and fixing them. Then I’d get some more (different) errors. After about a week of this, I decided to have a look at the Ruby code to see what was going on. It turns out that the problem lies in the Ruby inspect function. Well, all 20 or 30 inspect functions, really. Each of which produces a slightly different output! So, one inspect function will quote a file name while another won’t. The inspect functions defined in the C interpreter are reasonably regular, but that doesn’t apply to the ones in the Ruby library code (look in set.rb, if you want an example). In any event, I’ve got it working pretty much ok now, even if my initial simple and elegant Antlr inspect parser now looks a bit like a Christmas tree with miscellaneous parse expressions stuck on.
However, it now works and, believe me, it really is the business for debugging Rails applications. Look at the @products expansion below. In debugging, a picture really is worth a thousand words.