Perl_Part7

6
In Perl parlance a ‘package’ is a way of specifying a namespace, before we examine the syntax of a package let’s look at what a namespace is and the benefits they can provide. A rose by any other name In essence a namespace is used to isolate variables and functions into separate “compartments” to help avoid name- space pollution and collision. Within a program all of the functions and variables (including filehandles) are from the ‘main’ package, to determine which package the currently executing code is in Perl provides the ‘__PACKAGE__’ constant: print "Current package is: '"; print __PACKAGE__, "'\n"; The ‘__PACKAGE__’ constant cannot be placed within a double quoted string and still be interpolated, by including it in double quotes the literal value is returned instead. Creating a new package by using the ‘package’ function with the name of the package you wish to create (Listing 1). A package’s scope is terminated by the end of the file, exiting the block the package was declared in or declaring another package afterward, as shown in Listing 2. Using a namespace we can reuse variable names in each package using the ‘our’ key- word to declare the variables to exist with a specific value within a package (Listing 3). This code will compile and run but give warnings. Modules – Scratching Itches Now you have been introduced to how packages work you may be wishing you had stopped reading at the copy and paste coding section. Now that you have seen the cost of code re-use the right way we can introduce you to the benefits, namely building modules. A module is quite simply a package placed in a separate file, where the file name is the same as the package name with a ‘.pm’ suffix so that Perl readily recognizes the file as a “Perl Module”. The code below is from a file called Toaster.pm: #this should be placed in #a file called Toaster.pm package Toaster; our $VERSION = 1.00; my $num_slots = 2; my $toasting_time = 10; sub roast_toast { sleep $toasting_time; print "Toast is done\n"; return 0; } 1; The first line of a module IS ALWAYS the package declaration, ensure the case of the name matches the file-name. The 62 Dec 02 / Jan 03 www.linux-magazine.com O nce your code begins to grow beyond a small script and into large applications you will often need to re-use small snippets, functions or even collections of functions that you have written in new applications. There are two main ways you can set about this re-use: copy and paste code abstraction Unlike most choices in Perl there is only one sensible way to do it. Copy and pasting code may seem like a quick and easy way to reproduce the functionality you need but it has a number of drawbacks that far out-weigh any temporary time-savings. The greatest of these issues is bug- fixing, if you find a bug (and it WILL happen) in a piece of code you have manually copied and pasted into multiple files then you will have to track down each and every occurrence of the code (Potentially even in files on different machines so a simple find and replace will not make the task any less arduous for you) and make the change numerous times. You will also find that you frequently make small incremental adjustments to the code to make it fit better to the task, so any enhancements will have to be copied too. If just one instance of the code is overlooked, then there are different solutions to the same problem. Fixing a bug in this manner will cost you far more than any time you saved by adopting this approach. Are you sure you fixed that bug everywhere? Now that we have covered the worst way of implementing code re-use let’s explain the principles behind the preferred methods, packages and modules. The commonly adopted approach to code reuse is to write functions and put them into a file in an accessible location. The functions within a file should be logically grouped together by purpose. Functions whose tasks have a similar theme are usually placed in the same file. To fit in with the festive season this month we are going to look at presents, well packages to be exact but you can still think of them as little bundles of coding joy. BY DEAN WILSON AND FRANK BOOTH Thinking In Line Noise Pre-wrapped Packages Perl Tutorial: Part 7 PROGRAMMING #in the default package print "Current package is '", __PACKAGE__, "'\n"; package Huey; print "In package ", __PACKAGE__, "'\n"; package Louey; print "In package ", __PACKAGE__, "'\n"; package Dewey; print "In package ", __PACKAGE__, "'\n"; package main; print "In package ", __PACKAGE__, "'\n"; Listing 1: __PACKAGE__

Transcript of Perl_Part7

Page 1: Perl_Part7

In Perl parlance a ‘package’ is a way ofspecifying a namespace, before weexamine the syntax of a package let’slook at what a namespace is and thebenefits they can provide.

A rose by any other nameIn essence a namespace is used to isolatevariables and functions into separate“compartments” to help avoid name-space pollution and collision.

Within a program all of the functionsand variables (including filehandles) arefrom the ‘main’ package, to determinewhich package the currently executingcode is in Perl provides the‘__PACKAGE__’ constant:

print "Current package is: '";print __PACKAGE__, "'\n";

The ‘__PACKAGE__’ constant cannot beplaced within a double quoted string andstill be interpolated, by including it indouble quotes the literal value isreturned instead.

Creating a new package by using the‘package’ function with the name of thepackage you wish to create (Listing 1). Apackage’s scope is terminated by the endof the file, exiting the block the packagewas declared in or declaring anotherpackage afterward, asshown in Listing 2.

Using a namespacewe can reuse variablenames in each packageusing the ‘our’ key-word to declare thevariables to exist witha specific value withina package (Listing 3).

This code willcompile and run butgive warnings.

Modules – Scratching ItchesNow you have been introduced to howpackages work you may be wishing youhad stopped reading at the copy andpaste coding section. Now that you haveseen the cost of code re-use the right waywe can introduce you to the benefits,namely building modules.

A module is quite simply a packageplaced in a separate file, where the filename is the same as the package namewith a ‘.pm’ suffix so that Perl readilyrecognizes the file as a “Perl Module”.

The code below is from a file calledToaster.pm:

#this should be placed in#a file called Toaster.pmpackage Toaster;our $VERSION = 1.00;my $num_slots = 2;my $toasting_time = 10;sub roast_toast {

sleep $toasting_time;print "Toast is done\n";return 0;

}1;

The first line of a module IS ALWAYS thepackage declaration, ensure the case ofthe name matches the file-name. The

62 Dec 02 / Jan 03 www.linux-magazine.com

Once your code begins to growbeyond a small script and intolarge applications you will often

need to re-use small snippets, functionsor even collections of functions that youhave written in new applications. Thereare two main ways you can set aboutthis re-use:• copy and paste• code abstractionUnlike most choices in Perl there is onlyone sensible way to do it.

Copy and pasting code may seem likea quick and easy way to reproduce thefunctionality you need but it has anumber of drawbacks that far out-weighany temporary time-savings.

The greatest of these issues is bug-fixing, if you find a bug (and it WILLhappen) in a piece of code you havemanually copied and pasted intomultiple files then you will have to trackdown each and every occurrence of thecode (Potentially even in files ondifferent machines so a simple find andreplace will not make the task any lessarduous for you) and make the changenumerous times.

You will also find that you frequentlymake small incremental adjustments to the code to make it fit better to thetask, so any enhancements will have to be copied too. If just one instance of the code is overlooked, then there aredifferent solutions to the same problem.Fixing a bug in this manner will cost youfar more than any time you saved byadopting this approach. Are you sureyou fixed that bug everywhere?

Now that we have covered the worstway of implementing code re-use let’sexplain the principles behind thepreferred methods, packages andmodules. The commonly adoptedapproach to code reuse is to writefunctions and put them into a file in anaccessible location. The functions withina file should be logically groupedtogether by purpose. Functions whosetasks have a similar theme are usuallyplaced in the same file.

To fit in with the festive season this month we are going to look at presents,

well packages to be exact but you can still think of them as little bundles of

coding joy. BY DEAN WILSON AND FRANK BOOTH

Thinking In Line Noise

Pre-wrapped Packages

Perl Tutorial: Part 7PROGRAMMING

#in the default packageprint "Current package is '", __PACKAGE__, "'\n";package Huey;print "In package ", __PACKAGE__, "'\n";package Louey;print "In package ", __PACKAGE__, "'\n";package Dewey;print "In package ", __PACKAGE__, "'\n";package main;print "In package ", __PACKAGE__, "'\n";

Listing 1: __PACKAGE__

Page 2: Perl_Part7

module name should begin with anuppercase letter, as a rule only pragmasbegin with a lowercase letter.

In the Toaster module we declare twovariables and a function. If you’rewondering what the ‘1;‘ line at the endof the code block is there for (in a realmodule this would be at the end of thefile), it is required as all Perl modulesmust evaluate to ‘true’ when they’recompiled.

Although the value of the last evalu-ated expression in the module would bereturned this is not guaranteed to evalu-ate to ‘true’ as we can see by thefunction ‘roast_toast’ returning ‘0’ so forclarity and simplicity we explicitly return‘1’ to ensure a correct compile and load.

Loading the ToasterWe now need to actually load themodule into our perl program when werun the application so we can access thefunctionality it provides.

Perl tracks the modules it has availablefor use by storing a list of paths as a listwithin which it looks for ‘.pm’ files. Thislist is known as ‘@INC’ and is availablewithin perl itself for modification. Beforewe move on to showing you how to addyour own directories let’s show twopossible ways to display the defaultvalue of ‘@INC’.

The first way to do this is by allowingPerl itself to do the work and show uswhere it searches:

perl -V

You will then be shown a number ofdetails that describe many of the optionsthat this Perl interpreter was compiledwith. Underneath those details you willfind a section that resembles:

/usr/lib/perl5/5.6.0/i386-linux/usr/lib/perl5/5.6.0/usr/lib/perl5/site_perl/5.6.0/Ui386-linux/usr/lib/perl5/site_perl/5.6.0/usr/lib/perl5/site_perl

This information shows the defaultlocations that perl will search when youhave a ‘use’ statement in your code.

Two items of interest are that many of the site directories have the versionnumber contained within them allowing

many versions of Perl to live happily onthe same machine while still allowingeasy identification of which version themodules belong to.

The machine this was written on hasfive versions for backwards compatibilitytesting. The second item of interest isthat the current directory ‘.’ is includedby default.

The second way to show the searcheddirectories by using actual Perl code,from the command line you can issue:

perl U

-we 'print map {"$_\n" } @INC;'

To generate a list of the defaultdirectories that are printed to screen inthis format:

/usr/lib/perl5/5.6.0/i386-linux/usr/lib/perl5/5.6.0/usr/lib/perl5/site_perl/5.6.0/Ui386-linux/usr/lib/perl5/site_perl/5.6.0/usr/lib/perl5/site_perl

Recognize the directories it returns? Thisis the same information that the Perlinterpreter itself told us about but the listis available from within Perl itself.

Now we have provided a number of different techniquesto retrieve and displaythe current and defaultvalues of ‘@INC’ wewill move on and stepthough the list of waysto coerce Perl intolooking in additionallocations for additionalmodules including:• ‘-I’ command line

switch• Modifying @INC in

a BEGIN block• ‘use lib’ pragmaThe ‘-I’ method can be a very long-windedway of specifyingadditional directoriesand suffers from animportant drawback:You have to rememberto add it with everyinvocation of theprogram.

# nvoke 'buildscript with# build/directory added to @INCperl -I build/directory U

buildscript.pl

In the above example of ‘-I’ we add the‘build/directory/‘ to the ‘@INC’ list ofthe ‘buildscript.pl’ script. Where ‘-I’comes into its element is when used inquick prototyping of very small projects,however once your requirements grow tothe level where you need to specifymultiple additional include directoriesyou will begin to see the use of ‘-I’ as alimiting factor to how far your projectcan scale. We have not yet covered Perl’sspecial blocks such as BEGIN or END inthis article but it is worth mentioningthis technique at this stage as a refer-ence, although it is an oversimplificationat a basic level if you have a BEGINblock in your code then its contents willbe executed before anything else in theapplication is, including module loading.

# notice this should be executed# first as it is before the# BEGIN blockprint "Normal Hello\n";BEGIN {# this sections runs firstprint "I'm run first\n";

}

63www.linux-magazine.com Dec 02 / Jan 03

PROGRAMMINGPerl Tutorial: Part 7

#in the default packageprint "Current package is '", __PACKAGE__, "'\n";# Exiting the block the# package was declared in{package Larry;print "In package ", __PACKAGE__, "'\n";}# Back to main packageprint "In package ", __PACKAGE__, "'\n";# Closing a package by# declaring a new packagepackage Moe;print "In package ", __PACKAGE__, "'\n";# in this case the new# package is main again.package main;print "In package ", __PACKAGE__, "'\n";# Package terminated by# end of file.package Curly;print "In package ", __PACKAGE__, "'\n";

Listing 2: Exiting the block

Page 3: Perl_Part7

BEGIN block is insidethe Perl application itis possible to use Perlfunctions to alter thevalues in ‘@INC’ andso dynamically build-ing a list of directoriesis made simple withvery little additionalcode or complexityrequired.

The last of the morecommon approachesis using a pragmaknown as ‘use lib’ tospecify the desiredadditions. Using thismethod is actually one of the simplerways of specifying new paths, it’s as sim-ple as adding a call to the pragma at thetop of your program:

# !/usr/bin/perl -wuse strict;use lib("/home/dwilson", U

"/home/wanttogo");use CustomModule;print "In main body\n";print "=" x 25, "\n";print join("\n", @INC);

When this code snippet is run the twoadditional directories are added to‘@INC’ and then made available to therest of the program. If you ‘use’ moduleslike this then you should always specifythe name of the module in a ‘use’ state-ment AFTER the ‘use lib’ otherwise youwill get run-time errors, as shown inListing 4.

Although we did not define our ownBEGIN block in this code the moduleloading is still done at this phase and theerror is caught before we go on any fur-ther. The ease of use provided by ‘uselib’ is significant and has a very lowlearning curve that allows it to be usedin most of the cases where you wouldwant to add additional paths, once youfind yourself needing more flexibility

than this you will often have to resortback to using BEGIN blocks with all thepower they provide, albeit at the cost ofgreater complexity.

Invoking the mighty toasterAfter wading through the coverage ofhow to create your own packaged name-space and then reading the detailssurrounding the loading of modules youare probably getting the itch to test yournew found knowledge with someconcrete code examples.

The examples throughout the rest of this section assume that you have the “Toaster” module in one of thelocations specified in ‘@INC’ so if you have skipped past the previous text you are going to be unable toprogress until you have gone back andread it all.

You can test that you can access“Toaster” correctly by running:

perl -MToaster -e 'print U

$Toaster::VERSION, "\n";'

This should return ‘1’, if you see “Can’tlocate Toaster.pm in @INC” then themodule is not in the ‘@INC’ path andyou need to amend your configuration asper the instructions given above ( in the“Loading the Toaster” section ) before

64 Dec 02 / Jan 03 www.linux-magazine.com

As you would expect, it has acorresponding END block. The codecontained within the block is ALWAYSrun just before the program finishes itsown execution.

print "running happily in ";print __PACKAGE__, "\n";END {print "exiting at ";print scalar localtime();print "\n";'

}

Although we will delay the detailed lookat the full range of functionality thesetwo block types provide the more com-mon uses of these blocks make senseeven without knowing all their intimatedetails, END blocks are ideal places toput clean up or summary code andBEGIN blocks are a perfect place to alter‘@INC’ as shown below:

# !/usr/bin/perl -wuse warnings;use strict;# this is our moduleuse CustomModule;BEGIN {# this will be executed before# the rest of the codeunshift(@INC, "/home/dwilson");}print "In main body\n";print "=" x 25, "\n";print join("\n", @INC);

We use the BEGIN block to place anotherdirectory at the start of the ‘@INC’ array( array index zero ) pushing the otherdirectories one position back. We do thisso that our additional directory is thefirst one that is checked for the module.

The execution then moves back to thetop of the file and begins running thecode in its usual order and includes the“CustomModule” before moving on tothe print statements. If you run this codeyou will get a list of the directories in‘@INC’ including our additional one, thechange we made is still effective.

Adding additional paths like this viathe BEGIN block is a common practicewhen you either have a large number ofcustom paths you wish to have includedor when you want to actually doconditional inclusion of modules. As the

Perl Tutorial: Part 7PROGRAMMING

Can't locate NotExist.pm in @INC (@INC contains: /home/dwilson/home/wanttogo /usr/lib/perl5/5.6.0/i386-linux /usr/lib/perl5/5.6.0/usr/lib/perl5/site_perl/5.6.0/i386-linux /usr/lib/perl5/site_perl/5.6.0/usr/lib/perl5/site_perl .) at module_error.pl line 5.BEGIN failed--compilation aborted at begin_module.pl line 5.

Listing 4: Runtime errors

use warnings;use strict;our $fred = 'blah';print "Current package is '", __PACKAGE__, "'\n";package Huey;print "In package ", __PACKAGE__, "'\n";our $fred;package Louey;print "In package ", __PACKAGE__, "'\n";our $fred;package Dewey;print "In package ", __PACKAGE__, "'\n";our $fred;

Listing 3: Reusing variable names

Page 4: Perl_Part7

you can run the code samples. If wewant to use the ‘roast_toast’ function atthe moment we need to qualify the callwith its full package name:

Toaster::roast_toast();

Although using the full package name asa prefix to all external calls may seemlike just an inconvenience at the momentonce you begin to use multiple moduleswith long names it will begin to have aneffect on the clarity of your code.Another important reason to avoid usingthis approach is with data access, orencapsulation as it is often known as.

At the moment we can reach in andchange the value of any variable that welike with no regard toward the internalstructure of the module, as an exampleof this if we look at the ‘$toasting_time’variable we can see that it is numericand is used internally in the module.Look at the consequences of making achange like this:

use Toaster;$Toaster::toasting_time = U

"Thirty Seconds";Toaster::roast_toast();

If we run without warnings with codelike this we will see strange behaviour asPerl converts ‘$toasting_time’ into anumber from a string when ‘roast_toast’uses it and the sleep time will becomeerratic.

Instead of this direct action we shoulduse the functions provided to manipulateany required variables, a practice calleddata encapsulation, that is one of thetenets of Object Orientated developmentand a good design decision even in pro-cedural code like ours.

By encapsulating data we protect our-selves from tying our code too tightlywith the module’s own functions, all wewant to do is ‘roast_toast’, we do notcare if the time taken changes, we simplywant the action to be performed, in arobust design the implementation shouldbe hidden to us.

We can address both of the aboveconcerns by using a feature of Perl’smodule system called ‘Exporter’. TheExporter module allows module writersto specify a list of the variables andfunctions that they wish to expose to the

calling application so that they areloaded into the current namespace. Inthe example below we add someadditional Exporter related code to showhow little is needed before we start tosee the benefits:

#revised Toaster moduleuse strict;use warnings;package Toaster;require Exporter;our @ISA = qw(Exporter);our @EXPORT = U

qw($num_slots roast_toast);our $VERSION = 1.50;my $num_slots = 2;my $toasting_time = 10;sub roast_toast {sleep $toasting_time;print "Toast is done\n";return 0;

}1;

The newly revised Toaster module ( withfree set of knives ) required just threenew lines included to take advantage ofthese benefits, before we detail thoselines here is a small sample script thatcan use the module:

use Toaster;roast_toast();

This is an extremely simple example ofhow all the explicit declarations can beremoved to cut down on the amount ofline noise in the code while retaining thefull functionality. If we try to change the‘$toasting_time’ with the first examplebelow it fails:

use Toaster;$toasting_time = 23;

The error we receive is “Global symbol‘$toasting_time’ requires explicitpackage name” due to no variable called‘$toasting_time’ being present in the‘main’ package and Toaster notexporting its own ‘$toasting_time’. Whilewe can still modify the variable the sameway we did in previous examples using afully qualified package name this iswillfully ignoring the module writer’swishes and becomes more a case ofcoder beware.

If the module author changes the waythe module is implemented ( which isallowed as long as the public functionsare left alone ) then your code couldbreak and you would have no recourse.There is probably a very good reasonwhy the module author did not exposethose variables and finding out whycould be painful.

Going back to our revised version ofthe Toaster module we first pull in the‘Exporter’ module and we then assignExporter to ‘@ISA’, this allows yourmodule to ‘inherit’ functionality from the Exporter module. Inheritance is atopic more related to object orientatedprogramming so we will gloss over thedetails, for now just think of these twolines as the code that enables yourmodule to export symbols.

The @EXPORT line controls whichfunctions and variables are to beexported by default. Any entries in thisarray will be exported to the callingnamespace when this module is ‘use’d.If the caller only wants to pull out asingle function from your module andkeep the memory footprint of her ownapplication down then it is possible toamend the ‘use Toaster;‘ code so that themodule only exports what is desired:

use Toaster qw(roast_toast);

This code sample will only import the‘roast_toast’ function, if you now try andmodify the ‘$num_slots’ variable thatthe module has in its ‘@EXPORT’ arraythen you will get an error as it is nolonger available in this package.

use Toaster qw(roast_toast);#this worksroast_toast();#this fails with an error$num_slots = 23;

Now we have covered the basic rulesand functionality of Exporting from onemodule into an application, let’s look at a slightly more complex scenario. If amodule has a basic level of functionalitythat it always wants to provide, but italso has some niche functions that areonly useful in specialized applicationsbut require too much memory to exportby default, rather than forcing the caller to use fully qualified package names

65www.linux-magazine.com Dec 02 / Jan 03

PROGRAMMINGPerl Tutorial: Part 7

Page 5: Perl_Part7

show you that the entry barrier is not ashigh as it might seem we now move onto one of the best examples of code reuseon the Internet, CPAN.

Getting ModulesWhile Perl can stand feature for featurewith other modern programminglanguages its true ‘killer app’ may beCPAN (http://www.cpan.org), theComprehensive Perl Archive Network, alarge online repository of modules builtby the Perl community.

The modules in CPAN are themselvesgood examples of why extra effort isrequired to build a generic module .However the effort is its own reward,CPAN’s stock of code mostly originatesfrom coders “scratching their own itch”and donating the code back to thecommunity to save other people fromreinventing the wheel. CPAN is one ofthe more successful examples of the“Cathedral” development methodologywhereby a pool of developers raise thestandard of the code base.

Once an author is registered on CPANthey can begin the process of uploadingmodules. Before a module can beuploaded the name and purpose of themodule has to be announced to‘[email protected]’ where the hardworking volunteers ensure there are noduplications with existing work and themodule uses an appropriate namespace.

Once the module details have beenaccepted the module is uploaded to theserver where it comes under the scrutinyof the Perl QA Smoke testers.

The smoke testers are another group of volunteers that donate processingtime on a variety of operating systemsand architectures, using batched scriptsnew arrivals and updates on CPAN aretested and the results are posted back toCPAN showing which platforms themodule ran on. Finally the module ispropagated though the CPAN mirrorsuntil it becomes fully available every-where.

Retrieving a Perl module can be donein a number of ways:• CPAN• CPAN++• manual install• PPM• Native package installer (apt-get, rpm

or similar)

The example given below shows thetypical install procedure for a modulethat is being installed manually and thenwe introduce you to the cpan shell that ismade available by the CPAN.pm module.We will not be covering the othermethods of installation as they are not asuniversally available.

Once the module’s ‘.tar.gz’ file isdownloaded from one of CPAN’s modulepages the following steps should betaken to install it:

# extract module$ tar -zxvf U

<modulename>-<version>.tar.gz$ cd <modulename>-<version>$ perl Makefile.PL$ make$ make test$ make install

Stepping through the above example weunpack the module and then change into its directory. Running ‘perlMakefile.pl’ causes perl to generate aMakefile for the module filling in manyof the required details with theinformation Perl discovered about thesystem when it was built and installed.To show how much work this savesconsider that a Makefile.pl of 25 lines isexpanded to a ready for use Makefile ofover seven hundred lines.

We then run a ‘make’ to do anybuilding required for a module beforerunning the modules test harness with‘make test’. Not all modules have a set oftests to run. The Perl QA effort hasprogressed to the point where all thecore modules have a test harness.

Although not having tests should not stop you from using a module their presence indicates a conscientiousauthor and an indication of robust code,providing all the tests pass…

We then run ‘make install’ to performthe work of installing the module in oneof the paths which Perl searches for itslibraries. An important often overlookeddetail is that this is the only step ofinstalling modules that actually requiresyou to be root: all of the other stages canbe executed as an unprivileged user.

The extra privileges are neededbecause it writes to directories that mostpeople will not have access to. Now thatyou have seen the procedure for

66 Dec 02 / Jan 03 www.linux-magazine.com

and break some of the laws of gooddesign Exporter allows a second array tobe populated. This array is called‘@EXPORT_OK’ and only exports whatthe caller requests.

package Kettle;require Exporter;use strict;use warnings;our @ISA = qw(Exporter);our @EXPORT = qw(boil);our @EXPORT_OK = qw(whistle);our $VERSION = 1.00;my $boil_time = 2;my $pints_held = 4;sub boil {print "Kettle has been $$

boiled...\n";}sub whistle {print "Whhhhhhheeeeeeeee\n";

}1;

The package above shows a very simpleimplementation of a Kettle that has theessential kettle function, ‘boil’ while alsoproviding the seldom requested ‘whistle’.If we just ‘use Kettle’ then we only get‘boil’ as that is the only element in the‘@EXPORT’ array and if we explicitlyask for ‘whistle’ with the ‘use Kettleqw(whistle)‘ then we lose the ability to‘boil’. To solve this problem Perl allowsyou to ask for the entire ‘@EXPORT’array and then any additional functionsthat you would like:

use Kettle qw(:DEFAULT whistle);boil();whistle();

By using the special ‘:DEFAULT’ label toimport the values that are in the‘@EXPORT’ array and also providing thename of the features that you need inyour package you can make genericmodules that allow a large scope ofreuse. Working through the correct pathof code reuse has taken a lot more initialeffort than the simple copy and pasteapproach does, but hopefully you willhave been convinced to do thingscorrectly by the additional power thatmodules provide.

We have barely breached the surfaceof Perl’s module system provides. To

Perl Tutorial: Part 7PROGRAMMING

Page 6: Perl_Part7

installing a module by hand you canappreciate the abstraction that installingvia CPAN provides. The other majorselling point of the CPAN approach isdependency tracking.

When you try and install a module byhand that depends upon additionalmodules you must first install thosemanually otherwise the install fails dueto unsatisfied dependencies. This couldtake several iterations if the modules thatare listed as dependencies have furtherdependencies of their own.

Installing via the CPAN module uses ashell similar in many ways to bash,including command completion andhistory – if the required modules areinstalled. The first time you invoke theCPAN shell you will be prompted with alist of configuration options that you willbe asked to confirm or edit. Theseinclude which mirrors to downloadfrom, where certain binaries are locatedon the system and whether toautomatically follow dependencies.

To invoke the CPAN shell from thecommand line you must type:

perl -MCPAN -e shell

And the prompt will change to ‘cpan>‘.The invocation line causes the perl inter-preter to load the module specified bythe upper case ‘-M’, in this case theCPAN module while the ‘-e’ calls thefunction ‘shell’ which has been exportedfrom the CPAN.pm module.

From within the cpan shell you caneasily search for and install additionalmodules with a very importantadvantage over installing them by hand,CPAN.pm will track and installdependencies for you.

Depending on the values you suppliedwhen you ran CPAN.pm for the firsttime, this tracking dependencies wouldbe done either automatically without aprompt, only after you answer yes toinstall at a prompt or the module installwould fail. As you would expect the lastoption is seldom chosen.

Navigating around the CPAN shell isvery simple once you have a grasp of afew basic principles, if you are unsure ofthe command required to carry out atask then type ‘help’ at the prompt and itwill return a list of the valid commandsand what they do.

The commands are in three maingroups:• Querying commands• Module installation• Meta-commandsThe querying commands are the bestplace to start as they are often thecommands you use the most, to view thecollection of modules under the XMLnamespace type in ‘m /XML::/‘ andpress return, a list of all the modules willscroll past along with some additionaldetails such as the author name andmodule version. When you look alongthe selection of XML modules you maysee a module that looks promising forthe task at hand, for exampleXML::XPath.

Once you have found a module thatmay be suitable you can install it byissuing ‘install XML::XPath’ at theprompt, the module will then bedownloaded to the machine and themanual steps described above will berun via the CPAN.pm module. If themodule has any tests defined for itselfthen they will be run at the install and areport of the successes and failures willbe shown.

If the module fails its tests then theinstallation of the module will beaborted. If the module passes its owntests but fails because of unsatisfieddependencies then CPAN.pm will go andtrack down those dependencies andinstall then going through as manyiterations of this as needed until eitherthe modules are all installed or one ofthem fails.

Similar CodeWhen you have begun to use a numberof CPAN modules you may find that thestandard of code provided is highenough that you would like to see whatelse the author has contributed.

The author of ‘XML::XPath’, MattSergeant, a Perl luminary responsible fora large number of CPAN’s more popularhas an impressive collection of modulesthat can be viewed without leaving thecomfort of the CPAN shell.

We rerun the search for the‘XML::XPath’ module but this time as weknow the full name we do not use a reg-ular expression search and instead weenter ‘m XML::XPath’. ‘m’ is the keywordthat tells CPAN.pm we are searching for

a module, you can also use ‘a’, ‘b’ or ‘d’to search for authors, bundles or distrib-utions but those are out of the scope ofthis article.

The ‘m XML::XPath’ command willthen go and get a list of all the modulesthat are currently listed in the author’shome directory and display them onscreen with some additional details suchas the files last update time, the versionnumber of the module and even the filesize of the complete module. From hereif we wanted to install another modulewe could do a simple ‘install XML::SAX’and the CPAN.pm module would takecare of it for us.

Now that we have shown you how toinstall modules we’re going to show youhow to be a little more choosy in themodules you actually download, to findout more information than the name andbrief summary you can use theCPAN.pm shell to retrieve and displaythe modules own readme file. To do thisfor XML::SAX you would type theintuitive ‘readme XML::SAX’, CPAN.pmwill go and download the file and thenthe pager you chose in the initializationof the CPAN.pm module will be invokedto read it.

The last installation example we willshow is a little different from theprevious ones as it applies to CPAN.pmitself, whenever a new release of theCPAN.pm module is issued CPAN detectsthis the next time it is run and offers thechance to upgrade. Although it mayseem a little strange to use CPAN.pm toupgrade the CPAN.pm module, theprocess is very reliable and requires verylittle additional effort beyond a normalmodule install.

After you have issued an ‘installCPAN’ command and the module hasbeen downloaded and the tests run youfinish off the install by issuing a ‘reloadcpan’ command, the screen will have a little process counter of dots appear and a summary of the total number ofsubroutines that have been reloaded byCPAN.pm itself is shown marking thesuccessful completion of the upgrade.

When you have completed your workin the CPAN shell to exit back to yourcommand shell just enter ‘q’ on a line byitself and press return, the lock-file willbe removed and the CPAN shell will thenbe closed. ■

67www.linux-magazine.com Dec 02 / Jan 03

PROGRAMMINGPerl Tutorial: Part 7