When your code is producing a large quantity of output to a terminal window it can be very hard to quickly tell what's going on just by glancing at the screen - especially if the terminal is producing so much text that things start to scroll off the top of the screen before you can complete reading them.
Term::ANSIColor allows you to send control codes to the terminal telling it to display your text in different colours or with different features (bold, underlining, etc) turned on. This enables you to much better format your output allowing you to break up fast flowing text visually, and provide a mechanism that you can use to show someone that very prominently something is wrong. It allows the user presented with scrolling text to simplify the question they have to ask - not, "What does this say...should I pause it and check for errors", to rather "Does this contain red text?".
Term::ANSIColor can be made to export a number of routines that return the escape codes that if sent to your terminal cause it to change colour. for example:
use Term::ANSIColor qw(:constants);
print RED, "This text is in red\n", RESET; print "This text is normal again.
Prints
This text is in red
This text is normal again
Unlike HTML there isn't a start and end tag - you turn on the features that you
want and they stay on until you call RESET
or get replaced with another
competing feature. So, you can flip colours without having to turn the
previous colours off like so:
print RED, "red means stop, ", YELLOW, " yellow means wait, ", GREEN, "green means go!". RESET, "\n";
red means stop, yellow means wait, green means go!
You can also make text bold and underlined
print UNDERLINE, "Chapter 14", RESET, "\n\n"; print "It was then, and ", BOLD, "only ", RESET, "then that...";
Chapter 14
It was then, and only then that...
And you can also change the background colour
print ON_RED, "Hello", RESET, "\n";
Hello
And non-competing features can be combined
print "We can make things look really ",
BOLD, UNDERLINE, YELLOW, ON_GREEN, "ugly", RESET, "\n";
We can make things look really ugly
Different, more advanced, terminals may also support additional
features - see the manual for a description of features like dark
,
blink
, reverse
and concealed
that you can also use.
One good technique for debugging a problem is to generate debug output all over your code. You'll often see temporary code in my modules like this when I'm first testing my objects:
sub foo { my $self = shift;
print STDERR "Got to foo\"; print STDERR Dumper($self);
...
This produces copious output that allows me to track what methods are being called on my object, and the state of the object when said method is called. The problem with copious output is that it's often all to easy to drown yourself with so much debug info that it's impossible to tell the output from one Data::Dumper ends and another starts (especially when they flow over several screens) and if you're not careful you'll accidentally page down from one output to another, totally confusing yourself.
When this starts happening, I either reduce the number of Dumper statements I'm calling, or if I need them all to work out what's going on, I bring Term::ANSIColor to the rescue and colour code each method's debug output separately:
sub foo { my $self = shift;
print STDERR RED; print STDERR "Got to foo\"; print STDERR Dumper($self); print STDERR RESET;
...
This is a simple script that I wrote to check that a bunch of URLs were working as expected. Rather than cluttering up the display with a bunch of status messages I use Term::ANSIColor to change the colour of the URLs depending on if they are reachable or not. This way I can tell if there's a problem simply by glancing at the terminal the script is running in rather than having to actually read any of the output.
#!/usr/bin/perl
# turn on perl's safety features use strict; use warnings;
# load a lot of stuff use LWP::Simple qw(get); use Time::HiRes qw(gettimeofday tv_interval); use Term::ANSIColor qw(:constants);
# define how long before we should get a warning about # things use constant MAX_ALLOWED_SECONDS => 5;
# test some pages test_url("http://2shortplanks.com"); test_url("http://use.perl.org/"); test_url("http://www.cpan.org/modules/01modules.index.html"); test_url("http://2shortplanks.com/doesntexist");
sub test_url { my $url = shift;
# what time is it now *exactly* my $t0 = [gettimeofday];
# download the page my $result = get $url;
# work out what color we should print in # on red background if couldn't load # red if took too long to load # green if okay if (!defined($result)) { print ON_RED } elsif (tv_interval($t0) > MAX_ALLOWED_SECONDS) { print RED } else { print GREEN }
print $url; print RESET, "\n"; }
When this is run it produces this output:
http://2shortplanks.com http://use.perl.org/ http://www.cpan.org/modules/01modules.index.html http://2shortplanks.com/doesntexist
Showing us that though http://2shortplanks.com and http://use.perl.org are fine, the list of all modules takes more than five seconds to download and http://2shortplanks.com/doesntexist has, unsurprisingly, errors.
Test::Builder::Tester is an example of where I use Term::ANSIColor in a module on CPAN. It compares the output of testing functions with the expected output, and complains if they differ. However, when Test::Builder::Tester complains that two test outputs differ it can be very hard to spot by eye where exactly the two sections of text are different, especially if they differ in invisible characters (for example, one string has an extra space on the end.) To help with this I provide options to turn on coloured output to highlight the differing text in red.
1..5 ok 1 - use Acme::Test::Buffy; ok 2 - function 'is_buffy' exported ok 3 - works when correct ok 4 - works when correct with default text not ok 5 - works when incorrect # Failed test (t/01basic.t at line 85) # STDERR is: # # Failed test (t/01basic.t at line 81) # # Expected 'Buffy' but got 'buffy' instead # # not: # # Failed test (t/01basic.t at line 81) # # Expected 'Buffy' but got text 'buffy' instead # # as expected
This is an example of using Term::ANSIColor to show information that I otherwise couldn't provide - there's no other way to straight forwardly indicate where the text differs without inserting something in the text itself.