The Lighter Side of CPAN
All I Ever Needed to Know About Perl I Learnt from a Pun
by Alex GoughOctober 31, 2001
Programming can be a stressful game. We sit at our machines, day in, day out, endlessly staring at a monitor fathoming where that last devious bug has buried itself. It's not surprising then that sometimes it gets to be too much, and someone, somewhere, snaps. The strangest things become hilarious and valuable hours will be wasted developing a strained play on words into a fully tested and highly featured module.
Portions of this creative outpouring of humor often find their way
onto the CPAN. There is even the special Acme::* name space set
aside for these bizarre freaks so they do not interfere with the
normal smooth running of that ever so special service. It may seem a
little pointless for someone to release these into the wild, but you
may be surprised what you could learn from them. A good joke is
usually marked out by being both funny and simple, and the same applies
to jokes told in Perl. All unnecessary detail is stripped away,
leaving a short piece of code that makes a perfect example of how to
use, abuse or create a language feature.
There now follows a brief tour of some (but not all) of the more amusing extensions to Perl, along with some hints on how you might improve your programs by taking inspiration from the tricks they use to implement their punch lines. (Ba-boom tching!)
Getting It Wrong the Wright Way
Perl is a lazy language. It appeals to the discerning man of leisure who wants nothing more than a chance to get things done quickly. There are some who would have Perl be more lazy but, until rescued by Dave Cross and his band of visionaries, they were forced to work hard making sure that every single keystroke they made was correct. Dismayed by errors like:
Undefined subroutine &main::find_nexT called at frob.pl line 39.
many turned away from Perl. Now they return in droves, using
Symbol::Approx::Sub, their lives are made an order of magnitude
easier, leaving them more time to sip cocktails as they lounge in
deck chairs. This module can even save you money; observe the simple
calculation of your fiscal dues after the careful application of a
couple of typos:
#!/usr/bin/perl use Symbol::Approx::Sub;
sub milage { 40_000 };
sub taxipay { 10 };
sub tax2pay {$_[0]*0.4 };
sub myage { 25 };
# Sell car
print "For Sale: Very Good Car, only @{[ miage()]} on the clock\n";
# Cheque for tax man
my $income = 40_000;
print "Must pay taxes, cheque for: @{[ taxpay($income) ]}\n";
A calculation which could not be faulted by any government, but which will leave you with a brand new car and, half the time, a whopping rebate:
For Sale: Very Good Car, only 25 miles on the clock Must pay taxes, cheque for: 10
How does this all work? There are two major bits of magic going on: installing a handler that intercepts calls to undefined subroutines and a tool for divining the names of those routines that it can call instead.
The handler is implemented by creating an AUTOLOAD function for the
module that uses Symbol::Approx::Sub. When Perl is asked to
run a subroutine that it cannot locate, it will invoke AUTOLOAD in
the package where it was first told to look for the subroutine. This
is handed the same arguments as the original function call and is told
which subroutine Perl was looking for in the global $AUTOLOAD
variable. AUTOLOAD is mainly used to write lazy accessors for
object data, this example:
sub AUTOLOAD {
my ($self, $value) = @_;
my ($field) = $AUTOLOAD =~ /.*::(.*)$/;
return if $field eq 'DESTROY';
return @_==1 ? $self->{$field} : $self->{$field} = $value;
}
provides simple get/set methods. So that:
$object->name('Harry');
print $object->name, "\n";
prints Harry even though you haven't had to explicitly write a
name method for your object.
Perl stores all information about non-lexical variables, filehandles
and subroutine names in a massive hash. You can inspect this yourself
but doing so requires code that is so close to spaghetti you could
plate it up and serve it to an Italian. The easy way out, wisely
taken by the Symbol::Approx::Sub module, is to use the
Devel::Symdump module that provides a friendly and clean interface
to Perl's symbol table. Devel::Symdump provides various useful
tools: If you are scratching your head trying to resolve an
inheritance tree, then the isa_tree method will help; if you want to find
exactly what a module exports into your namespace, then you'll find the
diff method a constant friend.
Presently Living in the Past
Ever since the ancients erected the huge lumps of stone that paved the way for the digital watches that we hold so dear, mankind has needed to know when he is. Perl is no different and now has many -- although some might say too many -- date- and time-related modules, around 80 of them in fact. Simple statistics tell us that at least a few of those should be so useless we couldn't possibly resist trying to find something to do with them.
Date::Discordian, although lacking in chicken references. Gobble.
This could, in a limited set of circumstances, be helpful though. Imagine the scene: a trusted client is on the phone demanding a completion date for the project doomed to persist. You reach for the keyboard and, in a moment of divine inspiration, type:
perl -MDate::Discordian -le'print discordian(time+rand(3e7))'
You then soberly relate the result to your tormentor, ``Prickle
Prickle, Discord 16 YOLD 3168'' and, suddenly, everything is alright.
Well, they've put the phone down and left you in peace. If you
prefer to provide a useful service, then you might be better off
investigating the Time::Human module by Simon Cozens. This creates
person-friendly descriptions of a time, transforming the excessively
precise 00:23:12.00 into a positively laid-back ``coming up to
25 past midnight.'' The module is internationalized and could
be used in conjunction with a text-to-speech system, such as festival,
to build an aural interface to something like a ticket-booking system.
Moving swiftly on, we come to Date::Tolkien::Shire, a king amongst date modules. Most newspapers carry an ``on this day in history'' column -- where you find, for instance, that you were born on the same day as the man who invented chili-paste -- but no broadsheet will tell you what happened to Frodo and his valiant companions as they fought to free Middle Earth from the scourge of the Dark Lord. The undeceptively simple:
use Date::Tolkien::Shire; print Date::Tolkien::Shire->new(time)->on_date, "\n";
outputs (well, output a few days ago):
Highday Winterfilth 30 7465 The four Hobbits arrive at the Brandywine Bridge in the dark, 1419.
What better task could there be for crontab but to run this in the wee
hours and update /etc/motd for our later enjoyment. Implementing
this is, as ever, left as an exercise for the interested reader.
There is a more useful side to Date::Tolkien::Shire or, at the very
least, it does light the way for other modules. As well as the
on_date() method it provides an overloaded interface to the dates it
returns. This allows you to compare dates and times as if they were
normal numbers, so that:
$date1 = Date::Tolkien::Shire->new(time); $date2 = Date::tolkien::Shire->new(time - 1e6);
print 'time is '.( $date1 > $date2 ? 'later':'earlier' ).
"than time -1e6\n";
prints time is later than time -1e6, the more prosaic
Date::Simple module provides a similar interface for real dates and
ensures they stringify with ISO formatting.
Pages: 1, 2 |





