Reviews by Chris Dolan



Pod-POM-Web (1.03) *****

Pod-POM-Web is an on-the-fly HTML interface to all of the Perl modules installed on the local machine. Think of it like a subset of on your computer, but much faster.

This is a fantastic module. It's kind of like App::Ack: it's the tool I hadn't realized I was missing until I tried it.

The author has been very responsive to the minor bugs I've reported. The code is tight yet readable.

Net-IP-Match-Regexp (0.94)

(Everyone: sorry to reply here, but I couldn't find an email address for Nick, who posted a rating earlier today...)

Nick, please post bug reports at, not From your brief description of the problem, it appears that you are passing a net mask to the match_ip(), which expects a single IP addresss. That is, you have called "match_ip('', $re)" when you should have called "match_ip('', $re)". The documentation states that match_ip expects "...a single IP address as a string of the form C<aaa.bbb.ccc.ddd>...". The docs also say "WARNING: This function does no checking for validity of the IP address."

If you have any further problems, please contact me offline. Net::IP::CMatch is a very nice alternative to this module, but for matching against a large set of IP ranges, my module is actually faster, thanks to Perl's powerful regexp engine.

Chris Dolan, author of Net-IP-Match-Regexp

Params-Util (0.15) *****

Params::Util is a collection of small functions to check data types. For example, _HASH0($var) returns a boolean indicating if $var is a hashref. _INSTANCE($var, $pkg) is just like $var->isa($pkg) but doesn't crash if $var is undef and is faster than eval{$var->isa($pkg)}.

Most of these functions are trivial, and you could probably write the equivalent yourself. But, as a collection they are high-quality and lend concise readability to your code.

My only complaint is that _HASH($var) and _ARRAY($var) return false if the hash or array (respectively) is empty, which is not very intuitive. Instead, you should probably use the awkwardly named _HASH0($var) and _ARRAY0($var).

File-Copy-Recursive (0.19) ****

This module recursively copies directories, preserving permissions like "cp -pr". I was surprised to discover that there are only two recursive copy modules on CPAN: this one and the older File::NCopy.

The File::Copy::Recursive interface is simple enough: dircopy($srcdir, $destdir). However, it is significantly overcomplicated by a pile of poorly-named global variables that allow the user to tweak behavior. The code itself is very hard to read and I had great difficulty tracking down the source of a chmod bug. Update: the bug is fixed and the author is VERY responsive!

The source code to File::NCopy is dramatically simpler, but that module has a rather odd way to signal recursion via a scalar reference that I find annoying.

Chemistry-PointGroup (0.01)

The author has released Chemistry-PointGroup-* as 33 separate uploads to CPAN, one .pm per package. I can't claim to understand what this module does (so I have not rated it), but it seems bizarre to me that the author couldn't have packaged all of these closely-related modules into a single distribution. Even setting aside the inconvenience to end users to have to download and install all 33 of those, it must have been a lot of work for the author!

SOAP-Lite (0.67) ****

SOAP-Lite implements a huge range of web service functionality. "Lite" is a misnomer IMHO. The interface is very perlish. An experienced user of SOAP-Lite can build or access a service with a tiny amount of code. WSDL support is limited, but effective.

The documentation is adequate, but just barely. This is a package that has great power buried in its guts, but most users should expect to just use the common features unless they want to expend a lot of time learning. Expect to spend a LOT of time debugging (or just figuring out how to debug). The package sorely lacks for good examples. The provided examples are either trivially simple, or head-scratchingly complex.

Whatever you do, *DON'T* look at the code if you can help it! This is the hardest to read CPAN module I've ever seen. It borders on Perl Golf complexity in places. I've spent the last few months working closely with SOAP:Lite -- at first I craved to rewrite it, but now I wouldn't dare. The author, Paul Kulchenko, is either a genius or a madman. Probably both, I'd guess.

My greatest fear is that there is some huge security hole in this package. I have no reason to believe there is one, but the code is so complicated that I'm not sure how one would manage to audit all of it.


Update for v0.67: Byrne Reese seems to be working hard to decipher and fix parts of this code, based on the number of new "TODO"s and CHANGES entries. Kudos to Byrne for taking on this difficult task.

This particular release has a rather painful wart. The SOAP::Lite::uri() method, which is called by EVERY SOAP::Lite client, has been deprecated. However, even the SOAP::Lite code itself was not updated to avoid calling this method! There are also 6 places where the documentation still shows examples using this deprecated method.

If you are a SOAP::Lite user, try to avoid v0.67.

Test-Spelling (0.10) *****

This highly useful module parses out your POD, filters out Perl-specific words, and pipes the rest to aspell/ispell/etc. Any unknown words are reported as Test::More errors. The vast majority of the work is done by Pod::Spell, but this module puts a supremely useful wrapper on it.

My only complaint is that the documentation lacks discussion about how to flag words to ignore on a per-file basis. The easy answer is to put a line like the following at the BEGINNING of the POD:

=for stopwords xyzzy quux CPAN

File-Slurp (9999.09) *****

Overall, I like this module a lot and use it constantly. I have one huge complaint though. There is a critical dataloss bug in the current version that has been unaddressed by the author for the last two weeks.

This command will truncate the file "foo" to zero bytes regardless of what's in the file.

perl -MFile::Slurp -e'append_file("foo", "")'

This could be fixed by a simple workaround: in the append_file function:

return if (-e $file && $content eq "");

UPDATE: The above bug is fixed and I love this module again! Thanks, Uri.

Perl-Critic (0.08_02) *****

Perl-Critic is a source code analyzer that judges your code by the standards set by Damian Conway's book "Perl Best Practices". I tried it on one of my modules (via perlcritic `find lib -name '*.pm'`) and found all of the advice to be good with one exception (already reported to

My one main complaint:

* There should be a little more explanation for the criticisms. Granted, the module does state page numbers for Damian's book, but some of the criticisms forced me to look at the code to understand why it was complaining (e.g. the noisy quoted string complaint). Perhaps a verbose mode to describe the criticism more deeply, or a DIAGNOSTICS section in the POD to detail all of the warnings

I encourage someone to write Test::Perl::Critic or perhaps to add a Module::Build perlcritic action!

Video-Info (0.999) *

This module is just the result of h2xs. There is no code. This should be removed from CPAN.

It appears that the previous version (v0.993) had some significant code and documentation, but this version (v0.999) looks like a mistake.

Video-Manip (0.03) *

This module has no documentation. I have no idea what it does, other than that it does something with events. Even the code in the examples directory sheds no light on the purpose of this module. What video format is it attempting to manipulate???

CGI-WebGzip (0.12) ***

[disclaimer: I'm the author of CGI::Compress::Gzip, which provides similar functionality]

This module auto-detects if the client browser supports Gzip compression and, if so and if appropriate, compresses STDOUT. Similar functionality is provided by:




This module might have earned a "4" overall, but it does not have any tests and (less significantly) the documentation does not include a discussion of similar modules. I know from personal experience that the tests are the hard part of this functionality.

Unlike CGI::Compress::Gzip, this module is not a subclass of CGI. That is either a good thing or a bad thing, depending on whether you're after ease of use or speed. This module is much lighter weight than CGI::Compress::Gzip.

My brief perusal of this code suggests that under mod_perl, the programmer might need to explicitly close STDOUT for it to work, but I'm not positive.

Net-ICal (0.15) **

This is a nice and very useful module for manipulating iCal/vCard files. However, it is unmaintained and slightly buggy. Bugfix patches have languished in the request tracker for almost two years.

With those patches, this module is worthwhile. Without them, I instead recommend that people use other modules like iCal-Parser.

Rose (0.013) *

This package has a version number and nothing else. The author admits this is alpha code, but don't you think you should have some actual CODE before releasing to CPAN? If you just want to group some modules under a version, use a Bundle.

FOLLOWUP: the author contacted me to explain that he posted the empty module just to synchronize the other required packages in a user-visible way (he suggests that a bundle is not user visible because it is never installed).

What I say is that either the related modules are so related that they should be in the same package, or they are loosely coupled enough that their version numbers should be independent. In either case, this empty version holder module is unnecessary.

guestbook (0.5) *

This is a poorly named, packaged and authored CGI application. The documentation is bizarre (it even suggests that you need Perl to run the guestbook application).

Class-Autouse (1.12) *****

Class::Autouse lets you pre-declare classes you intend to use, but doesn't actually load them until the first time you invoke one of their methods. This is a clever hack to avoid run-time loading of modules that you might not actually use.

I haven't used this extensively yet, but the documentation is great and it seems like the author thought of all the important caveats.

MIME-Base64 (3.05) *****

This module translates content to or from a Base64 encoding. Base64 is a technique for encapsulating binary data in ASCII so that it can be transmitted by protocols that don't handle binary very well, like email.

This module is particularly useful for attaching files to Perl-generated email messages.

This module is pleasantly easy to use. It is widely used by other modules which implement Base64 functionality (Perl::via::Base64, Mail::SendEasy::Base64, etc).

See also MIME::Base64::Perl, which implements the same algorithm in Perl instead of in C -- slower, but nice if you don't have a compiler available.

Digest-MD5 (2.33) *****

Computes MD5 hashes on any input, and outputs as binary, hex or base64.

Simple, fast, correct. This is an ideal library.

IO-Zlib (1.04) *****

IO::Zlib is a handy wrapper around the Compress::Zlib library that allows reading and writing of compressed content via a standard Perl filehandle. The module's emulation of a filehandle is flawed, but that's primarily due to limitations of the Compress::Zlib library, which requires a real fileno for IO, so pseudo-filehandles (like IO::String) will fail.

The documentation is adequate, but could use a discussion of the module's limitations and references to alternatives (i.e. PerlIO::gzip).

Apache-Htpasswd-1.5.5 (Apache-Htpasswd-1.5.5) ****

This is a handy read/write encapsulation of httpd password files (usually called .htpasswd). The methods are awkwardly named, but otherwise the module is very easy to use.

One notable misfeature is that an existing password of a single digit may be misinterpreted as a flag to force overwriting the password instead of validating that password. The documentation also omits that the login name may be substituted for an undefined new password under some circumstances.

While this package is very useful as-is, a refactoring into a 2.0 release with an overhauled interface would be worthwhile.

Module-Build (0.20) *****

Module::Build is a superb package. It intends to replace ExtUtils::MakeMaker and the ubiquitous Makefile.PL files with Build.PL files. I hope it succeeds!

It is very friendly to subclassing and it is fairly easy to read. Don't let the low version number fool you. This package is nearly ready for prime-time.

The changes I've noticed are that it's stricter about where it looks for some files. *.pm files must live in a lib/ subdirectory, which is a good idea in the long run I think.

D-oh (0.05) **

D::oh a tiny module for redirecting STDERR and STDOUT. It's really not very useful, since it can be replaced with a couple of lines of simple Perl code. Instead, it's intended to be a CPAN joke.

While funny, use of the D namespace is bad form. It should be Debug::Doh or something like that.

The synopsis is wrong. The output it putports to yield is incorrect.

The module has sortFile in it's @EXPORT_OK. Huh? There is no sub sortFile in the module, nor is sortFile employed.

The module unnecessarily imports on File::Basename.

Chris Nandor: It's bad form to rate your own module without saying as much in the review, let alone giving that module a 5.

Lingua-EN-Numbers (0.01) ***

[See also: Lingua::Num2Word, which is a cool wrapper for number -> word converters in serveral languages.]

This module converts numbers to the English equivalent (for example 20 => "Twenty"), in either American or European style. The module is object-oriented, but makes heavy use of class variables, which is a serious weakness IMO.

Compare to Number::Spell, which has less functionality but a simpler interface.

Getopt-Long (2.32) *****

Getopt-Long adds a polished feel to a command line program. It supports all the typical Unixy conventions for flags and arguments. Combined with the Pod::Usage module from the PodParser distribution, it makes for a complete, self-documenting framework for an application.

Math-RPN (1.08) ***

This module is a straightforward RPN calculator implementation. The code is very readable, but the packaging is abysmal. The author simply tarred and uploaded a single .pm file, lacking a license, Makefile.PL, or a README.

If the packaging were polished, I would probably give this module a rating of 5.

Number-Spell (0.04) ****

This is a simple module that converts a positive integer to its English equivalent (e.g. 20 => twenty). It has support for American and European conventions for the meaning of "billion" and up. The interface consists of a single exported subroutine. I use it for spelling out numbers in checks.

The author is unresponsive as of the time of this review. If anyone is interested in an extension to this module that has support for zero, negative numbers and limited support for decimal numbers, email me at CDOLAN @

Update: I just learned about Lingua::EN::Number which has similar functionality, but appears to be much better written and supported.

WeakRef (0.01) *

Do not use this module! It is obsolete. The functionality has been absorbed into Scalar::Util, which is part of the Scalar-List-Utils package.

Net::FTP / libnet (1.16) *****

Net::FTP offers an object-oriented FTP client. It is beautiful. Like most of Graham Barr's work, this package is polished and professional.

RTF-Parser (1.07) ***

My exposure to this module is solely through the rtf2html utility. It only supports a subset of RTF and makes pretty bad looking HTML, but it works and makes readable, if ugly, documents.

There is NO documentation for this module other than a few lines of README!

Email-Valid (0.14) *****

Email::Valid takes an email address as a string a returns a boolean whether it is valid or not.

This is the epitome of a good, small CPAN module. It solves a problem well that many programmers have solved poorly. It's easy to use and understand and it does one thing very well and that's it.

Mail-Addressbook-Convert (1.1) **

This package is used to convert mail addressbooks from one format to another. It does this by internally converting them to Eudora format and back out, with some degree of lossiness.

The mechanism to add new addressbook formats to the family is fairly obvious, but an understanding of the Eudora format is a prerequisite, which is quite annoying. Some of the converters are incomplete and data is discarded (e.g. importing LDIF data apparently discards everything except alias, realname and email).

This code is quite crufty. While the author should be greaty commended for delving into all the addressbook formats, the package badly needs a rewrite. I tried to add vCard formats for input/output but have been stymied so far by my lack of familiarity with Eudora and it's address syntax.

Spreadsheet-ParseExcel (0.2602) ****

Combined with Spreadsheet::WriteExcel, this module allows automated interaction with Excel files. It primarily provides access to the data in the files, not the formatting, but the latter is of limited use anyway.

The interface to the data is pretty obvious. The "Fmt" files use to filter the data coming out of the document are far from simple or obvious. I found it necessary to write my own for handling Excel documents that are near-ASCII.

A major limitation is that the entire Excel document is parsed at instantiation. This means that opening a document has large latency, while subsequent reading through the data is quick. A rewrite to allow quick, random access into the Excel doc would be very valuable, although likely difficult...

Spreadsheet-WriteExcel (0.41) ****

Combined with Spreadsheet::ParseExcel, this module allows dynamic interaction with Excel documents as data stores. The biggest limitation is that fields are limited to 255 characters. This prevents interaction with the full range of documents. This module provides substantial support for the appearence-oriented features of Excel docs.