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