YA Perl Advent Calendar 2005-12-01 – 2005-12-05

Hello, as some may have noticed there's no advent calendar this year... and there was much rejoicingdismay. So I've—quite stupidly some might say—decided to take on the challenge. We're already th of the way through so you'll forgive me if I rush on the catching up and take a cue from Damian's Small Miracles. And now, on with the show. —jpierce@cpan & belg4mit@perlmonks

Below is a code listing I whipped up to fetch a list of previously featured modules, so as not to flog a deceased equine designed by committee as it were ;-). The listing features five perl modules.

Perl::Tidy aka perltidy
This utility is used for pretty printing your code, or rather your cow orkers' code since everyone reading this has read Perl Best Practices and taken it to heart, n'est-ce pas? Anyhow, perltidy can also output syntax highligthed HTML as in our example created with perltidy -html -nnn -css=style.css mods.pl.
LWP::Simple
Actually, this has already been featured twice before, so why not again? It really is quite useful and well, simple. Use it for all your HTTP GET/HEAD needs.
HTML::Parser
We actually use two of the interfaces provided in this package, HTML::TokeParser and HTML::HeadParser. HeadParser is brilliantly simple and saved me from parsing HTML with a regexp. TokeParser works well, but like many screen scraping tools you need to have a feel for the document structure and may risk future breakage. Note the difference in calling syntax however, HeadParser will read a document from a variable whereas TokeParser requires a variable reference for this behavior.
Lingua::EN::Numbers::Ordinate
This module was another nice piece of candy which prevented me from reinventing the wheel and implementing my own number English-ifier, since perladvent.org uses ordinal URIs :-( Similar modules exist for other languages, but not necessarily with similar names e.g; Lingua::PT::Nums2Ords
Text::Table
To be honest, I originally just did a print instead of $table->add() but the module is quite simple to use, even if the POD is verbose. Plus it handles alignment, prior to using sprintf to format the date for constant width by zero-padding $D I had a simple

    $table->add("$Y-12-$D", $title);    

and Text:Table still properly aligned the Module column.

mods.pl


   1 #!perl -sw
   2 #mods.pl -- Previous Perl Advent Calendar Modules v3
   3 
   4 use strict;
   5 use vars '$html'; #Switch for HTML output to provide linked module names
   6 
   7 use LWP::Simple;
   8 use HTML::HeadParser;
   9 use HTML::TokeParser;
  10 use Text::Table;
  11 use Lingua::EN::Numbers::Ordinate;
  12 
  13 my $table = Text::Table->new( qw(Date Module) );
  14 
  15 #2000 is a special case
  16 {
  17   my $content = get($_="http://perladvent.org/2000/");
  18   unless( $content ) {
  19     warn("No content for: $_\n");
  20     last; }
  21 
  22   my $parser = HTML::TokeParser->new(\$content);
  23 
  24   my $D = 1;
  25   #Cheaply lifted from the Toke documentation
  26   while (my $token = $parser->get_tag("li")) {
  27     my $title = fixTitle( $parser->get_trimmed_text("/li") );
  28     $table->add(sprintf("2000-12-%02i", $D++), $title);    
  29   }
  30 }
  31 
  32 my $header = HTML::HeadParser->new();
  33 
  34 foreach my $Y ( 2001 .. 2004 ){
  35   foreach my $D ( 1..25 ){
  36 
  37     my $content = get( $_ = sprintf("http://perladvent.org/$Y/%s",
  38 				    ordinate($D))
  39 		     );
  40     unless( $content ) {
  41       warn("No content for: $_\n");
  42       next; }
  43 
  44     $header->parse($content);
  45     my $title = fixTitle( $header->header('Title'), $Y);
  46     
  47     $table->add( sprintf("$Y-12-%02i", $D), $title );
  48   }
  49 }
  50 
  51 print $table;
  52 
  53 #Never you mind this...
  54 sub fixTitle{
  55   my($title, $year) = @_;
  56 
  57   $title =~ s/Perl $year Advent Calendar: // if $year;
  58 
  59   #These are unavailable
  60   $title = '' if $title =~ /^tbc|Perl Advent Calendar|Lost/;
  61   if( $html && length($title) ){
  62     $title = qq(<a href="http://search.cpan.org/search?module=$title">$title</a>);
  63   }
  64   elsif( ! length($title) ){
  65     $title = 'N/A';
  66   }
  67 
  68   return $title;
  69 }
Which gives us the following; well, almost. A list of all modules featured on prior perl advent calendars, see also ASCII-betical listing:
Date       Module
2000-12-01  Data::Dumper
2000-12-02  LWP::Simple
2000-12-03  POE::Component::IRC
2000-12-04  Exporter
2000-12-05  Time::Local
2000-12-06  Time::Object
2000-12-07  Tie::Scalar::Timeout
2000-12-08  Tie::HashDefaults
2000-12-09  Crypt::RC4
2000-12-10  GD
2000-12-11  Image::Imlib2
2000-12-12  File::Remote
2000-12-13  N/A
2000-12-14  XML::Grove
2000-12-15  Getopt::Long
2000-12-16  File::Find
2000-12-17  DBI
2000-12-18  Memoize
2000-12-19  Storable
2000-12-20  Inline
2000-12-21  Class::Virtual
2000-12-22  Class::Multimethods
2000-12-23  Symbol::Approx::Sub
2000-12-24  Template
2000-12-25  Date::Christmas
2001-12-01  Mail::Audit
2001-12-02  Mail::ListDetector
2001-12-03  Tie::DBI
2001-12-04  File::Spec
2001-12-05  XML::XPath
2001-12-06  Acme::Pony
2001-12-07  Scalar::Util
2001-12-08  List::Util
2001-12-09  GraphViz
2001-12-10  Test::More
2001-12-11  POE
2001-12-12  POE::Component::Client::HTTP
2001-12-13  Crypt::Solitaire
2001-12-14  Spreadsheet::WriteExcel
2001-12-15  Pod::Coverage
2001-12-16  Tie::Hash::Cannabinol
2001-12-17  Attribute::TieClasses
2001-12-18  Attribute::Overload
2001-12-19  Class::MethodMaker
2001-12-20  ExtUtils::ModuleMaker
2001-12-21  Exporter::Simple
2001-12-22  Text::Autoformat
2001-12-23  Inline::Files
2001-12-24  Quantum::Superpositions
2001-12-25  Parse::RecDescent
2002-12-01  URI::Find
2002-12-02  IO::AtomicFile
2002-12-03  DBD::SQLite
2002-12-04  Test::Builder
2002-12-05  Image::Size
2002-12-06  Devel::Size
2002-12-07  File::MMagic
2002-12-08  XML::Handler::AxPoint
2002-12-09  XML::SAX
2002-12-10  Params::Validate
2002-12-11  File::Find::Rule
2002-12-12  Object::Realize::Later
2002-12-13  Benchmark
2002-12-14  Test::MockObject
2002-12-15  YAML
2002-12-16  WWW::Mechanize
2002-12-17  Acme::Intraweb
2002-12-18  CPANPLUS
2002-12-19  Inline::TT
2002-12-20  Class::Data::Inheritable
2002-12-21  Tie::File
2002-12-22  XML::LibXML
2002-12-23  Class::DBI
2002-12-24  Pixie
2002-12-25  Devel::DProf
2003-12-01  CGI::Untaint
2003-12-02  HTML::Entities
2003-12-03  Hook::LexWrap
2003-12-04  PPerl
2003-12-05  Template::Extract
2003-12-06  Mail::SpamAssassin
2003-12-07  Attribute::Handlers
2003-12-08  CGI::Application
2003-12-09  Data::Dimensions
2003-12-10  Test::Inline
2003-12-11  File::chdir
2003-12-12  Class::ISA
2003-12-13  only
2003-12-14  Date::Parse
2003-12-15  Text::Glob
2003-12-16  Math::BigInt
2003-12-17  diagnostics
2003-12-18  PDF::Reuse
2003-12-19  Acme::Code::FreedomFighter
2003-12-20  Regex::Common (sic)
2003-12-21  Inline::Java
2003-12-22  LWP::Simple
2003-12-23  N/A
2003-12-24  Data::Structure::Util
2003-12-25  PAR
2004-12-01  DateTime
2004-12-02  Term::ANSIColor
2004-12-03  Class::Accessor::Chained
2004-12-04  String::ShellQuote
2004-12-05  CPAN::Mini
2004-12-06  Module::Pluggable
2004-12-07  Term::ProgressBar
2004-12-08  Data::Dumper::Simple
2004-12-09  Proc::Daemon
2004-12-10  Data::UUID
2004-12-11  Encode
2004-12-12  Text::Unidecode
2004-12-13  Devel::Trace
2004-12-14  SQL::Abstract
2004-12-15  Archive::Extract
2004-12-16  Cache::Cache
2004-12-17  Mac::Glue
2004-12-18  Acme::Drunk
2004-12-19  N/A
2004-12-20  Filesys::Virtual
2004-12-21  Sys::Hostname
2004-12-22  N/A
2004-12-23  N/A
2004-12-24  N/A
2004-12-25  N/A