Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Saturday September 28, 2002
08:56 PM

Finding Prerequisites

[ #8075 ]

A couple of weeks ago I released a bunch of Test:: modules. Somewhere after The Perl Conference I started to convert all of my tests to Test::More and along the way I found I needed a lot of other stuff too.

With such rapid releases I made plenty of mistakes, and the most egregious one, missing dependencies for PREREQ_PM, caused almost all of the new modules to FAIL CPAN Testers. I think one base module missed a dependency, and it went south from there.

Every time something like this happens, I write a some sort of test to detect it. In this case, I need to determine if all of the modules I use in the distribution show up in Makefile.PL.

I started fooling around with %INC, the special hash that keeps track of loaded modules. That hash, however, keeps track of all loaded modules. Not only does it have keys for the modules that I explicitly loaded, but all of the modules that they loaded too. I do not need to know about those as long as I trust that their distributions list all of their prerequisites.

While I was looking for something else on CPAN, I came across Module::Info which reports all of the modules that I explicitly load. It actually walks the script's op-tree which is much better than regular expressions.

Module::Info gets me almost all of the way, but I need to filter that list to remove the modules supplied by the distribution. Since Business::ISBN depends on Business::ISBN::Data but both come from the same distribution, my prerequisite reporter should not warn me that Business::ISBN depends on Business::ISBN::Data. Now the fun starts.

I probably could not do this with other languages, but Perl lets me muck with namespaces that do not belong to me. In this case, I want to execute Makefile.PL but make ExtUtils::MakeMaker do something different. I do not need another Makefile, but the keys in the PREREQ_PM anonymous hash. I simply redefine the WriteMakeFile function.

sub ExtUtils::MakeMaker::WriteMakefile
    {
    my %hash = @_;
 
    my $hash = $hash{PREREQ_PM};
 
    @prereqs   = sort keys %$hash;
    }

To see which modules are in the distribution, I use File::Find::Rule to look inside blib, the build library.

my @files =
    map {
        my $x = $_;
        $x =~ s|^$_[0]/?||;
        $x =~ s/\.pm$//;
        $x =~ s|/|::|g;
        $x;
        }
        File::Find::Rule->file()->name( '*.pm' )->in( 'blib/lib' );

Any other module that Module::Info finds and does not show up in PREREQ_PM or blib I need to put in PREREQ_PM before I release the distribution.

I combined all of this in Test::Prereq and I have been using it for about a month. I have not had that same annoying problem again, and when I add to my modules, sometimes using a new module, my test suite immediately finds and tells me to fix the problem. I do not have to remember to fix PREREQ_PM or which modules I need to add. Test::Prereq does both of those for me. :)