The Perl community is one of the most wellestablished demonstrations of the Open Source Software movement. Many people that have benefited from Perl's openness have in turn contributed libraries and scripts back to the public for others to use. The collective contributions to the Perl community have been organized into the Comprehensive Perl Archive Network, known more commonly as the CPAN.
The CPAN is not a single machine, but actually over 100 machines holding more than 750 MB of cool stuff, available for your access via anonymous FTP or, in a few cases, HTTP. They all mirror off the master site in Finland at various intervals, usually not exceeding four to eight hours, so it's usually safe to use the CPAN archive nearest to you. If you're in the US, visit http//www.cpan.org. If that site is down (which it occasionally is),or you're somewhere else in the world, try http//www.perl.com/CPAN/, which should send you to an up-and-running site that is close to you.
Once you get to the CPAN archive, you'll find all sorts of useful things, including the latest release of Perl for UNIX and other operating systems. In particular, you'll find hundreds of pre-written and tested Perl modules to handle many common tasks.
Let's look at two of those modules and how they might be used together in an interesting way. The Net::IRC module provides support for Perl to handle the Internet Relay Chat protocol. With this module, you can write an IRC bot -- a Perl program which connects to an IRC server as if it were an IRC client and interacts with that server programmatically.
The second is one of my favorite modules, Chatbot::Eliza, which implements the classic Eliza algorithm. The original Eliza program was written by Joseph Weizenbaum and was described in the Communications of the ACM in 1966: Eliza is a mock Rogerian psychotherapist. It prompts for user input and uses a simple transformation algorithm to change user input into a follow-up question. The program is designed to give the appearance of understanding.
This program is a faithful implementation of the program described by Weizenbaum. It uses a simplified script language devised by Charles Hayden. The content of the script is the same as Weizenbaum's.
I wanted to see what would happen if the Net::IRC module was hooked into Chatbot::Eliza to make an IRC bot that acts like a psychotherapist. The process was easier than I thought, and a good example of how to reuse existing code from the CPAN.
To install the two modules needed in this program, simply do the following:
$ perl -MCPAN -eshell
cpan> install Net::IRC Chatbot::Eliza
[cpan installation stuff omitted]
cpan> quit
$
That's all there is to it! This invocation will fetch the module source from the nearest CPAN archive and unpack, configure, make, test, and install them. You have to be the same user as the one that installed Perl. If you're not, invoke perldoc CPAN to get further instructions. Note that you don't have to install anything manually; CPAN.pm (which should be built into your current Perl installation) does it all for you.
Take a look at the "eliza bot" in the sidebar.
Line 1 begins the program, specifying the path to your installed Perl binary (for me, this is /usr/bin/perl)and enabling warnings (this is a good idea during development, but should always be disabled in production).
Line 2 enables the three common compiler restrictions. These restrictions disable the use of soft references (always a good idea), disable barewords being treated like strings (this keeps random typos from being ignored), and require all variables to be either explicit package variables or pre-declared with my to make them lexical. Because these restrictions make sense for Perl programs longer than ten lines or so, I usually enable them all.
Line 3 increments the value of $|. If you do this at the beginning of the program, the STDOUT filehandle becomes unbuffered instead of buffered. Here, that's a good thing, because we want to see the result of each print operation as it's being generated.
Lines 5 and 6 pull in the two modules as described earlier. These modules must be locatable in the directories specified in the compile-time @INC variable. If you need to add directories to @INC, see the documentation for the lib module (by invoking perldoc lib).
Lines 8 and 9 define two configuration constants for this program, each with a true/false value. The $IRC_debug value is passed to the Net::IRC module to enable debugging. If false, Net::IRC stays relatively quiet. If it's set to true, we get a fairly detailed tracing of all the steps and callbacks. I set $IRC_ debug to 1 while I was developing this code, but it's too noisy during normal operation, so I've set it to 0 here. The second constant, $TRACE, selects whether summary messages of everything the bot is doing gets sent to standard output. These are pretty small and can probably remain enabled during actual use.
Line 11 defines a new Net::IRC object, assigns it to $irc, and sets the debugging value for this object according to the value of $IRC_ debug, as defined above. This object represents the supervisor of all connections to various IRC servers for this particular program.
Lines 12 through 15 create an individual IRC connection. In this case, it is the sole connection for this bot, connecting as nickname eliza000 to the IRC server at the fictional host name random.place.not. Of course, to be useful, you will need to find an IRC server on the appropriate IRC network that supports the use of bots. (Most IRC servers do not allow bots, but some do.) When the code has returned from newconn, $conn holds a Net::IRC::Connection object -- our main interface for sending and receiving IRC packets.
The primary means of scripting a conversation with Net::IRC is to establish a series of event handlers. Each handler is associated with a particular event (transformed into a Net::IRC::Event object). When that event is seen (because of something the IRC server has sent to our bot), the corresponding handler is called, along with some parameters. For example, if you want to know every time someone sends a public message to a channel the bot has joined, you'll set up an event for public.
Lines 16 through 44 set up the particular event handlers that we need for this bot. I'm using a foreach loop here (spelled f-o-r but pronounced "foreach" !) to walk $_ through a list of arrayrefs. Each arrayref in turn contains two items: either a single word or another arrayref, followed by a coderef. The body of the foreachloop (in line 43) passes these arrayrefs as parameters to the add_global_handler method on the connection, resulting in the installation of a particular coderef as an event handler for one or more named events.