Sep 10, 2011

Mo Moo Moose not really stuttering



M ... Mo ... Moo ... Moose 

(if I were stuttering while I'm typing it would really bad for my brain :) 

is the way everybody should use OO in Perl.

Start from Mo!

Create a class.

package Point2d;
use Mo qw(default);
has x => ( default => sub { 0 } ); 
has y => ( default => sub { 0 } );

Extend it.

package Point3d;
use Mo qw(default);
extends 'Point2d';
has z => ( default => sub { 0 } );

Then somewhere else ...

use Point3d;
my $point = Point3d->new;

And everything is ok ... then, your code grows, you need more features ... just add an o to Mo

and you get a lot of cool stuff from Moo or copy the use string and past it after Mo to use Mouse.

Want much more features? Want introspection? Want antlers? Then switch to Moose.

Jun 21, 2011

How to use Devel::Cover

It's time to deploy another version of my CPAN module. I have 57 files and 698 tests: the question is

Are my tests "quite" good? Did they cover all possible cases?

Mmh, it's a difficult question, the answer depends on a lot of things ... here comes Devel::Cover to the rescue.

So we have this magic module that gives us some statistics to evaluate where are the gaps in our tests.

Yes, I know, it is still a difficult question, but at least Devel::Cover gives us some answers, for sure it is a good starting point.

Consider I am on Windows, so I have "set" instead of "export" and dmake instead of make.
 If it is not the first time you run it, launch a

C:\SVN_ROOT\PNI>cover -delete
Deleting database C:\SVN_ROOT\PNI\cover_db

Just set the environment variable HARNESS_PERL_SWITCHES=-MDevel::Cover and run your tests.
For example

C:\SVN_ROOT\PNI>set HARNESS_PERL_SWITCHES=-MDevel::Cover
C:\SVN_ROOT\PNI>prove -l

Here it is the cool part !

C:\SVN_ROOT\PNI>cover
Reading database from C:\SVN_ROOT\PNI\cover_db
...

Writing HTML output to C:\SVN_ROOT\PNI\cover_db/coverage.html ...
done.

This will produce a coverage.html file in the cover_db directory.

Noooooo, my _node-perlfunc-int.t has a red entry with a 50% ... mmh maybe because the test file is almost empty, it just checks default values.


If I click on that ugly 50.0, I can see this.


I'm going to add some tests, checking some results and for example passing wrong parameters. This is the result:

C:\SVN_ROOT\PNI>prove -l t\_node-perlfunc-int.t
t\_node-perlfunc-int.t .. 1/? Devel::Cover: Deleting old coverage for changed file t/_node-perlfunc-int.t
t\_node-perlfunc-int.t .. ok
All tests successful.
Files=1, Tests=9,  2 wallclock secs ( 0.06 usr +  0.01 sys =  0.08 CPU)
Result: PASS

et voilĂ 



Conclusion

Devel::Cover is a really powerful tool ... just use it !

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.

Mar 25, 2011

Source code generation with Template Toolkit

Source code generation is very powerful and saved me from wasting hours and hours to change a recurrent string in my code.

It is not always the best solution, there is also inheritance, but, in my case I have an abstract class, called PNI::Node, that will be the model for 90% of my modules. By now I have no more than 50 PNI nodes, but there will be more and more nodes and I can't open every .pm file to change, for example, a licence in the pod section.

This is a very simple implementation, for sure you can find a better way to do what you need : ok, let's go on!

For instance, I'm writing a CPAN dist called PNI, using ExtUtils::MakeMaker .

My template processing system is the Template Toolkit that is really great and has a lot of feature.

I just used the most common ones with this naming convention:

    path/to/my/file.ext.tt2 is the template for path/to/my/file.ext

so there can be a path/to/some/other/template.tt2 that don't have an associated output file and can be used in some INCLUDE, PROCESS or WRAPPER directive, and I still can have a path/to/other/file.ext that will not be processed .

All paths are relative to my CPAN dist dir, for example, lib/PNI/Node.pm.tt2 is the template for lib/PNI/Node.pm . I created a script called process_templates in my CPAN dist dir and must be launched from there . Since I'm writing Perl code, the script uses Perl::Tidy to indent modules and tests .

Don't forget to add a MANIFEST.SKIP file containg the following lines

^process_templates$
\.tt2$

so when you will make your dist you will not include all that stuff .

Here is the code for the script, I included it just as an example ...

it just works (for me :-) !

use strict;
use warnings;
use File::Find;
use Template;
use Perl::Tidy;

my $template_config = {
    STRICT => 1,
    DEBUG => 1,
    TRIM => 1
};

my $template = Template->new($template_config);

sub find_templates {
    my @dirs = @_;
    my @template_files;
    find(
        {
            wanted => sub {
                return unless /\.tt2$/;
                push @template_files, $File::Find::name;
              }
        },
        @dirs
    );
    return @template_files;
}

for my $template_path ( find_templates(qw(lib t)) ) {

    print $template_path , "\n";

    open my ($in), '<', $template_path;
    my @template_content_rows = <$in>;
    chomp @template_content_rows;
    my $template_content = join "\n", @template_content_rows;

    # naming convention: /path/to/my/file.ext.tt2
    # is template file for /path/to/my/file.ext

    my $output_path = $template_path;
    $output_path =~ s/\.tt2$//;

    if ( -e $output_path ) {

        print $output_path, "\n";
        my $output_content = '';    # cannot reference undef
        # process templates
        $template->process(
            \$template_content, {}, \$output_content,
            { binmode => 1 }
          )
          or warn $template->error
          # but if there is an error don't commit changes
          and next;

        # clean ^M chars ... i'm on Windows
        my $m_char = chr(13);
        $output_content =~ s/$m_char//g;
        # if it is a module or a test, tidy it
        if ( $output_path =~ /\.(pm|t)/ ) {
            my $output_content_tidy = '';
            perltidy(
                source => \$output_content,
                destination => \$output_content_tidy,
                argv => []
            );

            # replace content with its tidy version
            $output_content = $output_content_tidy;
        }

        open my ($out), '>', $output_path;
        print $out $output_content;
        close $out;
    }
    close $in;
}

Conclusion

It is just a starting point, and I know I'm reinventing the wheel for sure . There are a lot of Perl-men that use something like this, even more sophisticated .

I had to thank milan.pm leader Marcos Rebelo,
obrigado !
who shared with me his solution ( which also uses JSON to store metadata ) .

Mar 19, 2011

Deploy a Perl application on Windows

Suppose you have a Perl application for an end user but

  • probably your user don't know Perl exists
  • your user uses Windows
  • your user want just to click on a .exe to launch your program

What you will read it worked for me, feel free to improve it, adapt it to fit your needs and/or automate it as you like.
The only requirement needed is Strawberry Perl
Let's define some names so I can explain with my example how to deploy your Perl program on Windows: my program is called pni.exe, has a red mushroom icon,



and it is based on a CPAN module I wrote, called PNI::GUI::Tk.

PNI stands for Perl Node Interface, and PNI::GUI::Tk is a Tk based GUI for PNI with a pniguitk.pl script to launch it. It is really similar to a so called App, except that it is not under the App:: namespace.

Prepare to build you Perl app

First of all, get a Windows machine, ( this is the most difficult part for a lot of people that is allergic to Microsoft :-) then install the Strawberry Perl distribution, it is a really good way to feel unix-like on Windows.

Now, type
cpan PNI::GUI::Tk
to install the module and its dependencies that are Tk, PNI::Node::Tk and the PNI core module.

Now create a folder, called for instance PerlNodeInterface-windows-0.11, put the pniguitk.pl script inside, a README.txt file to be kind ( don't forget the .txt extension, since you are on Windows ) and a lib folder containing all dependencies. This is how it looks like, see below how to compile pni.exe.


There is a pniguitk.pl which launches the app:

#! env perl
use strict;
use warnings;
use PNI::GUI::Tk::App;
my $app = PNI::GUI::Tk::App->new;
$app->run;

Don't forget the auto folder for Tk since it is an XS module.

The dir tree it looks something like this:
lib
lib\auto\Tk\*
lib\PNI.pm
lib\PNI\*
lib\Tk.pm
lib\Tk\*
pni.exe
pniguitk.pl
README.txt

Everything was there, from the beginning

Yes, but you know, most of the people in the world never typed
perldoc ExtUtils::Embed
I started from there, and I found all the informations to compile pni.exe ... so here we go!
perl -MExtUtils::Embed -e xsinit
will produce perlxsi.c, rename it pni.c and add a main function, like the interp.c from
perldoc perlembed
Then change the arguments in the main function and hardcode a -Ilib and the name of the script .

Something like this :

//argv[0] stores the relative path of the executable
argv[1] = "-Ilib";
//argv[2] is for programfile
argv[2] = "pniguitk.pl";

 Get a cool mushroom icon :-) and create a text file pni.rc containing this line
ID ICON "pni.ico"
then launch
windres pni.rc -o coff -o pnirc.o
Now you can compile pni.exe with gcc using options
-Wall -mwindows -o pni pnirc.o pni.c
and options coming from the output of
perl -MExtUtils::Embed -e ccopts
and
perl -MExtUtils::Embed -e ldopts

You can automate compilation with few lines of code:

use ExtUtils::Embed;
use PNI;
print "\nBuilding PNI $PNI::VERSION\n";
my $gcc_cmd = join( ' ' , 'gcc -Wall -mwindows -o pni pnirc.o pni.c' , &ccopts , &ldopts );
print STDOUT $gcc_cmd , "\n";
system( $gcc_cmd );

Conclusion

Finally zip your folder, since zip is supported natively on Windows, and you will get a PerlNodeInterface-windows-0.11.zip ready for an user-friendly deploy.
If this procedure works and make sense for most of the perlish folks, Trawberry Perl could become a sort of JRE for Perl on Windows.
There are a lot of users out there that need our Perl programs, but they don' t need all the complexities behind.

Feb 5, 2011

Using Google Docs to draw UML Class Diagram

Yep! Perl Node Interface (a.k.a. PNI) version 0.1 was released on CPAN. I restarted writing it from scratch again to clean up, design my API and add the holy unit tests.

I was googling looking for google docs uml shapes, cause it would be really usefull - I mean for a small project like PNI - to have an uml class diagram published as a shared google document.

Of course, this is not a professional solution, but I realized that everything I need to draw a naive uml class diagram in google docs was there ...

so

check out my PNI Class Diagram,

and

feel free to use this basic model:  UML Class Diagram Template.