Hack 54. Debug with Comments


Let your documentation help you remove bugs.

There are two types of people who debug code: those who fire up Perl's built-in debugger and those who sprinkle print statements through their code. If you're in the second group, you probably know that one big problem with debugging by hand is that, once you remove the bugs, you have to go through and remove all the debugging statements as well.

What if you could safely leave them in the code? After all, if you needed them once, you'll probably need them again, when the next bug appears.

The Hack

"Something left in the code, but ignored" is pretty much the definition of a comment, so it's no surprise that you can use comments to turn off debugging statements. There's a much more interesting alternative, however: using comments to turn on debugging statements. The Smart::Comments CPAN module does just that: it turns comments into debugging statements.

Displaying variables

When you use Smart::Comments, any subsequent comment with three or more leading #s becomes a debugging statement and prints whatever the comment says to STDERR. For example, if you can't work out why your @play_calls variable is getting more elements than you expected:

my $call       = "26, 17, 22, hut!"; my @play_calls = split /\\s*,?\\s*/, $call;

insert some smart comments to report what's happening:

# make '###' magical... use Smart::Comments; my $call       = "26, 17, 22, hut!"; ### $call my @play_calls = split /\\s*,?\\s*/, $call; ### @play_calls

When you run that code, Smart::Comments will find the triple-# comments and print out whatever they contain:

$ perl play_book.pl ### $call: '26, 17, 22, hut!' ### @play_calls: [ ###                '2', ###                '6', ###                '1', ###                '7', ###                '2', ###                '2', ###                'h', ###                'u', ###                't', ###                '!' ###              ] $

Immediately you can see that the split is splitting your text at every single character (because your splitting pattern, /\\s*,?\\s*/, matches an empty string so split splits everywhere).

The real smartness comes in, however, when you write more structured comments:

use Smart::Comments; my $call       = "26, 17, 22, hut!"; ### input: $call my @play_calls = split /\\s*,?\\s*/, $call; ### split to: @play_calls

which produces the output:

$ perl play_book.pl ### input: '26, 17, 22, hut!' ### split to: [ ###             '2', ###             '6', ###             '1', ###             '7', ###             '2', ###             '2', ###             'h', ###             'u', ###             't', ###             '!' ###           ] $

Making Assertions

Even more useful, the module also allows you to write comments that act like assertions:

use Smart::Comments; my $call       = "26, 17, 22, hut!"; my @play_calls = split /\\s*,?\\s*/, $call; #### require: @play_calls = = 4

Assertion comments like this only produce a report (and an exception!) if the assertion fails. In that case, the smartness really shows through, because the smart comments not only report the failure, but they also automatically report all the variables used in the test, so you can see why the assertion failed:

$ perl play_book_with_assertion.pl ### @play_calls = = 4 was not true at play_book_with_assertion.pl line 7. ###     @play_calls was: [ ###                        '2', ###                        '6', ###                        '1', ###                        '7', ###                        '2', ###                        '2', ###                        'h', ###                        'u', ###                        't', ###                        '!' ###                      ] $

Best of all, when you finish debugging, you can switch off all the debugging statements simply by removingor just commenting outthe use Smart::Comments statement:

# use Smart::Comments; my $call       = "26, 17, 22, hut!"; ### input: $call my @play_calls = split /\\s*,?\\s*/, $call; ### split to: @play_calls

Because the code no longer loads the module, triple-# comments are no longer special. They remain ordinary comments, and Perl consequently ignores them:

$ perl play_book.pl $

Configuring smartness levels

By the way, you might have noticed that the require: assertion in the third example used #### instead of ### as its comment introducer. Using differing numbers of #s allows you to be selective about turning smart comments on and off. If you load the module and explicitly tell it which comment introducers are smart, then it will only activate comments with those particular introducers. For example:

use Smart::Comments '####';   # Only ####... comments are "smart"                               # Any ###... comments are ignored my $call       = "26, 17, 22, hut!"; ### $call my @play_calls = split /\\s*,?\\s*/, $call; ### @play_calls #### require: @play_calls = = 4

This final example turns off the debugging statements, leaving only the assertion active.

If editing your source code to enable and disable Smart::Comments is too onerous, consider making a shell alias [Hack #4] to load the module and execute a named program. The appropriate command line to run a program with Smart::Comments enabled is:

$ perl -MSmart::Comments split_test.pl                

To activate only specific comment introducers, as in the earlier example, write:

$ perl -MSmart::Comments="" split_test.pl                

with the appropriate number of # characters in the quotes.



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net