Cookin' with Tom and Nat

The Perl Cookbook, 2d edition

Author

Jim Keenan jkeen@verizon.net. January 18, 2004.

What's New?

The first edition of the Perl Cookbook succeeded not only in its own right but as a model for other work as well. As of early 2004, O'Reilly & Associates has published no fewer than 22 different information technology books using the cookbook formula pioneered by Christiansen and Torkington in August 1998.

The second edition of the Perl Cookbook retains all but a few of the recipes from the first edition, but adds, by my count, 80 new recipes, including two entirely new chapters. To oversimplify, these additions may be described as being either 'internal' or 'external' to Perl. The 'internal' recipes show new, improved ways of handling problems that Perl already was tackling at the time of the first edition. The 'external' recipes demonstrate applications of Perl to non-Perl information technologies which have become much more important since 1998.

In the first area, recipes are presented for use of newer Perl modules such as Tie::File, Switch, Inline::C, and POE. New features such as weak references also receive new recipes.

In the second area, recipes for using Perl to control Unicode, mod_perl and XML dominate. At least eight new recipes utilize Perl 5.8's improved Unicode handling for practical applications. mod_perl and XML are each the subject of entirely new chapters, with 27 new recipes between them. Ten new recipes have been written for improved handling of database connections, including transactions. LDAP and SOAP also are the subjects of new recipes.

See below for my own list of the new recipes.

Can an Amateur Follow the Recipes?

The value of a recipe in the Perl Cookbook (perhaps we should say, its 'yumminess') could be measured in either of two ways.  First, does it represent the best, or nearly the best, way of solving a particular programming problem?  Second, can a programmer who is not particularly skilled in the subject matter of a given recipe cook up a script according to the recipe and get the intended result?

Since I do not have the breadth or depth of programming experience that Tom and Nat have, I am not well positioned to evaluate whether their recipes are the best for the particular dishes they're trying to cook.  In the course of preparing this review, however, I tried out several recipes with useful results.  In fact, some of these recipes have led me to think of solutions to programming problems that have bedeviled me for years.

  1. Reading Mail with Net::POP3; Prompting for Passwords with Term::ReadKey

    Like most lay, non-geek computer users, for my first four years on the Internet I relied on commercial e-mail clients like Microsoft Outlook Express to receive and sort my e-mail; I knew nothing of the underlying e-mail protocols. And, like geek and non-geek computer users everywhere, my enjoyment of the Internet has been diminished in the last year by the vast increase in spam, viruses and worms coming into my e-mail inbox. I felt completely helpless when, just a few months ago, my daily e-mail count went from 300 items (90% junk) to 1100 items (99% junk, or worse). I purchased a shareware program (Poco) that, unlike the version of Outlook Express I was using, enabled me to view my e-mail headers on the server before downloading. I realized that if I could learn something more about how e-mail works, I could attack my spam problem more directly both through Perl extensions such as Mail::SpamAssassin and through the power of Perl regular extensions. But I first needed a painless way to learn how e-mail really works.

    Turn to the Perl Cookbook, Recipe 18.5: Reading Mail with POP3. I followed the recipe on using the Net::POP3 module and was accessing my POP3 mail within minutes.

        use Net::POP3;
        my ($site, $username, $password, $pop3, $messagesref);
        my ($k,$v);
        $site = 'incoming.verizon.net';
        $username = 'jkeen';
        $password = 'jimspassword111';
        $pop3 = Net::POP3->new($site); 
            # Most error-checking deleted for clarity
        defined ($pop3->login($username, $password))
            or die "Can't authenticate: $!";
        $messagesref = $pop3->list;
        while ( ($k,$v) = each %$messagesref ) {
            print "$k:\t$v\n";
            my $msgref = $pop3->top( $k, 0 );
            print "@$msgref\n";
        }

    But then I saw that the recipe called for use of a password as part of authentication. I didn't want to type my password in plain text or store it in a Perl script, even on my home computer. What to do?

    Again, turn to the Cookbook: Recipe 15.10: Reading Passwords. I was quickly able to write a simple command-line prompt for a password.

        use Net::POP3;
        use Term::ReadKey;
        # [snip declarations of variables]
        $site = 'incoming.verizon.net';
        $username = 'jkeen';
        print "Enter password for $username at $site:  ";
        ReadMode('noecho');
        $password = ReadLine(0);
        chomp $password;
        ReadMode(0);
        print "\n";
        # [snip balance of code]

    ``Wow,'' I thought, ``I really got this to work!'' The joy of using Perl to get something done ... something you didn't think you'd have the time to learn how to do.

  2. Migrating from One ISP to Another with Net::FTP

    People who read the New York Perlmongers list will recall that about a month ago I asked about the best way to migrate from one ISP to another, i.e., how to get the files I had in the 'free' storage space on my old ISP to that on my new. I tried to use WS_FTPro to establish a direct connection from the old ISP to the new, but eventually became convinced that the new ISP wouldn't allow it. So I had to learn how to code FTP connections myself.

    Once again, I turned to the Perl Cookbook: Recipe 18.2: Being an FTP Client. Here's how I established a connection to my new ISP:

        use Net::FTP;
        use Term::ReadKey;
        my ($ftp, $i, @files, $dirname);
        my %site = (
            name        => 'ftpmysite.verizon.net',
            username    => 'jkeen',
            password    => undef,
            topdir      => 'Storage'
        );
        $ftp = Net::FTP->new($site{'name'});
        # [snip:  prompt for password]
        $ftp->login($site{'username'}, $site{'password'});
        $ftp->cwd($site{'topdir'});
        $dirname = $ftp->pwd();
        print "Current directory:  $dirname\n\n";
        @files = $ftp->ls();
        print "Files listed via \$ftp->ls()\n";
        print "$_\n" for @files; print "\n";
        @files = $ftp->dir();
        print "Files listed via \$ftp->dir()\n";
        print "$_\n" for @files;
        $ftp->quit();

Value of the Chapter Intros

In evaluating the Perl Cookbook, you may be tempted to measure the book by the recipes alone.  That would be a mistake, because you would pass over the excellent chapter introductions.  Let me just mention one such introduction: that to Chapter 21 on mod_perl.

In my day-to-day work, I have absolutely no use (yet) for mod_perl. But I like to know what's going on in all aspects of Perl, so a couple of months ago I attended the New York Perlmonger's meeting where mod_perl expert Geoff Young spoke on mod_perl 2. Now I have to admit: I really didn't know what Geoff was talking about. I didn't have the Second Edition of the Cookbook at that point, but if I did, I would have been able to follow Geoff with no problem.

Should You Buy This Book?

Programmers turn to the Camel book to learn how to do things in Perl; they turn to the Ram book to learn how to do things with Perl.

This is as true of the second edition as it was of the first.  If you have not bought the first edition and need to know Perl, buy the second.  If you already have the first edition, assess how your Perl programming needs have changed since 1998.  If they have not changed at all, don't buy the second edition.  If, however, you now need to address newer programming issues such as Unicode, mod_perl and XML, then the second edition's treatment of these issues will be worth the purchase price.  In particular, if you are part of a programming team rather than a solo practitioner (hint: this applies to the reviewer's brothers), you should definitely order a copy of the second edition, even if you already have the first.

The Perl Cookbook, 2nd edition: New Recipes

Chapter 1
Strings
 1.5    Using Named Unicode Characters
 1.8    Treating Unicode Combined Characters as Single Characters
 1.9    Canonicalizing Strings with Unicode Combined Characters
 1.10   Treating a Unicode String as Octets
 1.14   Properly Capitalizing a Title or Heading
 1.21   Constant Variables

Chapter 4
Arrays
 4.4    Implementing a Sparse Array

Chapter 5
Hashes
 5.3    Creating a Hash with Immutable Keys or Values

Chapter 6
Pattern Matching
 6.17   Matching Nested Patterns

Chapter 7
File Access
 7.6    Writing a Subroutine that Takes Filehandles as Built-ins Do
 7.13   Storing Multiple Files in the DATA Area
 7.14   Writing a Unix-Style Filter Program

Chapter 8
File Contents
 8.18   Treating a File as an Array
 8.19   Setting the Default I/O Layers
 8.20   Reading or Writing Unicode from a Filehandle
 8.21   Converting Microsoft Text Files into Unicode
 8.22   Comparing the Contents of Two Files
 8.23   Pretending a String Is a File
 8.27   Program:  Flat File Indexes

Chapter 9
Directories
 9.11   Working with Symbolic File Permissions Instead of Octal Values

Chapter 10
Subroutines
 10.17  Writing a Switch Statement

Chapter 11
References and Records
 11.15  Coping with Circular Data Structures Using Weak References
 11.16  Program:  Outlines

Chapter 12
Packages, Libraries, and Modules
 12.5   Making Functions Private to a Module
 12.13  Overriding a Built-in Function in All Packages
 12.15  Customizing Warnings
 12.19  Writing Extensions in C with Inline::C

Chapter 13
Classes, Objects, and Ties
 13.7   Copy Constructors

Chapter 14
Database Access
 14.8   Saving Query Results to Excel or CSV
 14.10  Escaping Quotes
 14.11  Dealing with Database Errors
 14.12  Repeating Queries Efficiently
 14.13  Building Queries Programmatically
 14.14  Finding the Number of Rows Returned by a Query
 14.15  Using Transactions
 14.16  Viewing Data One Page at a Time
 14.17  Querying a CSV File with SQL
 14.18  Using SQL Without a Database Server

Chapter 15
Interactivity
 15.18  Graphing Data
 15.19  Thumbnailing Images
 15.20  Adding Text to an Image
 15.23  Program:  graphbox

Chapter 16
Process Management and Communication
 16.22  Turning Signals into Fatal Errors

Chapter 17
Sockets
 17.14  Multitasking Server with Threads
 17.15  Writing a Multitasking Server with POE
 17.19  Managing Multiple Streams of Input

Chapter 18
Internet Services
 18.8   Accessing an LDAP Server
 18.9   Sending Attachments in Mail
 18.10  Extracting Attachments from Mail
 18.11  Writing an XML-RPC Server
 18.12  Writing an XML-RPC Client
 18.13  Writing a SOAP Server
 18.14  Writing a SOAP Client
 18.15  Program:  rfrm

Chapter 20
Web Automation
 20.14  Using Cookies
 20.15  Fetching Password-Protected Pages
 20.16  Fetching https:// Web Pages
 20.17  Resuming an HTTP GET
 20.18  Parsing HTML
 20.19  Extracting Tble Data
 20.21  Program:  hrefsub

Chapter 21
mod_perl
 21.1   Authenticating
 21.2   Setting Cookies
 21.3   Accessing Cookie Values
 21.4   Redirecting the Browser
 21.5   Interrogating Headers
 21.6   Accessing Form Parameters
 21.7   Receiving Uploaded Files
 21.8   Speeding Up Database Access
 21.9   Customizing Apache's Logging
 21.10  Transparently Storing Information in URLs
 21.11  Communicating Between mod_perl and PHP
 21.12  Migrating from CGI to mod_perl
 21.13  Sharing Information Between Handlers
 21.14  Reloading Changed Modules
 21.15  Benchmarking a mod_perl Application
 21.16  Templating with HTML::Mason
 21.17  Templating with Template Toolkit

Chapter 22
XML
 22.1   Parsing XML into Data Structures
 22.2   Parsing XML into a DOM Tree
 22.3   Parsing XML into SAX Events
 22.4   Making Simple Changes to Elements or Text
 22.5   Validating XML
 22.6   Finding Elements and Text Within and XML Document
 22.7   Processing SML Stylesheet Transformations
 22.8   Processing Files Larger Than Available Memory
 22.9   Reading and Writing RSS Files
 22.10  Writing XML