There is an old saying amongst carpenters. Measure twice, cut once. This cuts down on materials. The same is true of typing for Perl programmers. Read more, type less. Okay, that doesn't have the same ring, but reading the documentation before writing your script does make sense.

I came across a script recently where a beginner programmer had obviously decided that typing was easier than reading. Here's an excerpt. The author needs to start a really wide table, but won't end it for a while yet.

PERL:
  1. use CGI qw/:standard/;
  2.  
  3. print "<table border = 1>",th,"day",td,"Date",td,"Time In",td,"Break Start",td,"Break End",td,"Time Out",td,"Evening In",td,"Evening Out",td,"flex hours",td,"flex bal",td,"lieu",td,"adjustment",td,"lieu adjustment",td,"type";

If we pretty this up some, the code above produces the following output. Hardly legible mark up.

HTML:
  1. <table border = 1>
  2.     <th />
  3.     day<td />
  4.     Date<td />
  5.     Time In<td />
  6.     Break Start<td />
  7.     Break End<td />
  8.     Time Out<td />
  9.     Evening In<td />
  10.     Evening Out<td />
  11.     flex hours<td />
  12.     flex bal<td />
  13.     lieu<td />
  14.     adjustment<td />
  15.     lieu adjustment<td />
  16.     type

Some experienced readers can spot several mistakes here. The first one is that CGI.pm provides a routine to start a table separately from ending it. Adding *table imports the start_table and end_table routines.

PERL:
  1. use CGI qw/:standard *table/;
  2.  
  3. print start_table( { -border => 1, } );

The next mistake shows a lack of reading (or understanding) about how the th() and td() routines work and how xhtml tables are built. Basically, arguments passed to these subs are incorporated into the table cell. I would venture that the programmer would have rathered this mark up.

HTML:
  1. <table border="1">
  2.     <tr>
  3.         <th>day</th>
  4.         <th>Date</th>
  5.         <th>Time In</th>
  6.         <th>Break Start</th>
  7.         <th>Break End</th>
  8.         <th>Time Out</th>
  9.         <th>Evening In</th>
  10.         <th>Evening Out</th>
  11.         <th>flex hours</th>
  12.         <th>flex bal</th>
  13.         <th>lieu</th>
  14.         <th>adjustment</th>
  15.         <th>lieu adjustment</th>
  16.         <th>type</th>
  17.     </tr>

Here's the code to do it.

PERL:
  1. use CGI qw/:standard *table/;
  2.  
  3.     start_table( { border => 1 } ),
  4.     Tr(
  5.         th( [
  6.                 'day',              'Date',         'Time In',
  7.                 'Break Start',      'Break End',    'Time Out',
  8.                 'Evening In',       'Evening Out''flex hours',
  9.                 'flex bal',         'lieu',         'adjustment',
  10.                 'lieu adjustment''type',
  11.             ]
  12.         )
  13.     );

If any of this looks strange, you know what you need to do: Go read the documentation. For now though, I can give lost readers a grasp of what is happening here. In its markup subroutines, CGI.pm allows markup atttributes to be defined by passing an anonymous hash before other arguments (if any).

The table routine in the example defines a border attribute with a value of 1. A more typical use might be an anchor.

HTML:
  1. <a href="http://ManThisAuthorIsGood.com/">Charles Clarkson</a>

There's not a whole lot to remember. We want an anchor, so the subroutine name is a() and the attribute is href. We place the attribute name in an anonymous hash and the text in quotes after the hash. We separate the arguments with a comma.

HTML:
  1. a( { href => 'http://ManThisAuthorIsGood.com/' }, 'Charles Clarkson' )

Another common feature of CGI.pm markup sub routines is their distributive nature. They allow us to replace this code.

PERL:
  1. print td(1), td(2), td(3), td(4);

With this code.

PERL:
  1. print td( [ 1 .. 4 ] );

To make this program more robust, we might use a column name array.

PERL:
  1. my @column_names = (
  2.     'day',              'Date',         'Time In',
  3.     'Break Start',      'Break End',    'Time Out',
  4.     'Evening In',       'Evening Out''flex hours',
  5.     'flex bal',         'lieu',         'adjustment',
  6.     'lieu adjustment''type',
  7. );
  8.     start_table( { border => 1 } ),
  9.     Tr( th( \@column_names ) );