Perl Best Practices
19.4. Formats
Don't use formats. The format statement is one of the oldest and most fundamental features of Perl. It implements the original "R" of the "Practical Extraction and Reporting Language". And even here in the 21st centurywhere data is more typically restructured, marked-up, CSS'd, JavaScripted, hyperlinked, and finally browseda simple text-based report is still often a cleaner and more usable alternative, especially in command-line environments: > contacts -find 'Damian' ================================== | NAME | AGE | ID NUMBER | |----------------+-----+-----------| | Damian M. | 40 | 869942 | | Conway | | | |==================================| | COMMENTS | |----------------------------------| | Do not feed after midnight. Do | | not mix with quantum physics. Do | | not allow subject to talk for | | "as long as he likes". | ==================================
But building such a report with format, as in Example 19-6, has some serious drawbacks, especially in terms of best-practice programming. For a start, formats are statically defined (i.e., specified at compile time), so it's difficult to build a format as your program executes; you have to resort to a string eval (see Chapter 9). Formats rely on global variables for configuration, and on package variables for the data they are to format (see Chapter 5). They also have to write their formatted text to a named filehandle (see Chapter 10). That's three best-practice strikes against formats already. Example 19-6. Building a report with format
# Predeclare report format with the necessary package variables... our ($name, $ID, $age, $comments); format CONTACT = ================================== | NAME | AGE | ID NUMBER | |----------------+-----+-----------| | ^<<<<<<<<<<<<< | ^|| | ^>>>>>>>> |~~ $name, $age, $ID, |==================================| | COMMENTS | |----------------------------------| | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |~~ $comments, ================================== . # and later... # Grab contact information... ($ID, $name, $age, my $comments_ref) = get_contact($search_string); # Massage comments into a single string... $comments = join "\n", @{$comments_ref}; # Open output stream to STDOUT and write formatted data... open *CONTACT, q{>-} or croak "Can't open stdout: $OS_ERROR"; write *CONTACT;
Formats aren't re-entrant or recursive either, so you can't use a format to format the page header of another format. And you can't (easily) pre-format data that's going to be squeezed into a particular field. Formats only provide a limited (and non-extensible) range of field types; they can't (easily) format bulleted lists, tables, comma'd numbers, monetary amounts, fully justified text, or verbatim data (i.e., with no line filling). And although it's easy to give each formatted page a header, page footers are difficult to produce. Perl 6 will remedy all these problems and deficiencies by replacing the format declaration with a form( ) function, which can be called at run time to produce a formatted string that can be either printed at once or used in further formatting operations. This new approach to text-based report generation is also available in Perl 5, via the Perl6::Form CPAN module. For example, a report like that generated by Example 19-6 could also be produced without package variables, named filehandles, or explicit list flattening by the code in Example 19-7. Example 19-7. Building a report with Perl6::Form
use Perl6::Form; my ($ID, $name, $age, $comments_ref) = get_contact($search_string); print form {bullet=>'*'}, ' =================================== ', '| NAME | AGE | ID NUMBER |', '|-----------------+-----+-----------|', '| {[[[[[[[[[[[[[} | {|} | {>>>>>>>} |', $name, $age, $ID, '|===================================|', '| COMMENTS |', '|-----------------------------------|', '| * {[[[[[[[[[[[[[[[[[[[[[[[[[[[[[} |', $comments_ref, ' =================================== ', ; Note the use of an asterisk as a bullet to improve the readability of the comments: ================================== | NAME | AGE | ID NUMBER | |----------------+-----+-----------| | Damian M. | 40 | 869942 | | Conway | | | |==================================| | COMMENTS | |----------------------------------| | * Do not feed after midnight. | | * Do not mix with quantum | | physics. | | * Do not allow subject to talk | | for "as long as he likes". | ================================== |