The hard way to install modules is to download them off of CPAN with
your web browser, uncompress them, run the Makefile.PL
(and do the
same for any prerequisite modules that script complains about that are
missing) then run the make file to build the module, then make test
to test it and finally run make install to install the module.
While that works, I'm not a big fan of going to going to such lengths needlessly. Especially when I can just use the CPAN shell to install a module (including all the modules that that module needs itself to function) with one command.
Having lauded CPAN, there's a new installation tool on the block. CPANPLUS.
So what's the difference? Well, to be honest, from a user point of view, not much - well, nothing significant anyhow. The real difference is in the backend. You see, CPANPLUS was designed from the outset to be used programatically instead of just interactively. This means you can write scripts to do automatic module installation for you easily. Indeed, yesterday's module Acme::Intraweb was written using CPANPLUS. But more than that, you can apply intelligence to querying CPAN for you - for the first time you as a user can turn the power of Perl on the Centralised Peal Archive Network itself.
Once you've installed CPANPLUS and configured it (it'll ask you lots of questions so it knows where it can download modules from) you can then run the shell.
[root@gan] cpanp CPANPLUS::Shell::Default -- CPAN exploration and modules installation (v0.03) *** Please report bugs to <cpanplus-bugs@lists.sourceforge.net>. *** Using CPANPLUS::Backend v0.040. *** ReadLine support available (try 'i Term::ReadLine::Perl').
CPAN Terminal> install Acme::ManekiNeko
The syntax is a little different to CPAN.pm, and it's got a few good extra features. For example, it's able to interact with the CPAN Testers system allowing you to report if installations were successful on your system and query the existing database of other user's attempts to install the module.
Now, how about using it programatically? Let's write a simple script to get a list of modules that are currently installed on my system.
#!/usr/bin/perl
# turn on Perl's safety features use strict; use warnings;
# create a new CPANPLUS object use CPANPLUS::Backend; my $backend = CPANPLUS::Backend->new();
# get work out what's installed my $installed_rv = $backend->installed();
# check we got that data back okay unless ($installed_rv->ok()) { die "Can't get list of installed modules"; }
# get just names of the installed modules # (the ->rv returns a hash of module names / locations) my @installed = keys %{ $installed_rv->rv() };
The $backend->installed
returns a CPANPLUS::Backend::RV
object. These 'Result Values' are used thoughtout the
CPANPLUS::Backend api to represent the results of a query. They can
be integrated to see if a query was successful or not (we can check it
with the ok
method.) They also hold the results for that query and
provide us a way of getting the data back again (with the rv
method.) Dependant on the type of query we did the result value may
also support many other methods. In this case we simply get the
results back which is a hashref of the locations of the modules that
are installed keyed by their name. We then took the keys of this hash
(the module names) and placed them in a list, as that's all we're
really interested in at the moment - a list of the names of the
modules installed on the system.
So, what can we use this list of modules for? Well, I find that if I've installed a module then it's often worth looking at the other modules that that person has written to see if they're useful too. So, let's write a script to find out who wrote each of the modules we have installed already, and who's written the most.
Before we get ahead of ourselves, we first need to get the module
object for each of the modules that we have rather than just the name
of the modules. CPANPLUS::Backend has the module_tree
method
that we can ask for hashref that contains a module object for each
module that's ever been uploaded to the CPAN keyed by name. We want
to produce a similar hash, but just with the objects that represent
the modules we've installed in it.
# get the module tree my $tree = $backend->module_tree();
# get the object for each of the installed modules # i.e. build a module tree for just the installed modules my %installed_module_objs; foreach my $module (@installed) { # get the object from the tree for that module $installed_module_objs{ $module } = $tree->{ $module }; }
Now what we need to do is work our way though that hash and count how many modules each author did.
# run over our installed modules tree and count how many # times each author's name comes up my %authors; foreach my $module (keys %installed_module_objs) { $authors{ $installed_module_objs{ $module }->author }++; }
Note that this %authors
hash contains the number of modules, not
the number of distributions, each author uploaded to CPAN. People
like ABW are going to have a large number of modules since just
installing something like the Template Toolkit will install seventy or
so little modules. Still, understanding the limitations of this, we
still sort the modules:
# create a sorted list of authors, my @sorted = sort {
# those with the largest number of modules first $authors{ $b } <=> $authors{ $a }
# and for those with the same number of modules # then sorted alphabetically or $a cmp $b
} keys %authors;
And finally we can create a little HTML page that lists all those modules.
# and finally print that out
# open the file use IO::File; my $fh = IO::File->new("authors.html",">") or die "Can't open 'authors.html': $!";
# module to encode strings for html use HTML::Entities;
print {$fh} q{ <html> <head><title>module count</title> <body> <table border="1"> <tr><th>Author</th><th>Number of Modules</th></tr> };
# print out the authors and their rank; foreach my $author (@sorted) { print {$fh} "<tr><td>". encode_entities($author). "</td><td>$authors{$author}</td></tr>\n"; }
print {$fh} q{ </table> </body> </html> }
Which should produce something that looks like