Flylib.com

Books Software

 
 
 

Chapter 4. Working with Modules


Chapter 4. Working with Modules

Hacks 28-42

Perhaps the greatest invention of Perl 5 is the idea of modules. They allow people to modify the language and reuse code far beyond what Larry and the Perl 5 porters ever envisioned . (Who could have predicted CPAN or Acme::* , for example?)

If you're doing any serious work with Perl, you'll spend a lot of time working with modules: installing them, upgrading them, loading them, working around weird and unhelpful features, and even distributing them. It makes a lot of sense to understand how Perl and modules interact and how to work with them effectively.

Here are several ideas that show off the varied ways that you can extend your programs. CPAN is only an arm's length away. Be ready.



Hack 28. Shorten Long Class Names

Type only what you need to type. You know what you mean.

Are you tired of using Perl classes with Really::Long::Package::Names::You::Cant::Remember ? Use aliased and forget about them. This handy CPAN module creates short, easy-to-remember aliases for long class names.

The Hack

Given the hypothetical example just cited, use aliased to load the class and create an alias all at once:

use aliased 'Really::Long::Package::Names::You::Cant::Remember';

my $rem = Remember->new( );

When aliased loads a class, it automatically creates a constant subroutine, in the local name space named after the final part of the package name. This subroutine returns the full package name. Because it's a constant, it's actually very efficient; Perl will inline the package name , so that by the time your code has compiled, Perl sees it as if you had actually typed:

use aliased 'Really::Long::Package::Names::You::Cant::Remember';

my $rem = Really::Long::Package::Names::You::Cant::Remember->new( );

You gain simplicity and lose, well, nothing.

Resolve conflicts

Sometimes you might want to alias two classes that have the same final portion of their package names. In such cases, specify the alias that you want to use to disambiguate the two classes:

use aliased 'My::App::Contact';
use aliased 'My::App::Type::Contact' => 'ContactType';

my $contact_type = ContactType->new( );
my $contact      = Contact->new({ type => $contact_type });

Importing with aliased

Sometimes, even in object-oriented programming, you need to import symbols from a module. aliased allows you to do so while still creating an alias. The only wrinkle is that you must explicitly specify an alias. Why? Because then you pass in a list of import symbols, and if you didn't specify an alias name, the first symbol would be the alias! Here's how it works:

use aliased 'My::App::Contact' => 'Contact', qw( EMAIL PHONE );

my $contact = Contact->new({
    kind  => EMAIL,
    value => 'perlhacks@oreilly.com',
});

If you hadn't put that 'Contact' there, then the alias would have been EMAIL and that wouldn't do what you meant .



Hack 29. Manage Module Paths

Keep your code where it makes sense to you, not just to Perl.

Perl's a flexible language and it tries to make few assumptions about your environment. Perhaps you're a system administrator with root access and a compiler and can install modules anywhere you want. Perhaps you only have shell access on a shared box and have to submit a change request to have something installed. Perhaps you want to test one set of modules against one program but not another.

Whatever the case, Perl gives you options to manage where it looks for modules. Suppose you have a program in your ~/work directory that uses a module named Site:: User . By default, Perl will search all of the directories in the special @INC variable for a file named Site/User.pm . That may not always include the directory you want ( especially if, in this case, you want ~/work/lib ). What can you do?

Within Your Program

The simplest and most self-contained way to change Perl's search path is within your program by using the lib pragma. This happens at compile-time [Hack #70], as soon as perl encounters the statement, so put it before any use line for the module you want to load. For example:

use lib 'lib';
use Site::User;

adds the lib/ directoryrelative to the current directoryto the front of Perl's search path list. Similarly:

no lib 'badlib';
use Site::User;

removes the badlib/ directory from Perl's list of search paths. If you have two versions of Site::User installed and want to make sure that Perl doesn't pick up the wrong version from the wrong directory, exclude it.

From the Command Line

Sometimes you don't have the option or the desire to modify a program, though, especially when you're merely testing it. In that case, use the lib pragma from the command line when invoking the program by using perl 's -M switch:

$

perl -Mlib=lib show_users.pl


This is equivalent to use lib 'lib' . To exclude a path, prepend a hyphen to lib :

$

perl -M-lib=badlib show_users.pl


The -I flag also lets you include paths, but it does not let you exclude them.


With an Environment Variable

Of course, modifying every program or remembering to add a command-line switch to every invocation is a tremendous hassle. Fortunately, there's a third option: set the PERL5LIB environment variable to a colon -separated list of directories to add to the search path. Depending on your shell, this may be:

$

export PERL5LIB=/home/user/work/lib:/home/user/work_test/lib:$PERL5LIB

%

setenv PERL5LIB /home/user/work/lib:/home/user/work_test/lib:$PERL5LIB


There's no good and easy way to exclude a directory for the search path here; put the correct directory at the front of the path.

If you put the appropriate invocation in the appropriate startup file (such as /etc/profile or the equivalent), users do not even have to know that this path is there. Of course, if they run programs from cron or another environment without these variables , some paths may not be present.

An easier option may be to write a simple shell script that sets the environment properly and then launches the actual perl binary, passing along the command-line options appropriately.

When Recompiling Perl

Your final recourse is to set the appropriate paths when compiling Perl [Hack #67]. This isn't as bad as it sounds, but it does take a little bit more dedication. Once you have downloaded and unpacked Perl, run the Configure script. Answer all of the questions appropriately until it asks:

Enter a colon-separated set of extra paths to include in perl's @INC
search path, or enter 'none' for no extra paths.

Colon-separated list of additional directories for perl to search? [none]

Type there the list of directories to add to Perl's built-in @INC . Note that perl will search this directory after it searches its core directories, so if you want to load something in place of a core module, you must manipulate the path with one of the other techniques.