Apr 23, 2011

Every module has a test with Module::Pluggable

This is a sort of meta test, checking that every module under a chosen namespace has its own corresponding file test, following a naming convention .

I will spend few words on this, just showing you the code that works for me and can be adapted to your needs ... so lets talk more Perlish than English :^)

I used the core module Module::Pluggable to get all packages under, for instance, the PNI::Node namespace where there will be all my PNI "nodes" i.e. plugins implementing the PNI::Node interface (that has simply two abstract method init and task ) .

I choose the following naming convention :
the PNI::Node::Foo::Bar::My_node_name
has
the test _node-foo-bar-my_node_name.t

Here it is a PNI::Find package which holds a static method called nodes that returns a list containing all the packages under the PNI::Node namespace . PNI::Find is a singleton, but don't care about that by now, it is just a convenience to call PNI::Find->nodes from my meta test ( see below ) .
package PNI::Find;
use strict;
use warnings;
our $VERSION = '0.12';
use Module::Pluggable search_path => 'PNI::Node', require => 1, inner => 0;

# singleton
my $self;

sub new {
    if ( not defined $self ) {
        $self = bless \__PACKAGE__, __PACKAGE__;
    }
    return $self;
}

sub nodes {

    my @nodes;
    for my $module ( $self->plugins ) {
        if ( $module->isa('PNI::Node') ) {
            push @nodes, $module;
        }
    }
    return @nodes;
}

1;


The following test script, called every_node_has_a_test.t, checks that under the t directory there is a test file for every node ( or plugin in your case ) .

use strict;
use Test::More;
use File::Spec;
use PNI::Find;

if ( not $ENV{TEST_AUTHOR} ) {
    my $msg = 'Author test.  Set $ENV{TEST_AUTHOR} to a true value to run.';
    plan( skip_all => $msg );
}

my $find = PNI::Find->new;

my @core_nodes_dirs;
my $node_dir_path = File::Spec->catfile(qw(lib PNI Node));
opendir my ($node_dir_handle), $node_dir_path;
for my $entry ( readdir $node_dir_handle ) {

    # looking or dirs starting  with an uppercase letter
    next unless -d File::Spec->catfile( $node_dir_path, $entry );
    next unless $entry =~ /^[A-Z][a-z]+/;

    push @core_nodes_dirs, $entry;
}

my $core_nodes_dirs_regexp = join '|', @core_nodes_dirs;

for my $node_class ( $find->nodes ) {

    # skip check on nodes not included in PNI
    next if $node_class !~ /^PNI::Node::($core_nodes_dirs_regexp)/;

    # naming convention for test of PNI::Node::Foo::Bar is _node-foo-bar.t
    my $node_test = $node_class;
    $node_test =~ s/^PNI:://;
    $node_test =~ s/::/-/g;
    $node_test = lc "_$node_test.t";
    my $test_path = File::Spec->catfile( 't', $node_test );
    ok -e $test_path, "$node_class has a test";
}

done_testing;

Conclusion

Test driven development is a must, that's why I think it is necessary to check that there is at least a test for every module specially if you can't know a priori how much will be populated a namespace, for example if you decide to have plugins .

Next step would be to code some helper to create your modules ... mmhh I'm going to open some good CPAN module like Mojolicious and steal some code :-)

Apr 2, 2011

Compile a Vanilla Perl on Windows with MinGW


Compiling Perl on Unix is really straight forward, but on Windows you need to pay some extra effort.

Read the procedure below if you want to build a default (a.k.a. Vanilla) Perl distribution with no pain.

All the informations you need can be found on the Internet but if you just don't want to waste your time around, this is the right place.

Here we go !
  1. Create a folder C:\MinGW
  2. download mingw-get from www.mingw.org and uncompress it under C:\MinGW
  3. Create a folder C:\Perl
  4. download latest Perl source and uncompress it under C:\Perl, for instance I got the folder C:\Perl\perl-5.12.3
  5. Download dmake from here, uncompress it and put the dmake.exe and the "startup" directory under C:\MinGW\bin
  6. Open a cmd prompt and type
set PATH=C:\MinGW\bin;%PATH%
cd C:\MinGW\bin
mingw-get install gcc g++
cd C:\Perl\perl-5.12.3\win32
dmake
dmake test
dmake install
The dmake and dmake test commands will take some time, depending on your pc perfomances.
Now you can remove the folder containing Perl sources, i.e. C:\Perl\perl-5.12.3 and ...
That's all !
For those who want to customize start with the
C:\Perl\perl-5.12.3\win32\makefile.mk
file where you can choose, for example, the destination directories for your installation which can be different from C:\MinGW and C:\Perl, but, should not contain spaces.
Don't forget to add
C:\MinGW\bin;C:\Perl\bin
to your PATH environment variable in order to use your Perl distribution without problems.