Use a Task distribution to specify groups of modules

A Task distribution is like a normal Perl distribution in structure, but it doesn’t actually provide any code. It lists as pre-requisites all of the modules or distributions that you want to install so you can use a conventiional CPAN tool to install all of the dependencies. A Task is slightly different from the older way, a Bundle, but for most people and uses, a Task might be a better way.

You can create your Task::* distribution with your favorite module tool (see Item 80. Don’t start distributions by hand). Once you have the basic structure, you edit the module file to document what your task does and you edit the build file to list the dependencies.

Suppose that you wanted to make one to install all of the modules mentioned in Effective Perl Programming (and we have in Task::EffectivePerlProgramming).

To do this yourself, you first create the stub distribution:

$ module-starter --module=Task::EffectivePerlProgramming
Class is Module::Starter
Created Task-EffectivePerlProgramming
Created Task-EffectivePerlProgramming/lib/Task
Created Task-EffectivePerlProgramming/lib/Task/EffectivePerlProgramming.pm
Created Task-EffectivePerlProgramming/t
Created Task-EffectivePerlProgramming/t/pod-coverage.t
Created Task-EffectivePerlProgramming/t/pod.t
Created Task-EffectivePerlProgramming/t/manifest.t
Created Task-EffectivePerlProgramming/t/boilerplate.t
Created Task-EffectivePerlProgramming/t/00-load.t
Created Task-EffectivePerlProgramming/ignore.txt
Created Task-EffectivePerlProgramming/Changes
Created Task-EffectivePerlProgramming/Build.PL
Created Task-EffectivePerlProgramming/README
Created Task-EffectivePerlProgramming/MANIFEST
Created starter directories and files

Next, you edit the .pm file to document your Task::* and to set a version number (the date is a good choice). Since this is a distribution like any other Perl distribution, when you install the Task, not only will the CPAN tool handle the dependencies, but it will also install the Task::* module, in this case Task::EffectivePerlProgramming. By adding a version to your distribution, you can update it later and use your CPAN tool to update your dependencies.

Here’s an extract of lib/Task/EffectivePerlProgramming.pm file:

package Task::EffectivePerlProgramming;

our $VERSION = '20100714';

=head1 NAME

Task::EffectivePerlProgramming - All of the modules mentioned in Effective Perl Programming, 2nd Edition

=head1 SYNOPSIS

This is just a Task module to install dependencies. There's no code to use
or run.

=head1 DESCRIPTION

These are the modules we used in the book:

=over 4

=item * Apache::DBI

=item * Apache::Perldoc

=item * etc, etc

=back

=head1 LICENSE AND COPYRIGHT

Copyright 2010 brian d foy.

You can distribute this module under the same terms as Perl itself.

=cut

1; 

In the Build.PL, you then list each of the modules that you want to install as a dependency. If you don’t care which version of the dependency you want to install, you can use '0' as the version since any version should be equal to or greater than that:

use strict;
use warnings;
use Module::Build;

my $builder = Module::Build->new(
    module_name         => 'Task::EffectivePerlProgramming',
    license             => 'perl',
    dist_author         => q{brian d foy },
    dist_version_from   => 'lib/Task/EffectivePerlProgramming.pm',
    requires            => {
		'Apache::DBI'     => '0',
		'Apache::Perldoc' => '0',
		'App::Ack'        => '0',
		# etc, etc,
		},
    build_requires => {
        'Test::More' => 0,
    	},
    add_to_cleanup     => [ 'Task-EffectivePerlProgramming-*' ],
    create_makefile_pl => 'traditional',
	);

$builder->create_build_script();

That’s it; you’re done! Well, don’t forget to run the tests to check your Pod for proper formatting. Once you’re ready, you can create your distribution:

$ perl Build.PL
$ ./Build test
...
$ ./Build dist
Creating Makefile.PL
Deleting META.yml
Creating META.yml
Creating Task-EffectivePerlProgramming-20100714
Creating Task-EffectivePerlProgramming-20100714.tar.gz
Deleting Task-EffectivePerlProgramming-20100714

You can upload your distribution to CPAN, put it in your private module repository, email it to your coworkers, or pass it around however you like.
If it’s on CPAN, you can install it as you would any other module:

$ cpan Task::EffectivePerlProgramming

Installing the task from a local file

You don’t have to upload your Task distribution to CPAN to use it. You can install the prerequisites of a distribution as long as you have that distribution. You could

In the cpan command-line tool, you can install the current directory (just the dot), including its dependencies:

$ cd Task-EffectivePerlProgramming
$ cpan .

The cpanminus command-line tool can install just the dependencies without installing the module inself (but that’s not necessarily a good thing):

$ cd Task-EffectivePerlProgramming
$ cpanm --installdeps .

Since this Task used Module::Build, you can use the installdeps build target, although you have an extra step now:

$ cd Task-EffectivePerlProgramming
$ perl Build.PL
$ Build installdeps

Bundles are still good

Task distributions take the place of CPAN.pm’s auto-bundles, mostly, but miss a key feature of Bundles, which can install modules given a local file path instead of just a repository path.

You can generate an autobundle with CPAN.pm. The output lists the currently installed versions, the latest version in CPAN, and the relative path in CPAN-like archive. At the end, it writes the actual auto-bundle file:

$ cpan -a 
...
Net::POP3                      2.29      2.29  GBARR/libnet-1.22.tar.gz
Net::SMTP                      2.31      2.31  GBARR/libnet-1.22.tar.gz
Net::SSL                       2.84      2.85  NANIS/Crypt-SSLeay-0.58.tar.gz
...
warnings                       1.06      1.11  JESSE/perl-5.13.9.tar.gz
warnings::register             1.01      1.02  JESSE/perl-5.13.9.tar.gz

Wrote bundle file
    /Users/Buster/.cpan/Bundle/Snapshot_2011_08_16_00.pm

The bundle file has some metadata and a list of packages and versions:

package Bundle::Snapshot_2011_08_16_00;

$VERSION = '0.01';

1;

__END__

=head1 NAME

Bundle::Snapshot_2011_08_16_00 - Snapshot of installation on Buster on Tue Aug 16 15:05:40 2011

=head1 SYNOPSIS

perl -MCPAN -e 'install Bundle::Snapshot_2011_08_16_00'

=head1 CONTENTS

Algorithm::Diff 1.1902

Apache::DBI 1.08

Apache::Perldoc 1.11

Apache::Test 1.31

App::Cache 0.36

App::Cmd 0.301

App::Module::Lister 0.13

App::cpanminus 1.0004

AppConfig 1.66

This auto-bundle is a list of everything you have installed, but it doesn’t have to be. You can list any packages and versions that you like. It’s completely up to you to decide what should be part of the task.

Putting this anywhere in your @INC (such as the current working directory) allows you to use the cpan tool to install it:


$ cd /Users/Buster/.cpan
$ cpan Bundle::Snapshot_2011_08_16_00

CPAN.pm handles Bundles specially to handle this.

Since the auto-bundle is a single file (although in a directory named Bundle), it might be easier for you to pass around. Either way, you have a way to tell people everything that should install.

Some interesting Tasks

Some Task distributions cover big topics, such as:

There are several Task::BeLike:: distributions that list people’s favorite tools and modules. If you want to do the same sorts of things as these people, you might want to install their BeLike distributions:

Things to remember

  • Collect project dependencies in a Task distribution
  • Install the Task distribution like any other module distribution, or directly from the local directory
  • Several tasks already exist on CPAN.