Reviews by Ben Bullock



Data-Uniqid (0.12) *****

This module creates a unique id by printing a base 62 version of the time and the process number, and the hostname if you want a globally unique ID.

I've been using this to generate about 300 IDs a day on a public-facing web service for about six years. I have not had any problems with it. I require IDs which are unique to my pages only, not globally unique.

MIME-Type-FileName (1.0)

The module is very simple and minimal. It consists of a small piece of code which is run when the module is used, which maps a hash of file endings to mime types, a routine called "guess" which strips the file extension and returns the equivalent mime type, or "application/octet-stream" if no extension is found, and a big block of data of extension to file name.

Unfortunately it overwrites its own values, so .jpeg turns into image/pjpeg, as reported here:

The provenance of the list of mime types is also unknown, the author doesn't mention where it comes from, but there are some definitely wrong ones like "application/x-javascript" which should be "application/javascript". The IANI list is online and available in text form for anyone to copy here:

so that kind of issue shouldn't have arised.

I wonder why the author created this module. I remember using MIME::Types back in 2008 or so, and the first version of this one dates from 2012. Good old MIME::Types gets 13/16 file names to correct mime types in my test, but this only gets 8/16. What was the original motivation for making another file extension to mime type module? It's not documented.

Anyway it is nice and simple, and self-contained, but unfortunately not very accurate.

For a comparison with similar modules, please see my page at

MIME-Detect (0.08)

MIME::Detect offers two ways to get the MIME type. One is "mime_types", which gets the mime type from the file itself, similar to File::MMagic or File::Type. The other is "mime_types_from_name", which looks at the extension part of the file name, like ".txt" or ".png". Both of these functions return a list of mime types in case more than one pattern matches.

MIME::Detect uses a very large XML file from for the matching patterns.

In the tests I tried, MIME::Detect performed fairly well, although the "mime_types" method couldn't detect some formats. The failures included executable files, files containing old encodings, and the old Microsoft BMP image format.

MIME::Detect was last updated in 2016 and seems to work well on most file types, so it seems this can be recommended for modern people.

Unfortunately though, it is by far the slowest of all the modules I tried. Loading and using this single module actually takes much more time than loading and checking the types of the files with all the other modules, "File::MMagic", "File::MMagic::XS", "Media::Type::Simple", "MIME::Types", "File::LibMagic", and "File::MimeInfo", combined.

Here is the time of my test with all the lines related to MIME::Detect commented out, but with all of the other above modules:

real 0m0.495s
user 0m0.440s
sys 0m0.056s

Here is the time after MIME::Detect is uncommented:

real 0m1.918s
user 0m1.768s
sys 0m0.150s

A bit slow! I have not profiled to find out what causes this slowness, but it's probably because the module parses a two megabyte XML file each time it is started.

It would make sense to preprocess the huge XML file, and distribute the preprocessed version, rather than parse the huge XML file each time the module is used. The bulk of the XML file is actually comments describing what the mime types are in various languages.

Regarding the documentation, the list of all the other modules for detecting mime types in the module's SEE ALSO is useful.

For a full comparison including source code and results on various files, see

MIME-Types (2.13)

It seems to work well enough. The results are almost, but not quite, identical to File::MimeInfo. For example an Excel file gets this:

File::MimeInfo: application/
MIME::Types: application/

but a bmp file gets this:

File::MimeInfo: image/bmp
MIME::Types: image/x-bmp

Unlike Media::Type::Simple it has enough sense to return an undefined value when it sees an extension it doesn't recognise, rather than throw a fatal error. Unlike File::MimeInfo, it doesn't try to open the file and guess what is inside it, which may be better in some circumstances.

For a full comparison including source code and results on various files, see

File-MMagic (1.30)

All the reviews are very negative, but the module is self-contained and works well as far as it goes, which is in identifying file formats which were common ten years ago. It has more successes at identifying files than File::Type in my tests.

The formats it recognises are dated though, it doesn't recognise modern executable formats, XML, SVG, can't really distinguish when there are non-ASCII bytes in the file, but it does a better job than File::Type in several cases.

But it seems nearly abandoned judging from the bug reports. Perhaps this module is ripe for adoption.

For a full comparison including source code and results on various files, see

File-MimeInfo (0.28) *****

If you want to go from file extension to mime type, this module does the job well, and additionally if it cannot work out what the mime type is from the file extension, it tries to read a bit of the file and work out from that whether it's binary or text.

A rival for this module is Media::Type::Simple, but that module is inconvenient in that you have to strip out the file extension yourself, and for some reason Media::Type::Simple throws a fatal error when given a file extension it doesn't recognise.

Although the results of the two modules are mostly identical, File::MimeInfo seems to give marginally better mime types for some kinds of data.

Anyway, this module seems useable to me.

For a full comparison including source code and results on various files, see

Media-Type-Simple (v0.31.0)

Since there doesn't seem to be a "Media::Type" or even a "Media::Type::Complicated" or "Media::Type::Difficult" the naming of the module is somewhat suspect.

The module itself is very unpretentious, only mapping from file extensions to mime types and back.

So far so good, but for some insane reason it dies if you send it an extension it doesn't recognize, rather than just returning the undefined value:

eval {
my $media_type = type_from_ext ('kangaroo');
if ($@) {
print "Died like this: $@";

$ perl
Died like this: Unknown extension: kangaroo at line 8.

Why does it die like that? That means I have to wrap every single use of this in an eval in case some file or another which I'm trying to find the type of has some unknown extension - essentially I have to test the file extension before I give it to this, or something equally ridiculous.

If you are writing code which is meant to tell the user what type something has, throwing a fatal error when the user sends you something of unknown type is not a sane practice. That is like inviting people to ask you questions, and then pulling out a gun and shooting someone if they ask you a question you don't know the answer to. Just say "I don't know", and return the undefined value!

As far as the results go, on various types of file it gives more or less identical results to File::MimeInfo, with a few exceptions. For example ".bmp" got me "image/x-ms-bmp" with this but "image/bmp" with File::MimeInfo, and .gz got me "application/x-gzip" from this, but "application/gzip" from MIME::Types and File::MimeInfo.

The fatal errors from unknown extensions part is stupid, but apart from that it seems to work well enough.

For a full comparison including source code and results on various files, see

File-Type (0.22)

This one more or less works for the basic cases, as long as you only need file types that were common up to 2004. Some interesting failures were that it labelled an Excel file (old format) as an msword file, a pure ASCII file as "application/octet-stream", and it seems to like adding "x-" in front of things, so you get "image/x-png" for png images, or "image/x-bmp" for bmp images. Interesting successes were that, unlike File::MMagic, it managed to spot non-ASCII bytes in a text file, and it managed to distinguish an executable from a stream of binary data. It has no idea about XML or SVG and puts anything remotely Unicode into "application/octet-stream".

For a full comparison including source code and results on various files, see

File-Type-WebImages (1.01)

If you already know that the file is an image file, and you want to find out whether it is a PNG, BMP, GIF, or JPEG, this can do that job for you. Other than that it returns undefined for everything, including SVG, which it doesn't handle.

But if you already know that you have image data, you probably already know the format as well, and as it mentions in its own documentation, any of the other modules on CPAN can tell you the mime type, so I can't see what use this is.

For a full comparison including source code and results on various files, see

File-MMagic-XS (0.09008)

It's called File::MMagic::XS but it is not compatible with File::MMagic, you have to use ":compat" to get the same interface, and even then it doesn't return the same results as File::MMagic, so it might as well have been released under a different name.

I thought it did a reasonable job on the files I tried it with. Where it differs from File::MMagic, it guesses better than File::MMagic does, and File::MMagic guesses better than File::Type.

For a full comparison of the mime type modules on CPAN, see

File-LibMagic (1.15) *****

Of the modules on CPAN which attempt to guess mime types by reading the file, rather than from looking at the extension, File::LibMagic seems to be the best one both in terms of speed and accuracy.

Unfortunately, the underlying library cannot properly detect encodings, and falsely claims UTF-8 to be "binary".

The solution I eventually settled on for my job was a combination of "read_binary" from File::Slurper, "valid_utf8" from Unicode::UTF8 to validate the encoding, and "info_from_string" from this module used on the text read in by "read_binary". I decided to use File::LibMagic rather than MIME::Detect because MIME::Detect is extremely slow to load and operate, and the encoding problems this has could be worked around using the above methodology.

For a full comparison including source code, see

Text-Unaccent (1.08)

As you can see from these test results:

this has had an unpatched bug report for ten years or so where it doesn't cope with sixty-four bit systems:

It's regrettable that people are using this as a dependence even now:

Another thing worth noting is that this module completely ignores Perl's Unicode encoding. Try commenting out the "use utf8;" in the following:

use utf8;

use Text::Unaccent;

my $charset = 'UTF-8';

my $string = 'ÀÁÂÃÄÅAあ';

print unac_string($charset, $string);

The output results will be identical.

HTML-Laundry (0.0107)

This module is similar to HTML::Scrubber and HTML::Restrict in that it's based on HTML::Parser, and it produces very similar results to the other two modules.

It differs from HTML::Restrict in having a list of default tags and attributes, and also the attributes allowed and restricted are not specific to each tag, but are global for all HTML tags.

When I used it there seemed to be some problems with character text, which I reported here:

Other than that, the module worked well. The startup time is comparable to HTML::Scrubber and faster than HTML::Restrict.

Unlike HTML::Scrubber and HTML::Restrict, the module seems to be restricted to XHTML output only.

The documentation for this module suggests that it is specifically for HTML snippets, but both HTML::Restrict and HTML::Scrubber work perfectly well for snippets too, and this works perfectly well for full pages of HTML, so I'm not sure what the intention was.

If you need XHTML, this module might be preferable, on the other hand if you don't need XHTML I suggest using HTML::Scrubber or HTML::Restrict.

For a list of similar modules and links to other reviews, please see my page at

HTML-Restrict (2.2.4) *****

Of the HTML tag restricting modules on CPAN, this, along with HTML::Scrubber, is reliable and can be recommended. Like HTML::Scrubber, it's based on HTML::Parser, and its outputs are very similar to HTML::Scrubber's.

* It is quite significantly slower to load and about 1/3 slower to run than HTML::Scrubber. It is about five times slower than HTML::Strip.

* Both of the modules have a nearly identical bug related to the <br> tag:



* Like HTML::Scrubber, it doesn't convert tags into a reasonable whitespace equivalent, so text containing <br> tag like

I wondered lonely as a cloud<br>That floats on high o'er vales and hills,

will be converted into

I wondered lonely as a cloudThat floats on high o'er vales and hills,

HTML::Strip doesn't have this bug, but it has another one related to adding whitespace where it isn't necessary.

* Unlike HTML::Scrubber, it doesn't turn > and < into HTML entities, which means it's more useful for converting HTML into text.

In the end, this was the module I chose to use, because
* I can easily preprocess around the <br> issue;
* Failing to process Unicode is a huge nuisance for me, so HTML::Laundry is out;
* Pre-and-post processing of the HTML to remove duplicate text takes far longer than the running time of HTML::Restrict, and I'm not doing it in response to user input but to make static text versions of HTML pages for searching within them, so the speed of HTML::Strip gains me little;
* Not having to remove the HTML entities from the output text as I would do with HTML::Scrubber is a minor convenience which tips the balance in favour of HTML::Restrict.

For a list of similar modules and links to other reviews, please see my page at

HTML-Scrubber (0.15) *****

This module works correctly to remove unwanted HTML tags from text.

The output is nearly identical to that of HTML::Restrict. Differences include:

* Scrubber converts > and < into HTML entities, whereas Restrict doesn't. Scrubber doesn't, however, convert & into an HTML entity, as it should do if it's going to convert < and >. This bug will bite you if you have both & gt; (ampersand, lower case g, lower case t, semicolon) and > in your input. (Incidentally, CPAN ratings has the same bug:

* Scrubber leaves all the whitespace at the beginning and end of the text, whereas Restrict removes it (even including the final newline, which seems like a bug to me.) If you use the following:

my $hr = HTML::Restrict->new (

trim => 0,


you get identical outputs from either one.

* In the following test, using File::Slurper to read and write 300 HTML files, Scrubber is about 33% faster than Restrict, and about 1/3 as fast as Strip:

With Scrubber 0.15:

$ time ./

real 0m2.921s
user 0m1.145s
sys 0m0.008s

With Restrict 2.2.3:

$ time ./

real 0m4.442s
user 0m2.323s
sys 0m0.008s

With HTML::Strip 2.10:

$ time ./

real 0m0.900s
user 0m0.111s
sys 0m0.055s

For a list of similar modules and links to other reviews, please see my page at

HTML-Strip (2.10)

HTML::Strip completely strips HTML tags from a document and leaves one with just the text.

It works well enough to remove the tags from HTML, and it also removes the contents of <script>..</script> and HTML comments. The behaviour regarding whitespace is rather different from HTML::Restrict and HTML::Scrubber. It turns all opening and closing tags into a space character, which means that it leaves things like the following, where there is an </a> tag in the original HTML:

< strokes in the correct order and direction .
> strokes in the correct order and direction.
< discussion forum .
> discussion forum.
< the KanjiVG project . The
> the KanjiVG project. The

All of the odd whitespace appeared where there is an </a> tag in the original HTML. This is the documented behaviour of the module:

"Anything that looks like a tag, or group of tags will be replaced with a single space character."

Oddly enough, though, neither HTML::Restrict nor HTML::Scrubber bother to turn characters which should be whitespace into whitespace. In HTML::Restrict and HTML::Scrubber, the <br> tag is turned into nothing, rather than a space or a return character, which means that if you have a sentence broken up like this:

I wondered lonely as a cloud<br>That floats on high o'er vales and hills,

then the output from HTML::Restrict and HTML::Scrubber looks like this:

I wondered lonely as a cloudThat floats on high o'er vales and hills,

whereas HTML::Strip gives you

I wondered lonely as a cloud That floats on high o'er vales and hills,

So unfortunately none of these modules actually grapples with the problem of converting HTML tags into a reasonable whitespace equivalent.

* HTML::Strip is much faster than HTML::Restrict and HTML::Scrubber. See my review of HTML::Scrubber for a comparison of performance.

For a list of similar modules and links to other reviews, please see my page at

HTML-TagFilter (1.03)

Although it's quite old, the module installed without problems.

The default behaviour seems quite zany. The default setup converts comments in the HTML into escaped entities, like this:

& lt;!-- comment --& gt;

If I added this to the object creation:

my $htf = HTML::TagFilter->new (

strip_comments => 1,


then it would correctly strip out the comments, so it must be recognising them as comments, and yet it does this zany conversion which results in visible things appearing which were meant to be HTML comments. I don't see anywhere in the documentation where it explains the rationale for that, and it just seems like a bug to me.

Like HTML::Detoxifier, it also leaves the contents of scripts between <script> and </script> intact, while removing the tags, but converting quotation marks in the JavaScript into " entities. It also converted the HTML5 doctype into entities, like this:

& lt; !DOCTYPE HTML& gt;

This module probably didn't work correctly at the time of its most recent release, in 2005, and it cannot be recommended in 2017. I suggest trying out HTML::Restrict, HTML::Scrubber, or HTML::Strip instead.

(There is a bug in cpan ratings where it is failing to convert & amp; into & correctly, so excuse me if this text becomes incomprehensible after repeated edits. To work around the cpan ratings issue I have used a space in the above.)

For a list of similar modules and links to other reviews, please see my page at

HTML-Detoxifier (0.02)

On the positive side the module has zero dependencies and installs without any issues. On the negative side, the lists of HTML tags in this module predate HTML5, and its <marquee> and <blink>-removing code is obsolete in 2017.

The module has problems compared to the alternatives. Given


x = y;


the command

detoxify ($html, disallow => [qw(everything)]);

just removes the <script> and </script> and leaves the x = y; part, which is definitely not desirable.

Although the module seems to represent quite a lot of work, the most recent update was in 2004, to version 0.02, so I recommend considering alternative modules like HTML::Restrict, HTML::Strip, or HTML::Scrubber, all of which will remove the text between <script> and </script> tags.

For a list of similar modules and links to other reviews, please see my page at

jsonpretty (1)

Perhaps it is worth pointing out that a script called "json_xs" with output which is essentially identical to this module, except for sorting the order of hash keys, was already in JSON::XS when this was released to CPAN:

A similar script is also in the Cpanel::JSON::XS as cpanel_json_xs:

Getopt-Long (2.49.1) *****

I only use this module for parsing command-line options in Perl. It does almost everything, and if you think you might need something which does something more complicated than what this does, consider whether you might be overcomplicating your problem.

AppConfig (1.71)

Some people, when faced with the problem of setting up options for a complex project, think "I know, I'll use AppConfig". Now they have two problems.

I used AppConfig for one project, in about 2008 or 2009, and have been regretting it ever since, and unfortunately I still have not got around to removing the thing.

It is not that the module does not work, or is not documented. The problem is that this module is far too complicated and does far too many things.

This module's maintainer used to be the same person as the Template Toolkit, so I thought this must be OK, and I delved deeply into all the complexities of AppConfig, thinking this must be the cool way to set up my configuration. What I realised too late is that this thing is just far too complicated and convoluted for normal people to be able to cope with, it has too many ins and outs, it makes too many decisions for you, and I really did not need to use anything this tortuous. Adding this configuration system to my already complex project just made the whole thing into a nightmare.

Since learning the error of my ways, I have never used any other command-line module except for Getopt::Long.

Devel-Plumber (0.3.4)

This module seems to have been abandoned. If you try to install this, its tests won't work with a modern C compiler, because it refers to a non-standard header file malloc.h which is apparently from the ancient days of Linux.

Test-Unit (0.25)

If you are considering what module to use for testing your Perl code, please consider using Test::More rather than this. Test::More is currently maintained and is a standard module for testing Perl.

Test::Unit has been abandoned for more than ten years. Sadly this also means that all the other modules which depend on Test::Unit often don't install any more:

This failure doesn't show up in the CPAN testers' results for the dependent modules because, since Test::Unit fails to install, a module which is dependent on it never even gets to the point of being tested, because the installation bails out after failing to install this.

Unfortunately the only review here on CPAN ratings which is still accurate in 2017, the one which says Test::Unit doesn't install on many systems, is the one which is downvoted so that it has disappeared.

There is a file AUTHORS with ten people in it; have all of these people stopped using the thing? The presence of a development version on CPAN dating from 2011 seems like a bit of tumbleweed blowing through this ghost town.

Test-Valgrind (1.19) *****

This module is very simple to use, and it is very helpful for finding memory errors in XS modules.

Just for example, here is one error I found with it:

With a C program one could usually test with

valgrind a.out

and look at the results, but with a Perl script, that becomes very convoluted because Perl usually exits without cleaning up its memory.

This module takes care of the Perl cleanup using Perl::Destruct::Level, and leaves the user with a nice and tidy output in TAP format which can be used to swiftly find memory leaks and other faults.

I think this is a very useful contribution.

File-Slurper (0.009) *****

Perhaps there are some edge cases which aren't covered by this, but this module is definitely good enough for almost all of the times you need to read some piece of text in from a file without all the "local $/", "while (<>)", and other kinds of tedious things.

Text-LineNumber (0.02) *****

It works correctly, and it can save you a small amount of time, a small amount of reduplication, and a small headache if you need to convert, say, "pos($x)" into a line number in a piece of text.

App-cpanminus (1.7042) *****

Everybody has said it already, but anyway, this is a huge improvement over the default CPAN client which comes with Perl.

The merit of this module is that App::cpanminus only tries to do one simple job, install a module for you, which is the only thing you really a cpan client to do, 99.999% of the time.

CPAN (2.14)

I think this module is very problematic. It is not really documented clearly, and it tries to do too many things, and is generally far too clever for its own good. Just now, as a test to see if a problem had occurred, I tried to use this to install a module which had not been installed via cpanm.[1] The cpan shell started lots of background processes, tried to locate some kind of mirror in Singapore at "", kept on trying to download again and again after repeated failures, messed up my terminal, could not be stopped from downloading via interrupts, but kept on and on spawning background processes after one presses the interrupt. Despite all the help and the options on the screen if I press h, it won't tell me the simple way to do things like how to stop it connecting to the unavailable mirror at and connect to another CPAN mirror. Looking at google for help there are threads from 1994 and 2004 full of "weird old tricks" on how to configure this thing. [2][3]

The only thing that 99.9% of the people using this 99.99% of the time ever needed was a way to download modules and install them. What seems to have happened is that the author started adding all the bells and whistles for fun or something, and ended up making it unable to do the simple job that people actually need it to do.

Nowadays I only use cpanm (App::cpanminus).

[1] Please refer to this bug report:

App-perlbrew (0.77) *****

I've been trying to debug an issue with a CPAN module which was shown up by CPAN testers. At the moment, the testers' reports are not available on the web. The problem seemed to be with older versions of Perl, but despite much effort I was unable to install them to find out what was wrong. I have never installed or even tried perlbrew before today, but in desperation I tried it out.

Thanks to perlbrew I was able to install a Perl 5.12.5 and find the errors in my CPAN module very quickly. I'm very impressed with how easy it was and how it managed to install the old version of Perl on my system where I wasn't able to. The whole system of shell replacements is just ideal for this kind of work.

Very good job! Thanks.

Captcha-reCAPTCHA (0.98)


Path-Tiny (0.096)

Deleted stale review, not using this any more.

The unswitchoffable warnings about no flock on BSD are just too annoying.

Lingua-EN-Conjugate (0.311) *****

This module more or less correctly conjugates English verbs. There is also something called Lingua-EN-Inflexion but this module looked a lot simpler, so I used this one.

IP-China (20160412)

Disclosure: I wrote this module.

Test-Pod-LinkCheck (0.008)

I've been looking for a way to check Pod documents due to my errors such as using L<function> instead of L</function>, or using L</function> where the "function" section cannot be found.

So far I have found this module and also App::PodLinkCheck. Test::Pod::LinkCheck is a little difficult to use. For example, if it doesn't find any pod documents, the "all_pod_ok" method doesn't print "no pod documents found", but instead "you haven't run any tests". This is confusing. It also says that some modules aren't on CPAN when they actually are. I also wasn't very happy with the errors it found and did not find, and I felt that App::PodLinkCheck (podlinkcheck) was doing a better job, at least for my particular case.

Pod-POM-Web (1.20) *****

Of the Pod viewers I tried, this one works the best. It found all the modules I have locally installed, and displayed all the pod I tried it with. It displays encoded UTF-8 as well.

The display could be improved. Navigating involves clicking on some tiny boxes containing a plus, with the list of modules expanding up and down the left hand side, and the formatted pod on the right hand side is done in a rather garish colour scheme with very small fonts used for example code.

It would also be nice if the 1990s frames could be removed in favour of a navigation bar and the ability to link to a local copy of a particular document.

The requirement for the user to install a complex search module in order to be able to jump directly to the local CPAN module documentation, instead of enabling javascript and clicking lots of tiny boxes is absurd, in my opinion. For my local Perl module documentation "server", I just made a CGI script which prints a form then substitutes :: with / and prints a redirect to the appropriate page of Pod::POM::Web.

Storable (2.51)

The following short script will crash almost any XS module you care to try it with:

use warnings;
use strict;
my $xsmodule = 'Image::PNG::Libpng';
eval "use $xsmodule";
my $iv = 1;
my $ivref = \$iv;
bless $ivref, $xsmodule;

Change $iv to a random number or zero if you like, and change $xsmodule to whatever you like.

Unbelievably, this is what Storable actually seems to do:

use warnings;
use strict;
use Storable qw/thaw freeze/;
my $xsmodule = 'JSON::XS';
my $thing;
eval "use $xsmodule;\$thing = $xsmodule->new ()";
thaw (freeze (\$thing));

This module has been around since 1995 and it's part of the Perl core.

See also

AI-General (0.01)

It's an Acme module with no content.

MD5-Reverse (0.01)

This seems to be an empty placeholder with no function.

HTML-Bare (0.02)

From documentation:

> As far as I am concerned, as the author of the module, the 'HTML' in 'HTML::Bare' should be thought of to mean 'eXtremely Mad Language', because the module was written from scratch without referring to the specification known as 'HTML'.

Sorry but I am going to give up on trying out your module here. Just untangling what you are trying to say or think is too much work. Good luck with it!

HTML-AA (0.10)

It's better not to use Google Translate to write your documentation.

JSON-Create (0.20)

A response to the dishonest and misleading review by Zoffix Znet is included in the module distribution as follows:

@perlancar: I have no way of knowing what benchmarks you're referring to.

Dist-Zilla (5.042)

A nightmare of undocumented behaviour, hundreds upon hundreds of dependency hells, and thousands upon thousands of exasperating quirks all rolled into one gigantic ball of wax. For added fun, many of the dependent modules don't even have their dependencies documented, so you end up in an endless trudge of searching through build logs to find out what dependency failed to install this time. I used Dist::Zilla once, for one module, and I went through about twenty cycles of trying to install dependencies by scraping though build logs. Even then it still would not install cleanly.

It simply is not possible that using this insanity can save anybody any time and effort, so the only conclusion I can come to is that this is some sort of shibboleth for authors or trendy club.

Save your sanity, don't use this nonsense.

Pod-Checker (1.71) *****

I got a lot of bug reports about broken POD internal links, so I searched on CPAN for something to check these automatically, and found this. I am using this module to check POD before uploading to CPAN. It finds broken internal links as well as other kinds of errors, like forgetting to put =back after =over. It seems to be easy to use and works well. I had to remove some warnings about empty lines containing whitespace though, since the empty lines are within example code blocks.

Devel-CheckLib (1.05)

[Delete this, please ignore.]

HTML-Lint (2.22)

I wanted to check some cruddy old HTML pages for errors, so I started looking on CPAN. HTML::Lint was the second thing I came upon, after one other thing which looked very difficult to install.

It did a few useful things, like catching closing tags without an equivalent opening, or informing about img tags with no height, width, or alt text. But this module has a big problem if your web page contains any UTF-8 encoded Unicode characters. If you use its "parse_file" method, not only does it insist that you have to use HTML entities:

Invalid character \xC2 should be written as Â
Invalid character \xA9 should be written as ©

but even worse it doesn't take any notice of your encoding anyway, and it tells you to use entities for each byte, which is wrong and will result in a broken web page. If you read the text in yourself as UTF-8 and send it to this module via its "parse" method, things get even worse since it doesn't have any way of coping with these inputs. When I tried using "parse" on a Unicode-encoded string, I got streams of errors like this:

Use of uninitialized value $val in substitution (s///) at /home/ben/software/install/lib/perl5/site_perl/5.10.0/HTML/Lint/ line 112.

I tried fiddling with the three error switches provided, but it turned out that switching off the entity part also switches off the other parts which were useful to me. I guess one could just send the output of this module through 'grep -v "Invalid character"' to remove these bogus errors.

Looking at the issue tracker for the module

it seems like the above problems have been reported already.

Update for 2015: the module seems to still have exactly the same problems in 2015 which it had when I wrote the above review in 2008. It would be great if this could be improved.

HTML-Tagset (3.20)

Reading the bug reports for this module, it looks like it's been nearly abandoned:

The maintainer doesn't seem interested in adding support for the new HTML 5 tags, and there are no updates since 2008, despite some patches for bugs. Another unfortunate fact is that a lot of the module is not correct. Here I'll give a link to my own module's documentation, which discusses several issues in detail:

Considering there are 33 other modules which depend on HTML::Tagset,

it really is a shame that it's not being updated, despite the many offers of help from people which one can read at the above link.

Not only that, but HTML::Parser, which is a very core CPAN module, also depends on this, and that has 540 dependent modules.

It's really a shame about that.

JSON-Meth (1.001006)

From the module documentation:

> Don't make me think and give me what I want! This module automatically figures out whether you want to encode a Perl data structure to JSON or decode a JSON string to a Perl data structure.

So, in the event that you have something which may be a Perl data structure, or may be a string containing JSON, this module converts it into the other thing.

The problem I have with this, is how does that resolve the initial confusion? The output is either a string containing JSON or a Perl data structure. Even if we call the module twice, the confusion remains. It's as if someone made a module to help people who don't know their arse from their elbow, by exchanging their arse for their elbow. Surely this merely compounds the anatomical conundrum.

Edit: changed "for people" to "to help people".

Task-Kensho (0.38)

This module appears prominently on advertised as a way for people, in the words of the other reviewer, to "in the sea of over 18,000 CPAN modules, find recommended modules for the most common programming areas". That does sound like a good idea, doesn't it? And I'd like to be enlightened as to what the best Perl modules are. But I am pretty stuck on viewing Task::Kensho. Why does it recommend a database driver for SQLite, for example? Why does it choose "Date::Tiny" over "Date::Calc"?

I would be very happy to see a comparison of modules with some kind of reasoning as to why I should pick one, so I didn't have to spend the time trying to choose one, but Task::Kensho seems to add to my confusion rather than resolve it. The big quote about Zen Buddhist terminology from Wikipedia at the head of each section of the module also doesn't help.

I am very sorry, but I do not think that this module is of general enough utility and understandability to have it touted on every page of

JSON-MaybeXS (1.003005)

In the one corner we have Tuco, otherwise known as Marc Lehmann, and his JSON::XS. In the other corner we have Reini Urban, who seems from the photo to look a lot like Lee Van Cleef, and his Cpanel::JSON::XS. And in the other corner there is Clint Eastwood with his JSON module, buried in the grave next to Arch Stanton. And for all the people who cannot decide between these cowboys there is JSON::MaybeXS. And also JSON::Any. And JSON::XS::VersionOneAndTwo. And next week for the person who wants to make yet another one of these stupid modules, I have a suggestion for the name: JSON::GoodBadUgly.

Unicode-UTF8 (0.61) *****

This offers functions "decode_utf8" and "encode_utf8" which do the same thing but are very surprisingly faster (about ten times faster) than the same functions from the core module Encode. If you need to do a lot of converting to and from Unicode UTF-8 this is a better choice than Encode.

I also use the "valid_utf8" function from this module for a file server which serves files from the disc, to check what kind of character set the file might have before sending it to the browser.

Font-TTF (1.04)

This module is virtually undocumented. It's probably a great module and does everything, but with documentation this minimal, I'm left with the options of either (a) reading the source code and the Apple TrueType manuals and trying to work out what this does (b) reading the Apple TrueType manuals and just writing the bits of code which I need to do the jobs I want to do. For me, (b) is probably going to take less time and be less frustrating.

The core documentation, Font::TTF::Manual, really tells me next to nothing about what the package does, instead it describes architectural decisions made when designing the module. There are scraps of information in each of the submodule documents, but it's just not enough to get started.

Which is a shame, since the module looks like it's really comprehensive. If the authors would like people to use this module they should try to rewrite the documentation from the user's perspective.

IO-Compress (2.069)

In addition to the extremely complex (unnecessarily complex) interface, the IO::Compress::Gzip and IO::Uncompress:Gunzip parts of this module have extremely serious performance issues. (yes, "extremely serious" is not an exaggeration.) I strongly recommend considering alternatives.

Lingua-ENG-Inflect (0.0682)

This is an exact copy of another module, Lingua::EN::Inflect, version 1.891. The only thing that was changed between the two modules is the name, from "EN" to "ENG", the version number, and a line "use 5.10.1;" at the start of the module. Beyond that there is quite simply no difference whatsoever, the code is identical. Try a diff on these two files if you doubt it:


Since this module was released, the original Lingua::EN::Inflect has been updated so the source code no longer resembles it.

I recommend people to choose the original Lingua::EN::Inflect over this rather pointless fork.

Lingua-JPN-Number (0.0682)

This module is an unnecessary fork of a module which was superceded.

If you need to process Japanese numbers, I suggest using "Lingua::JA::Numbers" by Dan Kogai rather than this fork of a superceded module.

Lingua-ZHO-Numbers (0.1192)

This is a fork of another module, Lingua::ZH::Numbers. However, the fork is broken. Whatever has been changed has not been documented, the documentation is just the original, even though it doesn't describe the module contents. It says that the "PetaMem" author has taken over maintenance from the original author, but if so why not get co-maintainership rather than fork to a confusingly similar name?

Considering that the original module still works and is documented correctly, and doesn't seem to have any outstanding problems like a huge list of bugs on, why is it even necessary to fork? And this doesn't seem to work, it breaks the existing interface in undocumented ways.

I think this is a really poor effort and best avoided. I suspect the same of the other modules by this author which seem to have a similar provenance.

Module-Rename (0.04)

Update: the module was changed:

This would be a good module but it really needs updating. The "module-rename" script does not have any options to turn off what directories are altered, e.g. ".git".

I would suggest at least an "-i" interactive option and a "-d" for skipping directories for the script. Also the documented "-v" option does nothing: here is the exact output:

$ module-rename -v Lingua::JA::Gairaigo Lingua::JA::Gairaigo::Fuzzy

If you wanted to make this incredibly great, it would be just super if there was a way to override the "move" routine used.

Getopt-Long-Descriptive (0.093)

Getopt::Long::Descriptive claims to be similar to Getopt::Long but with the addition of an automatically-generated usage message. However, for example, whereas with Getopt::Long, I can do something like

GetOptions ("verbose" => \my $verbose)

and have my program use -v as an option:

./script -v

with Getopt::Long::Descriptive, the short options don't occur unless I specify them. This may be a good thing or a bad thing, but either way it isn't the same thing as Getopt::Long, or even an extension of the same thing. Also, it is quite handy in short scripts to be able to send a reference like the \my $verbose above, which Getopt::Long::Descriptive doesn't support.

It would be great to have an automatic way to generate usage messages which was also compatible with Getopt::Long, but this isn't it. After evaluating this module I decided to stick with using Getopt::Long and here-documents for usage messages.

Roman (1.24)

This module converts between roman numerals (I, II, III, IV, V) and arabic numerals (1, 2, 3, 4, 5).

I tried and it worked for small numbers and the common cases. Unfortunately it seems to fail for some unusual roman numerals which are in wikipedia:

my $r1910 = 'MDCCCCX';

print arabic ($r1910), "\n";

Also, when it fails, it just gives an "undefined value" - may be it should print an error?

It says that it is restricted to ASCII symbols - that may have been true in 1995 but perhaps this can be updated for 2012?

Also, the namespace as "Roman" and the global exporting of the functions are a bit questionable.

Anyway if, like me, you are too lazy to code this yourself, it works for the common cases. I also think this would make a useful standalone script and would suggest adding a command-line roman/arabic converter using the module.

Bootylicious (1.10)

(review refers to github version)

This barely functions. The example article it gives does not display the article text, the links to articles go to the wrong article. Generally it seems to be hopelessly broken.

Lingua-Syllable (0.03) *

An inspection of the code reveals exactly one function, which seems to be utter junk; on empty input it prints a warning and then continues to execute, with the empty input used as a parameter. This looks like code which has rarely actually been put to work.

Even worse, the one function it does contain is nothing but a wrapper for the Lingua::EN::Syllable module, but also using Lingua::Rhyme as a dependence. Why is it namespaced as Lingua::Syllable I do not know, but this seems to be pure namespace abuse on the part of the author, since it is only for English.

Lingua-Phoneme (0.011) *

Similar to Lingua::Rhyme, this seems to be very little more than clutter, taking up megabytes of CPAN space. It's also in the wrong namespace (should be Lingua::EN::..), and it forces the user into a particular choice of storage (a MySQL database).

I can't imagine how anyone could successfully use this module.

Poetry-Aum (1.1)

Unfinished Acme:: module cluttering CPAN.

The documentation claims "If you feel you need documentation for this module, please consult an experienced Perl Monger/Rabbi."

If you care to try it, you will find that nothing in the code works:

--------- INPUT:

use Poetry::Aum;
my $boo = Poetry::Aum->new ();

---------- OUTPUT:

Can't locate object method "new" via package "Poetry::Abstract::Entity" (perhaps you forgot to load "Poetry::Abstract::Entity"?) at /home/ben/software/install/lib/perl5/site_perl/5.14.1/Poetry/ line 32.


"If you feel CPAN needs this module, please consult an experienced Perl Monger/Rabbi".

Lingua-Rhyme (0.092) *

This code seems to be very difficult to use. First of all, it's in the wrong namespace, since it is only for English. Secondly, for whatever reason, it requires a MySQL database. The documentation only really describes how to make the MySQL database and says nothing about how the dictionary works or what algorithm might be used to decide a rhyme.

It's also rather a self-indulgent use of CPAN disc space (four megabytes of dictionaries are included in the distribution).

This module seems poorly-designed, self-indulgent and a waste of space.

Pod-Browser (1.0.1)

This doesn't find files on the local system so it's not much use for browsing local modules which aren't released to CPAN.

Pod-Server (1.14)

I installed and got running with the usual commands. It started working instantly without any hiccups, and it was clever enough to work out the name of the server and give a URL for it. Unlike Pod::Webserver I was able to access the generated pod pages from other computers. It was able to find all the pages on the local computer. It displays encoded UTF-8 correctly, and it has a nice design for the pages.

However, for some reason (maybe my misconfiguration) the top page only lists pod files from AE to DateTime::, with no "next page" visible, so it's necessary to type in the URL for other files. Also it only displays parts of some pod pages. For example, "DBI::FAQ" is visible down to "3.7 What databa" then it suddenly stops.

Pod-Webserver (3.10)

I installed successfully and was able to start the pod webserver. The top page was visible from localhost, although not from other computers on the network. It correctly listed the installed pod files when viewed in Lynx. Each attempt to view the pages, however, resulted in a 404 error, so I was not able to view any Perl manual pages with this. The -H option didn't seem to work either.

The bug tracker on contains many bugs and patches from years ago. I assume this means the module is neglected or abandoned?

I was able to hack this into a workable thing by making a few small changes, but I can't recommend the module as it stands.

Morale (0.002)

It's a bit ironic that a "Perl module for managing individual and calculating group morale" ended at version 0.002, in 2001.

Perl-Critic (1.126)

[Stale review removed.]

App-GitHub-create (0.0012)

This no longer works, because the authentication scheme it uses was removed.

ack (2.00a01) *****

ack is a source-code search tool which offers recursive searching (going into directories), highlighting, and regular expression searches.

I have found this very helpful in searching through third-party source code, such as MetaCPAN source code, or even for finding stuff in header files in /usr/include.

I wish I had discovered this earlier.

Anchovy (0.01) *

Empty module, contains no code whatsoever.

WikiText (0.19)

Module has been "coming soon" since 2008, but the submodules are empty stubs containing a package name and a 1; at the end.

On the bright side, the fact that the submodules contain only a 1; means that it passes all of its tests at cpan testers.

CPAN-Meta (2.120921) *****

I'm grateful to the author of this for writing clear documentation.

File-Compare (1.1001) *****

File::Compare provides a function for comparing two files to see if they are exactly the same or not.

It's a handy module for writing tests, e.g. this:

Lingua-EN-Inflect-Number (1.12)

This module is supposed to turn English nouns from plural to singular. However, the whole module is based on a mistake: it actually uses Lingua::EN::Inflect's method for turning a third person singular verb (he does, she likes, it eats) into a plain verb (I do, you like, they eat). The source code actually contains a comment "I don't know why this works, but it seems to." But unfortunately it doesn't; the most simple examples of irregular plurals are completely unhandled by this module:



use warnings;
use strict;
use Test::More;
use Lingua::EN::Inflect::Number 'to_S';

my %words = qw/
bogus bogus
citrus citrus
menus menu
species species
flies fly
monkeys monkey
children child
women woman
mice mouse

for my $word (sort keys %words) {

my $s = to_S ($word);

ok ($s eq $words{$word}, "$s == $words{$word}");




ok 1 - bogus == bogus
not ok 2 - children == child
# Failed test 'children == child'
# at ./ line 21.
ok 3 - citrus == citrus
ok 4 - fly == fly
not ok 5 - menus == menu
# Failed test 'menus == menu'
# at ./ line 21.
not ok 6 - mice == mouse
# Failed test 'mice == mouse'
# at ./ line 21.
ok 7 - monkey == monkey
ok 8 - species == species
not ok 9 - women == woman
# Failed test 'women == woman'
# at ./ line 21.
# Looks like you failed 4 tests of 9.


This module is inadequate for turning English plural nouns to singular ones, and the two other things it does are already handled by Lingua::EN::Inflect.

Nums2Words (1.13) *****

Re Lester Hightower's self-review, please note this is not self-promotion, it is related to an ancient bug from at least three years ago which has never been fixed. See the following email, which I sent over two years ago, reporting the bug:


MIME-Version: 1.0
Received: by with HTTP; Sat, 11 Jul 2009 18:02:22 -0700 (PDT)
Date: Sun, 12 Jul 2009 10:02:22 +0900
Message-ID: <>
Subject: CPAN ratings bug in
From: Ben Bullock <>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Dear maintainers,

There are two bugs regarding in
which have been there for at least a year or so.

Bug #1: The number of reviews is wrong. The number of reviews given on
the page shows the number of reviews where the
reviewer has given the module a star rating. For example,

says (3 Reviews) , yet there are actually four (one without a star
rating). This is repeated for many other cases.

Bug #2: If a reviewer writes a review, adds a star rating, then
deletes the star rating again, the star rating remains on For example, see

Note there is only one review, with no stars, yet the above still
keeps the five stars that the reviewer added then removed. This is not
due to a slow update, since the stars were removed a year ago.

Ben Bullock


Given that the unfortunate one-star rating is solely due to a bug, Mr. Hightower should be forgiven for self-rating 5 stars.

Since I've already reported the bug, maybe someone else could re-report it? Thanks.

Lingua-StopWords (0.09) *****

Lingua::StopWords provides lists of short words like "to" or "and" for several languages which should be neglected in searches. I installed Lingua::StopWords for use in a web log parser to remove uninteresting words from its list of search keywords. As far as I can see it works pretty well; some words it doesn't eliminate include "us" and "can", but since these could be "United States" or "Can of coca-cola" perhaps they are border cases.

The explanation of the module provides an example using "grep" of removing the stopwords from a list which I copied into my program. Although this is very simple, it would be preferable if this was provided as a method or procedure in the module.

Disclaimer: I have only used the English words part of this module. It provides lists for a lot of other languages but I didn't use them, so please consider this a review of the English-language parts only.

Number-ZipCode-JP (0.20120229)

review deleted.

Poem (0.01)

(Review deleted - this was a test of Unicode done on behalf of A.B.H.)

App-pmuninstall (0.28) *****

At last, a way to remove installed modules which works.

Dancer (1.3070) *****

I've never used Dancer but I'm planning to use it to host a blog containing ridiculous pictures of Celine Dion.

Lingua-EN-Numericalize (1.52)

Parts of the module work correctly. It also includes some very odd numbers, like eleventy-one, which seems to come from JRR Tolkein's books.

But, there are lots of bugs, and the code is almost like "Perl golf", and it is difficult to fix the bugs due to the coding style.

Data-Stack (0.01)

It looks like a joke module to me. Everything here is already provided by Perl arrays. I imagine the author knows that? Surely nobody actually uses this.

autodie (2.10)

I read in a lot of places that "autodie" is something that can be used in the same fashion as "use strict" or "use warnings" to catch problems. I started putting it into a lot of places and automatically adding to the top of every script. However, for something which is intended to go into every Perl script, this module is very slow to load:

****** Item 1:

use warnings;
use strict;
print "hello world.\n";

$ time perl
hello world.

real 0m0.007s
user 0m0.000s
sys 0m0.008s

****** Item 2:

use warnings;
use strict;
use autodie;
print "hello world.\n";

$ time perl
hello world.

real 0m0.084s
user 0m0.078s
sys 0m0.005s

I don't use this module any more, because of this performance problem.

(Someone wrote to me who was worried that I thought that autodie affected the time of "print" above. In case anyone is confused, please note that "autodie" doesn't affect the time of "print", as far as I know. You can remove the "print" and still get the same sort of time results. Check the autodie documentation at the link above the review for what the module does.)

Lingua-LO-Romanize (0.09) *****

I read the other review here and wondered why it was so harsh. Just out of interest when I saw the new version of this on CPAN, I took a look at this module by setting up a simple CGI script using it:

Just looking at the code, I wondered what the Moose was doing. It turned out the answer was "nothing". It took only a few minutes to remove everything to do with Moose from this module and give it a simple procedural interface:

It still passes all the tests of the original (t/01-romanization.t):

What is the function of Moose in this module? I think the other reviewer was right to be a bit angry about this unnecessary dependence. Although I wonder if that guy really needs to romanize Lao, or if it is just some kind of grandstanding using this module to attack Moose rather than write a review of this module itself. If you really need to romanize Lao and you hate Moose, it's pretty easy to get the functioning bits out of this module. No point in bashing this, and it's a bit cruel towards this module's author, who seems to be the only person in the world to have written free software to romanize Lao.

About the module itself, I am totally unqualified to pass comment. I noticed that when I tried the above CGI program on the Wikipedia page about the Lao language, there seem to be quite a few different forms of Lao romanization. If this is just one of them then maybe its name should reflect that, in case someone wants to also provide all the other forms of romanization.

Anyway I think the other review is a misuse of cpanratings so I will give this module five stars to compensate for the other silly review.

JSON (2.90)

This module parses the JSON format and puts it into Perl structures. I haven't used it the other way around so I don't know if it turns Perl structures into JSON or not, although it claims to.

Although it definitely works correctly, this module is difficult to use and the interface is over-complex and badly designed. It's also rather difficult to navigate the documentation. Before the maintainer changed the behaviour recently, the default behaviour was that it blew up with weird error messages like this:

Wide character in subroutine entry at ../lib/ line 54

if it was sent "utf8" encoded Unicode text. Even after trying all kinds of different options, in the end it was easier just to re-encode the text using "encode_utf8" from the Encode module and send it. Even then I was still getting problems with "decode_json", for example

my $text = encode ('utf8', $contents->{response});

my $json = decode_json ($text);

caused an error

Cannot decode string with wide characters at /home/ben/software/install/lib/perl5/5.12.3/i386-freebsd/ line 174.


my $text = encode ('utf8', $contents->{response});

my $json = from_json ($text);

did not produce this error, so I had to use "from_json" instead.

Why? Eventually I found out that one of these routines defaults to turning on the UTF-8 flag, and the other one defaults to turning it off. Then the error was bubbling up from another routine which sent the text to DBI. Why the module is written in this confusing way, I don't know, is it something to do with JSON::XS compatibility? Then the maintainer wrote a response review which demonstrates my point: to understand what this module is doing you need to spend a long time scrabbling through the documentation. Why on earth is it necessary to spend such a long time doing these things when JSON is such an absurdly simple format?

In the end, after seeing that maintainer's review, to save time:

It has two routines, one validator and one parser. Put UTF-8 flagged text in, get UTF-8 flagged text out. Put non-UTF-8 flagged text in, get non-UTF-8 flagged text out.

Math-Base36 (0.09) *****

I was about to do some work on improving my base 36 number reading routine when I had the idea to look on CPAN to see if there was any existing solution. I didn't expect to find anything but was surprised to find this. I'm using it to parse numbers created by JavaScript using "number.toString(36)" as a way of compressing message size. As far as I have used this, it works nicely, although my numbers only go from 0 to 36*36 - I haven't tested it beyond that.

(If you would like to make a comment about this review, please address it to me at

HTTP-Date (6.02) *****

Effectively & correctly converts Unix epoch times to and from HTTP server style dates.

Cairo (1.106) *****

This is a full interface to the Cairo drawing library under Perl. It's very nicely done, and everything works just the same as if using the C library. The one criticism I have of this is that the documentation is not clearly organized, and a lot of it is just some kind of printout of function arguments which looks like gibberish to the untrained eye. I guess the authors didn't want to have to reproduce the documentation for the existing C library, or something? I already knew the C version of the Cairo library before using this, so it was easy for me to get going, but someone who looks at the documentation for the module is going to feel extremely confused and discouraged unless they already know what the library does. There are some good example scripts in the examples directory:

so start there rather than looking at the module documentation.

Re the other review, I had no problems at all installing this on FreeBSD. The problem I had installing it on Ubuntu Linux was the usual one where the OS installs the system libraries without the C header files (like "cairo.h"). In this case the Cairo library probably exists on almost any variety of Linux, but the header files might be missing. Just the following is enough to install on Ubuntu Linux:

sudo apt-get install libcairo2-dev
cpan Cairo

Here the libcairo2 is already installed but the -dev addition is necessary to get it to install header files. It's not the Cairo module's fault that Linux distributions don't include header files.

Net-OpenID-Consumer (1.15)

[review deleted]

WWW-RobotRules (6.01) *****

This module parses "robots.txt" and tells you if your url is allowed for your user agent.

(Contact me at if you have a comment about this review.)

slice (1.2.8)

A collection of ancient versions of modules not written by the alleged author of this module which clutters up CPAN search results. See also my review for, almost all of the comments there apply to this too.

Sorry author, I am sure that in 1998 this was a truly marvellous way to "Extract pre-defined slices from an ASCII file", although I have no idea why that task would require you to pull in modules like IO::Socket::INET, but in 2011 this is a blot on the landscape.
I suggest this whole thing should just be deleted.

lcwa (1.0.0)

Originally this seems to have been part of an application to do some kind of web crawling or something. I haven't even looked at that. The reason I am commenting is that a large part of this package is a collection of other people's modules, dated to when this package was released in 1997. As a result, a collection of extremely old versions of modules, which were not written by lcwa's author, have been sitting on CPAN unchanged since 1997. Maybe that would not be a problem if nobody knew about them, but in fact these extremely antiquated versions of modules turn up in the search results of

At the time of writing this review, an ancient version of WWW::RobotRules turns up as the second hit if you search for the term "robots.txt" on

See for a screenshot.

Even worse, it's actually the sixth module on the list if you search for WWW::RobotRules.

When I searched for a module to read "robots.txt", I landed up at the version of WWW::RobotRules bundled in with this package. I spent quite a few minutes wondering why something like that had not been updated since 1997. I started to look for some more modern alternative, and I found my way to

which comes below the above broken module but above the legitimate WWW::RobotRules. Now it says right at the top of this, "Unlike WWW::RobotRules (which is very cool),". However, since the version of WWW::RobotRules which I'd discovered before that was obviously not very cool, I was puzzled, so I went back to the search box of and found my way back to the 2011 version of WWW:::RobotRules. This surely proves that there is something wrong with my method of searching and what a fool I am, but I notice that this package even got some bug reports at which should have gone to the legitimate modules, so it seems there are other fools like me.

So this package is really a distraction and a nuisance. I don't know if it was necessary to bundle up third-party modules in a package in this way in 1997, but in 2011 it is a really bad practice, so my request is that this package should somehow be removed from CPAN, made invisible, have the ancient third party modules removed, or otherwise downgraded in the search results.

SVG (2.50) *****

This module is a writer for SVG (scalable vector graphics). It takes Perl structures containing the SVG data which you want to write, and turns them into SVG for you.

It seems to be complete and effective and will save you the work of turning your data from Perl form into XML tags.

One note is that the top level namespace "SVG" doesn't seem necessary to me, I think it should have been "Image::SVG". Note that the mime type for SVG is image/svg+xml.

It doesn't read SVG in.

The documentation is very complete. Some of the links in the documentation are dead.

(Contact me at if you have a comment about this review.)

Algorithm-Munkres (0.08) *****

This is an implementation of a method of solving the assignment problem generalized to the case where there are different numbers of jobs to the number of assignees. This is linked to from the Wikipedia page on "Hungarian method".

The code seems to work OK, although I haven't carefully verified its correctness. It is very slow on very large datasets but pretty fast up to 100 x 100 matrices.

The interface is very simple and obvious, the documentation is a bit messed up, containing some dead links and odd formatting, but there is nothing here which needs extensive documentation anyway.

(Contact me at if you have a comment about this review.)

SVG-Parser (1.03)

Does this module actually have anything to do with SVG? It looks like just a generic XML parser with the word "XML" crossed out and "SVG" inserted. The only thing the docs and examples contain are completely generic stuff about parsing XML.

Although SVG is formatted as XML, that is only a part of the story. Something which calls itself an SVG parser should be able to, for example, parse the "d" attribute of an SVG <path> element, see e.g.

Otherwise what is it for?

IPC-Run3 (0.048)

This module is OK for some jobs where you are only inputting or outputting ASCII or otherwise don't care about Unicode encoding. However, if there is any Unicode involved, I don't use this module any more, because this module seems to mess up global variables via switching on and off "binmode" on STDIN, STDOUT, and STDERR. This bug has been reported, but somehow it seemed very difficult to fix.

If using this module and Unicode data, one has to, after each call to run3, add binmode STDOUT, ":utf8"; to restore the original modes on STDOUT, etc. So, although it is a very handy module, for Unicode cases, I do not recommend it.

CGI-Compress-Gzip (1.03)

CGI::Compress::Gzip offers a way to have your CGI output compressed into the gzip format using a drop-in replacement for Although it works if you use it as described, unfortunately it isn't quite a drop-in replacement, since it assumes that you're using the object-oriented interface of rather than the procedural one. In other words,

use CGI::Compress::Gzip;
my $cgi = CGI::Compress::Gzip;
print $cgi->header;

words as you'd expect, but

use CGI::Compress::Gzip ':all';
print header;

creates an error message.

Also, in my opinion, this should be built in to itself in the first place rather than being an extension.

Another thing I would take issue with here is the documentation's claim that

"... if the script chooses HTML output, apply gzip compression on any content header for STDOUT."

This isn't actually what the module does, in fact it uses "select" to redirect the output of print; it doesn't affect STDOUT at all. For example, try the following example script:

use warnings;
use strict;
use CGI::Compress::Gzip;
use Template;

my $cgi = CGI::Compress::Gzip->new ();
print $cgi->header ();
print "bobobo\n";
my $tt = Template->new ({INCLUDE_PATH => '.'});
my %vars = (nice => 'guy');
$tt->process ("test.tmpl", \%vars, \*STDOUT, {binmode => ':utf8'})

or die ''. $tt->error ();

Make a text file called "test.tmpl" containing a line of text and then run without compression like this:

$ ./test-comp.cgi

Switch on compression like this:


You'll notice that the "Template" output isn't compressed via gzip, thus breaking everything.

It strikes me that it would be possible to replicate this module's functionality by opening an in-memory file handle:

open my $cgi_output, ">", \$string;

then selecting it:

select $cgi_output;

then running gzip on the string before printing it:

use IO::Compress::Gzip 'gzip' ;
gzip \$cgi_output, \$final_output;

print STDOUT $final_output;

There we are, this whole module in five lines of code. Too radical?

P.S. Sorry if this review isn't useful to you; perhaps you were looking for the Charlie Brown cartoons? Stay lucky, chums.

Water (0.01) *****

Disregarding the advice of WC Fields, I often drink water. Now at last I can also download it from the internet, saving me the journey from my computer seat to the tap. Thanks very much to the creators of this module!

(Contact me at if you have a comment about this review.)

ExtUtils-ParseXS (2.2206)

This module's documentation is pretty interesting. First of all, the only meaningful function which it documents is "process_xs", and yet no such function exists in the module. This is followed by a list of "named parameters" such as this:

Adds extern "C" to the C code. Default is false.

Yeah, and actually looking at the source code we find:

# 'C++' => 0, # Doesn't seem to *do* anything...

Pity the fool who trusts this documentation.

Finally, the coup de grace is delivered by this:

I have no clue what this does. Strips function prefixes?

Fortunately or not, in fact "s" doesn't even exist in the module any more.

(Contact me at if you have a comment about this review.)

WWW-YouTube-Download (0.58)

[Stale review deleted.]

Compress-Zlib (2.015)

[Stale review deleted.]

Lingua-EN-Inflect (1.899)

Lingua::EN::Inflect is a module to adjust single English words with indefinite articles (a/an) or plural and singular. There are various subroutines to turn words into their plurals or add articles. These seem to work well and handle all the usual exceptions like "child/children", "goose/geese", "a university/an upstart" as required, so this module may well be enough for people who want to output correctly formatted text as output from a computer program.

However, I got stuck when I wanted to use this to analyze input. The module does not have an interface to detect if a noun is plural or singular. This seemed very strange since the module's plural comparison functions must have that ability in order to do their work. Internally there is a routine which does this job, called _PL_check_plurals_N, but unfortunately it is not available in the public interface.

The naming and behaviour of the routines is a bit strange. For example "PL" for plural, but the same thing is also used to convert a verb from the third person singular form. For example PL("cat") gives you "cats" as output, but PL("cats") gives you "cat" as output. I don't see when that would be useful, it's a bad idea, and that is not related to plural: "I eat" and "we eat" are singular and plural forms of the same sentence, but the verb doesn't change.

As I said at the top this is probably good enough for the case when you are generating sentences via the computer and want to get your "a/an" and singular and plurals right. So basically it fulfils its purpose. However, that is about all it does, the name "Inflect" is a little pretentious considering this module's functionality.

(Contact me at if you have a comment about this review.)

Lingua-Translate-Google (0.22)

[Stale review deleted - this module can no longer be used without a payment to Google.]

Lingua-EN-Syllable (0.28)

[Stale review deleted.]

Coy (0.06)

[This review and rating is of Lingua::EN::Hyphenate, which is a part of Coy. If you are interested in Coy, there is an interesting article here:


I found this module via Google and the following "mystery manual page":

which doesn't seem to feature anywhere in the distribution.

Why? Because I am looking for a way to break English words into syllables. Now, first of all, note that an incredibly simplistic regex,

my @vowels = ($input =~ /([aeiou]+y?|y)/g);

gets you a 71.4% accurate syllable count. Compared to that, this module achieves a result of only 82.9% accuracy. I thought I could improve it, but a very quick look at the horrendously convoluted regular expressions used in the module and I gave up in despair.

Compare this to Lingua::EN::Syllable, which is about thirty lines of simple code (including two arrays of data), and gets a result of 87.6% accuracy. I am dumbstruck that such an amazing array of regular expressions and subroutines as I have seen in Lingua::EN::Hyphenate can give results as bad as this.

Module-Build (0.4214)

Module::Build is a replacement for ExtUtils::MakeMaker for building CPAN modules.

Unless you already know exactly what you are doing before you start using it, Module::Build is very difficult to use, error-prone, and badly documented. For example, try the following experiment; delete the "package" line from your module. What happens? Here is the build script:

use Module::Build;
my $builder = Module::Build->new(

module_name => 'Fake::Module',

---- end

Here is lib/Fake/

#package Fake::Module;
our $VERSION = 0.01;

---- end

Here is the exact error message:

$ perl Build.PL
Can't determine distribution version, must supply either 'dist_version',
'dist_version_from', or 'module_name' parameter at /home/ben/software/install/lib/perl5/5.10.0/Module/Build/ line 1150.

Adding to this,

perldoc Module::Build

is no help at all telling me about any of these parameters.

This is just one example but very typical of Module::Build: meaningless error messages, and unhelpful documentation. I could pick several other examples, since I've had many, many frustrations like this dealing with Module::Build, but this was the one which prompted me to come here and write this review, since it actually happened (I accidentally deleted the "package" line from a long module, and spent some time trying to work out what on earth the above error message meant.)

Yes, it's my own fault for doing stupid things like accidentally deleting the "package" line from my module. But I don't want to spend all this time and agony learning the convolutions of Module::Build for what seems to be little gain.

To take yet another frustration from today (which is why I came back to rewrite this review), it seems I have not written a module abstract for a different module in the way that Module::Build requires, so it is complaining about "dist_abstract". And yet it does not document anywhere what the correct format for the module abstract is. I try searching on Google, and find in the docs for Module::Build::Functions

"Module::Build looks in the POD of the module from which it gets the distribution's version. If it finds a POD section marked "=head1 NAME", then it looks for the first line matching \s+-\s+(.+), and uses the captured text as the abstract."

OK, I write exactly what it says, like this:

=head1 NAME

Module - My Module


Does it work? No.

Then I try a whole bunch of other variations. Then I look at the source code to try to find what to do. Still I can't work it out. Again it's my own fault: somehow, some way, I should magically know what format Module::Build expects. But I don't.

Yes, I suppose I could study the source code even harder to work out what is going on. But if this really is meant to be the default way to build modules, is it too much to ask for it to be clearly documented, and have meaningful error messages, instead of sending people scrabbling around its source code or searching on Google?

There is some documentation of some of the parts in another module called "Module::Build::Functions", but unfortunately it's not accurate or complete.

Module-Starter (1.71)

(This is a review of the "module-starter" script)

"module-starter" is a script for creating the necessary directories and files when beginning writing a new Perl module. There are nice functions for creating a build script, with a choice of ExtUtils::MakeMaker, Module::Install, or Module::Build, and also functions for creating a manifest and an ignore list for files which should not be put under version control.

It would be incredibly useful if it just did the basic stuff to create a module, but unfortunately this actually does too many things. For example, it puts a message saying "The Great New <module>" into the Pod, and then it also writes a test which checks that the programmer has removed this message. It sounds like a joke, but it isn't. I'd rather, instead of creating all this busy-work, they had kept it simple and not written the text which I then have to remove.

It also insists on including email and free software licence information, with a limited choice of licences and no way to turn this off or alter it. That would be useful if every module was going to CPAN, but my guess is that most modules actually never get released publicly. Also it insists on putting lots of links to, cpanratings, and so on and so on. If these were options they would be great, but as unswitchoffable defaults they are not so great.

Not having an obvious way to turn all these bits and pieces off, module-starter becomes a little exasperating. My verdict: using it creates about as much work as it saves. I recommend against it.

It might be worth remarking that the Module::Starter module which this script is based on also has a facility to add one's own starter modules using it as a framework. I don't know if any exist but it might be an easier way to create something than starting again from scratch.

Text-LevenshteinXS (0.03)

This module doesn't handle UTF-8 encoded strings correctly. It only works on ASCII.


use warnings;

use strict;

use utf8;

use Text::LevenshteinXS qw/distance/;

print distance ("♠♡♢♣♤♥♦♧", "♠♡♢♣♥♦♧");

print " ", distance ("saru", "sagru"), "\n";

which should print 1 1 but prints 3 1

See also

FreeBSD-i386-Ptrace (0.03) *****

The "ptrace" system call provides a way to control a running process, such as catching system calls. This module is specific to the FreeBSD operating system on the Intel 386 processor.

I came to this module after trying fairly unsuccessfully to work out how to call the poorly-documented FreeBSD ptrace. I was looking for an example of ptrace in C. As it happens, Dan Kogai's Perl module was the best thing available for information on these functions. I ended up unwrapping Dan's Perl example into C.

Besides that, it's also a very useful module in itself, if you need to access ptrace in FreeBSD.

JavaScript (1.16) *****

This module provides an interface between Perl and the spidermonkey JavaScript engine from Mozilla. I installed this because I could not get the latest version of JE to work on my computer. The module works very well to the small extent I have used it so far.

The documentation of the module is fairly sparse but it seems to be enough.

The installation of the module itself was fairly painless. However, the installation of the spidermonkey library is not so painless, and unfortunately the "system" version of spidermonkey which comes with some free OSes seems usually to be broken, so it is necessary to self-install the library. The reviewer who complained about the installation problems surely must have had problems with that.

The following page was pretty helpful in installing spidermonkey:


Sorry, but the above blog page is gone now, unfortunately. But I have something which may be useful on my website:

File-ShareDir (1.03)

(Review removed, I no longer use this module.)

Religion-Islam-Quran (1.0)

This module offers various kinds of searches through the Koran/Quran.

The module contains the full text of the Koran in several languages including Arabic, installed into the Perl library space, which may not be the best choice of locations.

I've read the documentation and I've read the source code, and browsed through all the files, and I haven't seen anything resembling any kind of propaganda in it. It's no different from the modules like "Religion::Bible::*".

One criticism of the module is that it seems like the author is not too clear on Perl's powerful encoding abilities since converting the windows-1256 text version of the Koran (QuranArabic.txt) into the Unicode file also offered (QuranArabicUnicode.txt) is a doddle:

use Modern::Perl;
open my $input, "<:encoding(windows-1256)", "QuranArabic.txt" or die $!;
binmode STDOUT, "utf8";
while (my $line = <$input>) {

for my $char (split //, $line) {

my $num = ord($char);

if ($num > 0x80) {

print "&#$num;";

} else {

print $char;


close $input or die $!;

I just about squeezed this into a one-liner (90 characters long):

perl -MEncode -ne'for$i(split//,decode("cp1256",$_)){$n=ord$i;$i="&#$n;"if$n>128

This exactly reproduces the file QuranArabicUnicode.txt in the distribution, so why not save five megabytes?

Crypt-DH-GMP (0.00005) *****

This is a drop-in replacement for Crypt::DH which eliminates a somewhat troublesome dependency. It can be used to replace a Crypt::DH dependency in a third-party module.

common-sense (2.0) *

The documentation for the module makes completely false claims. It says "save a tree AND a kitten".

Not only did my tree get a disease and die, but one of my kittens ran away and I haven't seen him again.

I blame this Perl module.

Net-Whois-IP (1.15)

This is a recursive whois which queries successive servers.

It's flaky, and badly documented, and it even discards its own results (??).

Better to just use backticks: `whois`.

Win32-Process-List (0.09) ****

This module gives a list of processes and PID numbers on Windows. It is an interface to an XS module which calls native Windows routines. The module works on Windows and also Cygwin.

I downloaded this module in order to write a script which would detect a running Emacs process. As an experiment, I used it to make a script to kill off all instances of Google Chrome.

See for the code.

This worked OK to zap all the Chrome processes. However, I noticed that:

* the actual list of processes is created by "new". "GetProcesses" returns an array that was created by "new". This could catch you out if you have a script running for some time and the process list changes, because GetProcesses will return the list of processes at the time "new" was called.

* The functions described in the documentation don't have the documented behaviour. For example, GetProcessPID returns a hash, not a scalar as described. This function doesn't seem to work, though, so the SYNOPSIS program doesn't run anyway.

* It may be easier to just access the undocumented XS function ListProcesses. In the above example,

my %list = %{ Win32::Process::List::ListProcesses(undef) };

gets the same result.

So, although it works well enough, the module doesn't have proper documentation and the documented functions in it all seem to be "fake-o".

Net-OpenID-JanRain (1.1.1)

This module's installation scripts don't work (notice it fails tests on every system).

Looking at the test reports I thought maybe I could get it to work by installing some of the missing dependencies, like CGI::Session, by hand.

However, this wasn't such an easy task as I'd imagined.

I've also installed Net::OpenID::Consumer and got it to work after a short struggle, so I suggest using that instead.

Win32-OLE (0.1709) *****

Win32::OLE is a Perl module for interacting with Microsoft's OLE system for automating application programs. It can be used to control Office programs like Excel, Word, and PowerPoint from a Perl script. The entire object model of the Microsoft applications is available, so it is possible to almost completely replace VBA by Perl. (The parts you can't easily replace are things like forms.) I use this module daily and have had very few problems with it. The integration of the Microsoft objects into Perl object form has been done very well.

There are some books on how to use Perl with Microsoft applications, but I've never looked at them since it is easy to translate the online VBA documentation into Perl.

Another big plus is the ActiveState mailing lists where one can get very well-informed help for these modules.

* Pitfalls for the unwary

However, people who are thinking about using this module should know that the transition between the Microsoft and Perl worlds is not always entirely smooth. A bug which often catches me out is sending what I thought was a number (for example to specify an Excel sheet or column) to a Microsoft object and having an error thrown back at me, because what I thought was a number was actually a string:

my $text = "sheet12";
if ($text =~ /sheet(\d+)/) {

my $sheet = $1;

my $value = $Excel->Sheets($sheet)->cells(1,2)->Value();

# Crashes!

(The error here is that $sheet is a string not a number to OLE.)

Another source of trouble is Excel's date fields, which I solved thanks to advice found on Perlmonks.

Yet another problem is file names; sometimes / works, and sometimes it doesn't, and you have to

$filename =~ s:/:\\:g;

to get Windows applications to accept file names. For example, Excel will happily open a file /like/this but when you try to use the SaveAs method, it will only accept a file name \like\this.

* Comparison with other modules

For purposes of comparison, accessing Excel via Win32::OLE seems to be about five times faster than using the ParseExcel module on CPAN. On the other hand, you can't really use Excel via OLE non-interactively, so if you need to process Excel files in the background, ParseExcel is a better bet.

Net-Telnet (3.03)

[Review deleted pending update - sorry] (3.44) ***

Although is a "core module" included with the distribution of Perl, it has an ill-thought out, cluttered interface. Unfortunately, this interface can't be changed, since so much is built on top of it.

The documentation deserves special mention for being unreadable and unhelpful. Example: one of the basic functions of is to read from STDIN. Where is this even mentioned in the documentation? Absolutely nowhere. Instead, if you search for the words "STDIN" or "standard input", you'll find a lot of obscure claptrap, and not even one mention of the vitally important fact that using this module means that it reads standard input to EOF. Another reviewer mentions that the idea is to write gibberish documentation and then put the real documentation in a for-sale book in order to make money. That's a very cynical comment but it may even be true in this case.

Added to the problems of dealing with the horrible instructions are the inclusion of a set of fancy and yet irritating HTML generation routines. This is a design mistake. Dealing with the CGI is a completely different task from HTML generation, and HTML generation routines have no business in a CGI module.

The maintenance of the module is also questionable. The source code is a hodge-podge of patches and it is filled with "dead" comments which no longer apply to the code. Copyright notices seem to be out of date.

However, despite the negativity expressed above, which was created by the frustration of dealing with this module's documentation as a beginner Perl programmer, I want to qualify this review by saying that the code DOES ACTUALLY WORK, unlike a lot of the imitator CGI modules on CPAN.

Modern-Perl (1.20150127)

[Stale review deleted.]

Net-MacMap (0.01)

This module maps MAC addresses (ethernet hardware addresses) to the manufacturer (called the "vendor" for some reason).

This contains a list of MAC vendors hard-coded into its source code. Since the module hasn't been updated since 2003, and the list of MAC vendors is updated every day, I suggest using Net::MAC::Vendor, which pulls info directly from the website, instead of this.

Net-MAC-Vendor (1.25)

Net::MAC::Vendor provides a way to get information about the vendor from the MAC (Media Access Control) number which is associated with Ethernet hardware. It's handy for jobs like working from a router's arp table to what the hardware actually is (e.g. Nintendos or something for which it's hard to find what the IP address is).

The "lookup" part of the module works correctly although not quite as described (reported as bug #44963) - the vendor is the first part of the array and the address part is the rest. However, why does the module even bother returning the postal address? Unless we are planning some kind of mass mail shot to ethernet hardware vendors, the only information anyone is really likely to want is the vendor. Why not just provide that, and people who actually need the postal address for some reason could go to the IEEE web site.

Also, the dependence on the DBM::Deep module for caching seems unnecessary to me. The information which needs to be stored and read is an extremely simple fixed format which could be read into a hash and appended to a text file without the need for any dependencies, particularly one as complex as this.

WWW-Scraper-ISBN-ISBNdb_Driver (0.07) *****

This is a backend for WWW::Scraper::ISBN, a method of retrieving information about books via their international standard book number (ISBN) from the internet. This particular module obtains this information from the "" web site. In order to use the module, each user needs to obtain a string called a "key" from

Once you have obtained your key, you can test whether it works with the test scripts provided with this module. For example, in Cygwin, I installed this module, then set a variable "ISBNDB_ACCESS_KEY" like this:



and went to the test directory of the module, "/home/bkb/.cpan/build/WWW-Scraper-ISBN-ISBNdb_Driver-0.07/t" and ran the following test:

$ perl -T 01-isbndb.t

The module worked correctly as described to retrieve information about books based on their ISBNs from the web site.

However, it would be nice if the module's default behaviour didn't require "no warnings;". Also the module currently has a bug that it doesn't check its return value from Business::ISBN->new() and so it just crashes on a bad ISBN value with a weird error message instead of failing cleanly.

[This review was altered on 4 April 2009 to reflect changes to this driver module.]

Net-Interface (1.012)

Net::Interface promises to be a version of the Unix command "ifconfig" for use by Perl. It sounds like a good idea but my experience of the module so far has not been very good. The documentation does not make clear what systems the module is able to run on. It compiled on Linux but not on Cygwin so possibly Cygwin is not supported. However, although it compiled on Linux many of the functions failed to run. Although "ifconfig -a" returns the MAC address of my ethernet interface, this module failed to get it: using the ->info() method, very strangely it says that my mac address of eth0 is "[". Also, the function "hwaddress" failed to run with an error message. What surprised me the most was to get a "Usage: " message from the module even though I was running it from a script.

The documentation is not good. It starts off by telling you it is a "Perl extension" which is something hopefully we already knew. The synopsis doesn't offer an example but a list of imports, which is not much use. The body of the documentation is a mish-mash, for example there are sudden random comments in the middle of the documentation saying "NO LONGER SUPPORTED". I'm sorry but it's hard to read something as disorganized as this.

The interface seems frankly horrible: here is a quote from the documentation:

"->new(); has multiple calling invocations.
This method will refresh the data for an existing interface OR it can modify and existing interface OR it can create a new interface or alias."

I know "there's more than one way to do it" but I think it's virtually an abuse of conventions to stuff a function to refresh data for an interface into a function called "new".

This would be a good module if it ran on all platforms and worked properly, but since it's easy enough to just call ifconfig/ipconfig via "system" or backticks, this module doesn't seem very useful to me.

Test-Warn (0.11) *****

Test::Warn provides a way to test the warnings output by your Perl program.

The syntax of the tests seems odd to me, but it was clear enough what to do from the examples provided. Test::Warn seems fairly comprehensive since it also coped with warnings emitted by carp/croak.

The best thing about it is that it is fully integrated with Test::More, so you don't have to do any extra fiddling to get this to work beyond installing it.

Just as a side note, and regarding the review I wrote of Test::Pod::Coverage, this is yet another module which fails to install because of failed pod tests. If you are on Cygwin and this fails to install, remove t/pod.t and all will be well.

Win32-Codepage (1.00) *****

This module returns the default code page for your Windows system. I only needed the function "get_encoding" from this module. For my particular problem it returned the code page encoding correctly.

Test-Pod-Coverage (1.08)

Message to all Perl module authors: could you please disable Pod coverage tests when you distribute a module through CPAN?

First of all, as other reviewers note, the above module is difficult to set up and run, and so including these tests in your distribution will make your module fail to install on some people's systems. This will reduce the number of people who can use your module.

Second of all, this module is only useful for module authors, to check that your documentation matches the actual module. Your module's end-users do not need to run these tests.

Win32-WebBrowser (1.02)

Win32::WebBrowser starts the default web browser on Windows.

I tested it by changing around the default browser and pointing the module both at files on my system and the world-wide web, and I'm glad to say that it works exactly as stated, but it would be nice if the module was integrated slightly better into the Perl ecology.

At the moment it is set up to fail "make" and "make test" if $^0 is not set to 'MSWin32', hence the failed tests on Linux systems. Just for the sake of the CPAN testers, the make script should be set up better to detect the OS and do something more sensible than just going kaboom.

Also, despite the way it is set up, the module installed and ran perfectly on Cygwin after I'd commented out parts of the installation scripts (most of t/01load.t and lines 14-22 of Makefile.PL).

re-engine-TRE (0.09)

Tre ( is a regular expression library which extends standard regular expressions with approximate string matching. The re::engine::TRE module links the Tre regex engine into Perl as a substitute for the usual Perl matcher.

The module has very little written description of what it does, in particular there is nothing about how to use the approximate regexes. After much trial and error with no success, I went to the tests of this module, but still couldn't find anything which told me how Tre's syntax was implemented.

Unfortunately Tre itself is barely documented. The website's documentation consists of a grammar with not even a single example. However, it has lots of tests, so I took some example regexs from tre's "tests/retest.c" file, which look something like this:

test_comp("\\<(foobar){~}\\>", REG_EXTENDED, 0);
test_exec("zfoobarz", 0, REG_OK, 0, 8, 0, 8, END);
test_exec("boing zfoobarz goobar woop", 0, REG_OK, 15, 21, 15, 21, END);

and tried putting them into this module.

No luck!

Either the module hasn't implemented Tre's special regexes, or the author hasn't written any tests or documentation which use them. Just one line of example documentation, or even just a line in the test script, would have made a big difference to the useability of this module.

JavaScript-Minifier (1.14)

Review removed.

JavaScript-Packer (0.04)

Review withdrawn.

JE (0.032) *****

JE is a JavaScript engine written in Perl. It parses and executes JavaScript, and allows communication between the JavaScript and Perl. Impressively, it can parse big chunks of JavaScript without error and execute the parsed code correctly. This gives one way to run unit tests of JavaScript code from a Perl script without having to fiddle around with a browser, which is quite handy if you need to program something complex in JavaScript.

On the negative side, as the documentation states, it is fairly slow. JE doesn't know anything about things like document.getElementByID and other such DOM stuff, so it won't work on most of the JavaScript on the world-wide web. I don't know if there are plans to make it work with parsed documents in the future, but the author has also written an HTML::DOM module.

The documentation is not particularly nice but it is good enough to get you started writing stuff quickly. The interface is also fairly easy to understand. Parts of the module are clearly unfinished, with error messages sometimes popping up from obscure line numbers inside the source code (this only happened when parsing incorrect JavaScript though).

[Note to the other reviewer: Regarding the name "JE", my guess is that due to the many sub-modules, the author decided to pick a very short name in order not to have to type such incredibly long things as JavaScript::Engine::Object::Error::ReferenceError. It also goes by the alternative name of "JavaScript::Engine" if you prefer.]

Template-Multilingual (1.00)

This module is for templates in multiple human languages, so the user can get a different output from a template depending on which language they select.

I spotted this module a day or two ago after having spent a little time doing exactly this job, making some HTML pages for different human languages. I had been using the plain template toolkit and found it worked pretty well.

I looked at this module wondering what advantages it offered. However, having read the documentation and source code, and written a test script, I don't think there is very much this module does which the plain template toolkit itself can't. Using the example from the documentation, the template toolkit can do much the same thing, if we just throw a variable "lang" into it:
[%- IF lang == "en" -%]
[%- ELSIF lang == "fr" -%]
[%- END %]
The advantage of the template toolkit is that it has the [% %] syntax, which I much prefer to the HTML-tag-like format of Template::Multilingual. Things which look just like HTML tags could be confusing stuck in the middle of real HTML. Template toolkit syntax stands out from HTML, and you can look at an unprocessed file in a browser, without the browser deleting the tags. Template::Multilingual's pseudo-HTML tags will just disappear.

The only thing which Template::Multilingual seems to offer above the template toolkit is the ability to parse strings like "en_US" and find default values like "en" when US English isn't available. That isn't particularly useful for me, but it may be for some.

String (1.5) *

This module makes a close approximation of the JavaScript "String" object for Perl, offering functions like String.toUpperCase as a replacement for "uc":

my $x = new String("Perl");

instead of

$x = "Perl";
uc $x;

Perhaps it's meant to be useful for a JavaScript programmer coming to Perl for the first time, or as part of a backend for some kind of automated JavaScript to Perl convertor, but the documentation doesn't mention why Perl needs this.

Lingua-Romana-Perligata (0.50)

Very whimsical.

Text-Tree (1.0) *****

This module produces an ASCII graphics tree from inputs.

The functionality is fairly basic but it does what it claims.

Bugs exist in multi-line (\n) handling.

Tree-Visualize (0.01)

The author states "I am releasing this to CPAN largely as a means of self-motivation".

With no progress since November 2004, and a version number of 0.01, perhaps this means of self-motivation has been unsuccessful.

Note that many of the source code files are empty.

CGI-Mungo (1.1)

Why put both CGI::Mungo and Mungo (top level namespace)?

Lingua-JA-Kana (0.07)

This is a module for converting between three forms of Japanese writing, hiragana, katakana, and romaji. It is definitely a better bet than Lingua::JA::Romaji.

It functions correctly but is fairly basic. For example, the handling of ん is inadequate, and generally the module has no options to control the type of romanization performed.

[Review revised 9 Feb. 2009 since bugs mentioned in previous review have now been fixed.]

[Review revised again in June 2011 since module now handles full/half width katakana. Star rating removed but will probably persist in due to a bug which I reported, years ago, but still isn't fixed.]

Moose (2.1603)

[Stale review deleted.]

Module-Install (1.16)

The basic notion of Module::Install is to have an easier way to install your module with all kinds of things done automatically. This is a good idea, but it does so many things automatically that it's more than a little annoying. For example: if you happen to have a file called "" lying around in the directory, it will try to incorporate that into your module's set of tests, without asking you, even though it may be something you don't even want in the distribution. Or you may have some alternative or obsolete .pm files you actually don't want in your distribution, but it will try to bundle them all up and write tests for them.

Another annoying thing is its behaviour with regards to the MANIFEST file: it "kitchen sinks" the MANIFEST with every bit of cruft and every rotten old file that it can find in the directory tree. Perhaps I'm untidy or disorganized but I'm tired of having to continually fight against this module adding unwanted files and tests all over the place. This module is much too clever, and it should be stripped down to do no more than the user expects.

<Added to review August 2009>:

Here is a typical example of the irritating behaviour I described above:

[ben@mikan] My-Stupid-Module 519 $ make manifest
/home/ben/software/install/bin/perl "-Iinc" "-MExtUtils::Manifest=mkmanifest" -e

Added to MANIFEST: boo
Added to MANIFEST: bugs/bug_list.xml
Added to MANIFEST: inc/Module/Install/
Added to MANIFEST: My::Stupid::Module-0.01.tar.gz

Doubly irritatingly, it tells me I should edit a file called "MANIFEST.SKIP" in order to tell it not to do all this.

No! It should never have added those files without asking in the first place. I don't want to tidy my development directory, and I don't want to have to write a stupid MANIFEST.SKIP file either.

<added to review 19 Feb./modified August 2009>

Another annoying thing is that it can break compatibility with other modules. As the other modules get updated, Module::Install stays the same inside your directory, and on repeated occasions an install failed because of an incompatible old version of Module::Install.

Frankly, it's annoying. The only reason I'm still using this instead of ExtUtils::MakeMaker is because of File::ShareDir.

Mail-IMAPClient (3.18) *****

The module behaved largely as I expected and performed correctly and robustly to search, retrieve, and delete mail from the server under a variety of requirements. At the time of writing, this seems to be the best documented and most useful module for dealing with IMAP on CPAN.

With reference to Florian Knell's review about the speed of the module, I believe this is a server-side issue and not the module's fault at all.

Netscape-Bookmarks (1.95)

Hmm, there are two versions of this module floating around the internet, one on CPAN and one on SourceForge, causing users some confusion.

Both work with Firefox but some of the attribute fields of the bookmarks from recent versions of Firefox are missing.

It would be nice if

a) the author updated it to work with the bookmarks of recent versions of Firefox.
b) there weren't two versions.

Lingua-EN-Phoneme (0.01)

A good idea but the module seems misnamed. This isn't a general phoneme module for the English language but a way of getting phonemes out of CMUDict. I'd call it Lingua::En::CMUDict or something similar.

NetxAP (0.02)

[Stale review deleted.]

IMAP-Client (0.13)

I stumbled upon this while looking for some kind of IMAP module, because unfortunately "" doesn't have any kind of popularity feature to rate its search results.

Upon a brief trial of this module, there doesn't seem to be anything particularly wrong with it, but if you are wondering what IMAP module to use, Mail::IMAPClient is a much better bet than this one. It has better documentation and more functionality.

XML-Parser (2.44)

I sometimes need to parse the horrible format known as XML. What to do? The obvious solution in Perl seems to be XML::Parser.

However, XML::Parser has been a miserable experience. Yes, it works, but it is not nice. The problem is that the nature of the callback structure forces you either to use untidy global variables, or jam some foreign object into the parser object itself in order to keep your data somewhere as you parse the XML. In other words, there is no sensible place in XML::Parser to keep your data as you parse your XML file. It's as if it was designed only to parse the data but not ever do anything else with it.

This leads to the problem I've had with this, that every time I use XML::Parser, and want to do something slightly different, I end up having to copy and paste the entire parsing code, even if I am reading exactly the same file. It's very difficult to bundle everything up into a module to read the file and so I tend to end up with hundreds of similar and yet annoyingly incompatible parsers for exactly the same data.

However, today I came to CPAN ratings, looked at the other ratings for XML::Parser, and found recommendation for XML::SAX. I went and looked at the documentation, and found the solution to my problem is to use a closure:

"The only way currently with XML::Parser to safely maintain state is to use a closure:

my $state = MyState->new();

$parser->setHandlers(Start => sub { handle_start($state, @_) });"

That's useful to know.

libwww-perl (5.820) *****

I really like this set of modules, because they save me so much time. The functions do what I think they're going to do, and the documentation always heads me in the right direction. Unlike the horrific, even when I was a complete beginner at Perl I was able to use these modules without severe stress, which is one of the big reasons I like them.

I'm sure these modules have their limitations but if I need to stretch the boundaries of what these can do, I'd expect to have to fiddle with source code and write my own modules. I'd much rather have a simple thing to make straightforward jobs easier than a complicated thing which I can't use to "just get it done".

Mail-Mbox-MessageParser (1.5105)

How hard can it be to write a parser for the mbox format? The whole thing is just a concatenation of files separated by a blank line and /^From /. So why is it that writers of "fast and simple mbox parsers" like this can get things so wrong? For something which claims to be simple the installation alone requires downloads of a huge variety of C programs. I had more luck just writing my own mbox parser.

MIME-tools (5.427) ****

The module seems to work very well, although there are parts of it I don't yet understand, but the documentation is an incomprehensible mixture of annoying quips and patchy information. In the end I had to resort to reading and altering the source code to work out what the module was doing. Any documentation, for any module, needs clear pieces of sample code so that programmers can work out how to use the module. Lame quips and vague statements are not helpful.

Mail-Box (2.118)

This module is not only difficult to understand, but also doesn't seem to work, and for added fun it takes an age to install. A winning combination! All I wanted to do was to parse an mbox file. So I downloaded and installed this. Too bad, it won't install. So, after also trying another couple of CPAN modules, I ended up writing my own parser. Guess what? Between the time I spent struggling with this module's near-incomprehensible, miserable cross-linked documentation and waiting for it to miserably fail its tests, I think I spent more time on this module than I did on writing my own mbox parser.

Mail-POP3Client (2.18) *****

This module worked "out of the box" for my task without any problems or complications. Documentation seems complete and accurate.

Text-Levenshtein (0.07)

[Review deleted]

warnings-unused (0.04)

Review deleted due to module compilation failure.

Text-Banner (1.00)

It doesn't install using cpan, and the directory structure seems messed up, so you have to download it and install it "by hand" (make / make install doesn't work either) from the tar file instead.

Once you do, you get something which is like the Unix "banner" command, but with a lot of "creeping features" and object-oriented guff syntax, so first of all you have to create your object with "new", then "set" your banner and then "fill" it and then "get" it - clearly a case of object oriented programming going too far. Why not just have one simple single routine called "banner" which prints a reasonable default banner using # or X or something?

Fortunately it doesn't use Moose, but even so honestly I'm not sure what the point of the features and the object orientation is. And the default behaviour is plain stupid, it prints out the banner using ones and zeros: seriously this is its output (sorry if fixed width gets messed up):

0000000 0000000 0000000 0000000 0000000 0000000 0000000 0011100
0011110 0100001 0000000 0011110 0111110 0001100 0111110 0011100
0100001 0100001 0000000 0100001 0100001 0010010 0100001 0011100
0100001 0111111 0000000 0100000 0100001 0100001 0100001 0001000
0100001 0100001 0000000 0100000 0111110 0111111 0111110 0000000
0100001 0100001 0000000 0100001 0100010 0100001 0100000 0011100
0011110 0100001 0000000 0011110 0100001 0100001 0100000 0011100

The other annoying thing about the module is that it stores its data as some kind of crushed binary, which superficially looks clever but actually will surely be a pain if you want to do something other than use the banner characters the author suggests.

You could use this if you're desperate to have a Perl solution, but I'd recommend using the C banner program from Cedar Solutions which comes with Cygwin instead, or if you want lots of font options you might also like "figlet". The banner which comes with Linux is not much use because it prints too big and vertically instead of horizontally.

W3C-LinkChecker (4.81)

W3C::LinkChecker is the WWW consortium's own link checker (it looks at links in HTML pages and tries to check whether they are OK or not.)

It works but the results are horribly ugly and it's buggy, printing out uninitialized variable warnings to STDERR as it runs.

On the HTML setting the results are really silly and bossy messages ("This link is broken. Fix it NOW!") in a horrible colour scheme of red, yellow and grey.

Other problems: it doesn't seem to have any way to stop repeating the same messages over and over again when links to the same page appear on more than one checked page. In fact I ran it using its "--recursive" option on a set of pages which all contain links to the w3 consortium's CSS/HTML checkers, and for every single page it checked, it printed out exactly the same messages, over and over again, about robots.txt.

As far as checking links goes, it worked to some extent but it doesn't have features which I'd expect in a link checker. Xenu's link sleuth probably works better than this.

Games-Battleship (0.05) *

This game is very boring.

Badger (0.01)

According to the copyright notice, version 0.01 has been in development since 1996. Given another twelve years hopefully we'll get to version 0.02.

Perhaps this is why Mr T pities the fool that attempts to builds a production system based on Badger version 0.01!

Text-SimpleTable (0.05)

Hmm, what's wrong with Text::ASCIITable?

This looks like reinventing the wheel.

Template-Toolkit (2.20) *****

The template toolkit enables you to automate repetitive tasks in your Perl script without having to use "here documents" and long strings of text within the script itself. This aids maintenance of the Perl script and the text, since they can be edited separately.

The template toolkit is fairly well-thought-out and has been in use for long enough by enough people that bugs are very few. It is also very comprehensive, and has fairly good and complete instructions. But I have no idea why the author offers the documentation in such a variety of colour schemes. Some kind of whimsy?

One negative point I have is with the "extra language" one has to use for the toolkit. If I was going to make my own toolkit (I don't need to because this already exists), I would not use a separate syntax but just keep the usual Perl syntax inside the command bits [% %].

Data-Validation (0.2.52)

Looking at the source code for


we find

use Moose;
use Email::Valid;

then there are three lines of code which call Email::Valid. I'm not sure it even uses Moose, perhaps that is just there to look trendy.

Similarly there is a number validator which calls up a routine from Scalar::Util, and so on.

I have to ask what's the point of making modules like this, which just call other modules.

For the postcode part of the module, it doesn't mention that this is UK postcodes (not Canadian postcodes or something) module. How about taking over the maintenance of the existing but abandoned module Geo::Postcode instead of making another one?

Text-ASCIITable-TW (v0.02)

Since the module doesn't have any documentation to speak of, perhaps it's worth pointing out that it's intended to make Text::ASCIITable useable with Taiwanese (Traditional Chinese) characters.

It would make a whole lot more sense to write an ascii table module using the Unicode::EastAsianWidth module, which has the facility to detect wide characters from any east Asian language, including Korean, Japanese, and simplified Chinese.

Even more sense would be made if the author managed to convince the Text::ASCIITable author to incorporate that into the original module.

DateTime-Locale (0.43)

[This is a review of DateTime::Locale::ja, but some of the contents refer to the DateTime::Locale module too.]

This module is inadequate. It makes no effort to conform to the standard Japanese practice regarding dates (era-based years) and thus is of little practical use. It's a kind of "paint-by-numbers" methodology of creating a locale module which doesn't really reflect local usage.

It would make more sense to have modules like this written by people who speak the languages in question. Further, it would make more sense not to package all the DateTime::Locale modules together, so that someone who just wants to install one language's locale doesn't end up having to download a hundred or so date localization modules.

Still, one must be very careful not to anger the Perl gods who write all these crappy modules.

WWW-CPANRatings-RSS (0.0304)

Review deleted.

Test-Simple (0.92)

Review deleted.

Regexp-Wildcards (1.01)

This is a nice module & looks to be very helpful in making user interfaces for people who don't understand regular expressions.

Regexp-Common (2.122)

This is a useful module. However, it would be a much better module if all the cruft, like regular expressions to match tv urls, was removed from it. Unless tv urls are much more common than I had thought?

Acme-EpicFail (0.02) *

Hm, I thought it was lame. First of all it failed its tests on Cygwin. Second of all the only thing it does is either print "EPIC FAIL!" or "EPIC MEGA FAIL!". I was expecting some more spectacular forms of failure.

Pod-Simple (3.31)

[Stale review deleted.]

Pod-HtmlEasy (1.0102)

The module is OK if you use it to read and write from standard input/output as it says halfway through the documentation. However, it seems quite flaky and buggy if you actually try to use the module as a module. The script supplied with the module doesn't work and it keeps whining

"All options must be paired with values"

Similarly if you try to write your own script using it.

The HTML output looks like CPAN's which is a big benefit compared to the ugly one produced by POD::Simple::HTML.

But either the documentation is broken, or the module is broken, in a way that a couple of test scripts should have shown up, so I can't give it more than three stars. Write proper tests and fix the documentation.

DateTime-Calendar-Japanese-Era (0.08001)

The module works as stated but with a few quibbles. Firstly it has enough dependencies to keep the computer busy for about ten minutes just to install it, including all those good old Albanian dates. Secondly the documentation doesn't tell you what's in the data structure, so you've got to go and look at the source code. Thirdly, the data is not in an ideal format - the kanji names come out as UTF-8 but not decoded, so you either have to use "Encode::decode_utf8" to get the data into utf8 for actual printing, or turn off utf8 printing on your output stream.

Fourthly, the id names of the eras are OK for a unique ID but it would be nice to have either a kana or romaji version of the name without the numbers which are added for uniqueness, like SHOUWA2, otherwise the user has to strip off the 2's.

I'd also quibble with the decision to use File::ShareDir to store the data - since there is little possibility of not having to load all the data, why is it necessary to add another layer of complexity to the module?

Disclaimer: I have no idea about the reliability of the dates used in the module.

Convert-EastAsianWidth (1.02)

Zonked review since no longer relevant.

Unicode-EastAsianWidth (1.33)

[Stale review deleted.]

Unicode-Unihan (0.04)

As it stands, this module is not very useful.

If you have a copy of Unihan.txt, you can do the following to get the same results as the example given in this module, assuming $c contains the character you want to look up:

system ("grep U\\+".sprintf ("%X",ord ($c))." Unihan.txt | grep Mandarin");

So, since it's possible to replace the only function of this module with "grep", I'm not really sure what the point of the module is. Perhaps Unicode::Unihan has a speed advantage. But that is the only advantage that I can imagine.

Also, the AUTOLOAD-based interface is not very practical. If I want to look up the kMandarin key of the Unihan database, I have to access it via a named method like

$uh->Mandarin ($c)

that means that it's hard (messy) to access an arbitrary lookup key at run time, and unless I want to run around eval'ing, the lookup keys have to be hard-coded at compile time. That makes it hard to use this module as a backend for a user accessing a dictionary front end. It would be much cleaner to allow access via something like

$uh->lookup ('Mandarin', $c)

Using AUTOLOAD to create a method to look up the key is an example of someone doing something which is "too clever" and not actually useful.

Another deficiency of the module is that it doesn't have a method to grab all the keys associated with a particular character, like

my $hash_ref_containing_everything = $uh->all_info ($c)

That seems like an obvious functionality, and it's the first thing I'd implement if I was making this module. And, we should be able to go from a value, like the Mandarin pronunciation above, to the characters, so I can go

my @list_of_chars = $uh->lookup_values ('Mandarin', 'TUAN');

not just from a specific character to its specific value of one key.

Finally, for the sake of convenience it would be nice if there was a way to get a list of all the keys in the database other than going and looking at Unicode's web page.

Image-ExifTool (7.60) *****

I've used this module for a variety of images from a variety of cameras and found it to be complete and well documented. I tried the other EXIF modules on CPAN too and I'm pretty sure this is the one to use.

Incidentally to the review, it may be interesting to note that the source code is the only example I've seen of extensive (comprehensive?) use of Perl's prototype system in a CPAN module.

Image-EXIF (2.01)

It's not complete enough to be useful, and the interface is not documented. I suggest using Image::ExifTool instead.

String-Approx (3.27)

[Stale review deleted.]

Flickr-API (1.25)

[Stale review deleted.]

Lingua-Flags (0.07)

A cute idea, make little flags for each country for use in web pages.

It failed its tests for some reason, but I installed it after that anyway, because the problem seemed to be badly-written tests rather than bad code.

Suggestions for improvement:

1. It would make sense to use something like File::ShareDir (part of Module::Install) to store the data in rather than having all the data in the module. At the moment the module is over 100,000 bytes of mostly data.

2. It would be preferable to have SVG or other vector versions of the flags rather than gifs, if possible.

Flickr-Upload (1.32) *****

I was sick of jUploadr*, I couldn't be bothered to keep switching on Windows to use the "real" Flickr Uploadr, and uploading bunches of photos via the web interface was too fiddly. So I installed this module and wrote a script, which is about twenty lines. In a few minutes I had a working command-line photo uploader for Flickr.

[P.S. Note that there is actually an upload script in the distribution, so you don't need to make your own].

* jUploadr grabs core memory to store each photo in full, so if one drags and drops twenty or so large photos onto jUploadr on a normal powered computer, the computer virtually comes to a halt for one hour.

String-Diff (0.07)

Basically a wrapper for Algorithm::Diff, this module is fairly handy, and the documentation is better than Algorithm::Diff's is (which isn't saying much, since drinking a pint of salty sea water would probably be more fun than reading Algorithm::Diff's documentation).

The module works as advertised, but its application for most people won't be much more than just an example of Algorithm::Diff.

String-String (0.01)

[Stale review deleted.]

String-Buffer (0.05)

[Stale review deleted.]

String-Strip (1.01)

Re the comments of the other two reviewers of the module:

#!/usr/local/bin/perl -wl
use strict;
use String::Strip;
my $test = " \ta b-c def g; * ";
my $test2 = $test;
print "<",$test,">";
StripSpace ($test);
print "<",$test,">";
print "$test2";
StripLTSpace ($test2);
print "<",$test,">";

$ ./
< a b-c def g; * >

a b-c def g; *

So it doesn't seem to work as advertised, but it doesn't seem to delete hyphens either.

Acme-Monta (0.01)

Presentation method of popular Japanese TV host "Mino Monta" in HTML. Click the text and the colour changes from black so you can read the hidden words.

Lingua-JA-Romaji (0.03)

[Stale review deleted since not I will not be using this module and don't want to re-check.]

Encode (2.78)

[Review of Encode::Guess deleted since not using module any more]

DateTime-Format-Japanese (0.04000)

[Stale review deleted.]

Unicode-Japanese (0.49)

[Review deleted due to broken characters]

Data-Validate-Japanese (0.01001)

[Review deleted]

Lingua-JA-Regular (0.09)

Perl programmers who have to deal with Japanese might need something to transform half-width and full-width characters, or irregular kanji, and might come across this module in a search for "zenkaku" or "hankaku".

Unfortunately, though, this module is not useable as it stands. First of all it doesn't install correctly. If you're thinking of installing it, note that this module uses Dan Kogai's, and the reason it fails "make test" is because it doesn't mention that dependency. If you install Jcode before Lingua::JA::Regular, it will pass all its tests and install correctly.

Note also that the module is based on the EUC-JP encoding. In particular the functions for dealing with CP932 just convert the CP932 characters into ASCII forms rather than the corresponding Unicode symbol.

This module also has functions for dealing with fullwidth spaces, but these are obsoleted if you use Perl's internal encoding, since \s matches fullwidth spaces (0x3000, the things called "IDEOGRAPHIC SPACE" in the Unicode documentation). There may have been justification for using EUC-JP when the original version of the module came out, since version 0.01 of this module came out before Perl 5.8.1, but if you have to deal with a lot of Japanese codes nowadays you'd be better off switching to utf8.

The documentation is also minimal, unfortunately, and it doesn't have any facility to set the character set required except by looking at $ENV{HTTP_USER_AGENT}, which is weird. I'd recommend not using this module unless it's greatly updated.

Pod-Html (1.09_04)

This is a review of pod2html, not "Pod-Html".

It's fairly annoying.

The most annoying part of pod2html is that the error messages don't have line numbers but paragraph numbers - even though pod is a line-based format. So it's next to impossible to work out where the errors are. To work around this, you can run the module through podchecker, but podchecker doesn't give you all the error messages, for example the ones about links not being found.

Other annoying behaviours include turning a link to something into "the ... manpage". Note that itself doesn't seem to use the module either.

DateTime-Calendar-Japanese (0.06001)

This module seems incredibly bloated, requiring huge numbers of other, unrelated, modules and libraries to be downloaded and installed. For example, it requires a download of date formatting for Albanian to be installed, even though Albanian has nothing to do with either Japanese or Chinese. Although certainly the date calculations are complex, I think it's very hard to justify the number of downloads this module requires which don't have anything to do with Japanese or Chinese dates.

File-Mork (0.3)

This is much better written and more useable than Mozilla::Mork, but its documentation and interface don't add much value to the original Zawinski script,, which it was copied from, and it has some fairly glaring bugs. Like Mozilla::Mork, it's quite hard to see what the author is trying to achieve which doesn't. If you use this module, you'll probably end up having to alter the source code anyway, so I'd recommend starting from the original Zawinski script instead:

But ... note that the Zawinski Mork parser also has some bugs.

Mozilla-Mork (0.01)

Basically a stripped-down version of Jamie Zawinski's script, it's hard to see the point of this module. In particular the documentation is unhelpful and the Perl code does very little extra beyond what does. Its interface is downright annoying, with lots of verbose messages even when you set $verbose to zero, printing of whitespace to STDOUT while parsing, etc., and it seems to be fairly buggy.

If you need to parse Mork, you'd probably be better off adapting Jamie Zawinski's instead of this:

HTML-TableExtract (2.10)

Useful, but has flaws.

This module is very handy for getting the entries out of tables quickly. However it has some flaws. For example it's not possible to get the attributes of the <td> and other tags which form the table, so if you need to extract only the elements which have a certain name or class, you'll be stuck with this.

There is a way around the problem but it's complicated.

The other big problem with this module is that it's broken on Cygwin and Windows.

ShiftJIS-CP932-Correct (0.05)

I found this module when I was processing a bunch of Microsoft Word files and getting errors of the form "shiftjis \x87 does not map to unicode". I quickly installed this module, put it into my program, ran the program again, and got rid of the errors, in a couple of minutes.

However, in retrospect I should have just used the CP932 encoding rather than using Shift-JIS.

Lingua-JA-Numbers (0.04) *****

This is a module for converting between numbers represented as arabic numerals (0..9) and Japanese-style kanji numerals. It can also turn a number in arabic numerals into its Japanese pronunciation.

The module works as described and is clearly documented. It is able to convert numbers in either kanji or kana, and it can cope with "big" numbers which overflow Perl's integer representation by using strings.

Smart-Comments (v1.0.3)

Review deleted. [I'd rather add print statements actually.]

Business-ISBN (2.05) *****

This module works as described in the documentation, is easy to use, is well documented, and does its job correctly.

WWW-Search-ISBNDB (0.3)

First of all, the documentation of this module has a lot of problems. The example at the top doesn't work, it has ' in the wrong places, the "native_query" method used for searching isn't documented, and when you do get it to run it just prints out HASH(0x10239485) type of things instead of meaningful results.

Secondly, the module doesn't seem to work properly - the results I got were nonsense, and I couldn't see what I was supposed to do from the documentation. I wanted to search by ISBN but it didn't make it clear how to do that.

In the end it was much easier to write the scraper "by hand" using LWP::Simple and the excellent API documentation of than using this module, so my advice is to forget it.

WWW-Scraper-ISBN (0.25)

Review deleted, since the [negative] comments I made don't apply to the most recent version.

WWW-Scraper-ISBN-Pearson_Driver (0.23)

This module doesn't seem to function at all any more. It returned failure on every one of 27 ISBNs I tried.

Note to the other reviewer (maintainer): the module produced an error when given any ISBN whatsoever. It didn't say that they were not produced by Pearson Education. It didn't have anything to do with their being written by John Grisham. And since you're the maintainer, you know that. Rather disingenuous to fix a blocking bug like that, and then bash the person who points out that the module doesn't work. As for reporting the bug, the module was basically abandoned when I wrote the review.


WWW-Scraper-ISBN-LOC_Driver (0.26)

(Review deleted to save re-checking the module.)

Lingua-EN-Numbers (1.01) *****

This module converts between numbers written as words, as in "Twenty-two", and arabic numerals, as in "22". It seems to work satisfactorily.