From: Eivind Eklund Date: 2008-04-29T19:31:21+09:00 Subject: Re: How to debug Ruby Programs On Tue, Apr 29, 2008 at 11:05 AM, Krishna Mohan wrote: > > Hi, > > I'm a newbee to Ruby, can any one you please suggest me ways to debug a > Ruby Program. My major debugging techniques, in order of how useful they tend to be: 1. Read code carefully, including refactoring it to be more readable. Applicable refactorings include renaming methods, renaming variables, extracting methods, inlining methods, and restructuring algorithms. Adding comments so it is more clear probably don't count as refactoring; I find that useful, too. 2. As has already been mentioned, use of puts and inspect, for example # Made up example something.each do |thing_you_are_going_to_process| puts "Processing #{thing_you_are_going_to_process.inspect}" ... processing here ... end to see that you're operating in a sane way. Various forms of this is, at least for me, the number two major debugging technique 3. Add tests around parts of your program that are likely to contain errors. For instance, I've been operating with some slightly complex code to drive translation from one database to another lately; instead of dealing with bugs in that code, I've added tests for each code path. 4. Add invariant checking to your code - ie, check that things that should not be able to fail do not, in fact, fail. Here's an example: # Example paraphrased from some Perl code I did this with yesterday new_args['Created'] = WebApp::Util.string_to_stamp(old['create_date'']) raise "Unable to translate #{old['create_data'].inspect} for 'Created'" unless new_args['Created'] For more complex programs, it is sometimes very useful to check that complete data structures are the way they are supposed to be. For example, in a tree structure where every node is supposed to point at their parent, you can check with something like this (called as tree_root.invariant): class Tree def internal_invariant raise "Left #{@left.inspect} has wrong parent in #{self.inspect}" if @left && @left.parent != self raise "Right #{@right.inspect} has wrong parent in #{self.inspect}" if @right && @right.parent != self @left.internal_invariant if @left @right.internal_invariant if @right end def invariant raise "Root has parent?" if @parent internal_invariant end end I find the invariant adding and puts variants to flow over into each other a bit in practice; I'll often add extra invariants when doing debugging, and a bunch of output (puts statatements), and then I use "cvs diff" to find and eliminate the puts statements while committing the new invariant checks. Bonus tip: Eliminating stuff from a diff is often most easily done by storing the diff in a file, editing out everything you want to keep, and then doing patch -R < file_with_diffs_to_remove Eivind. Eivind.