Hack 34. Create a Standard Module Toolkit


Curb your addiction to explicit use statements.

Most experienced Perl programmers rely on a core set of modules and subroutines that they use in just about every application they create. For example, if you work with XML documents on a daily basis (and you certainly have our deepest sympathy there), then you probably use either XML::Parser or XML::SAX or XML::We::Built::Our::Own::Damn::Solution all the time.

If those documents contain lists of files that you need to manipulate, then you probably use File::Spec or File::Spec::Functions as well, and perhaps File::Find too. Maybe you need to verify and manipulate dates and times on those files, so you regularly pull in half a dozen of the DateTime modules.

If the application has an interactive component, you might continually need to use the prompt( ) subroutine from IO::Prompt [Hack #14]. Likewise, you might frequently make use of the efficient slurp( ) function from File::Slurp. You might also like to have Smart::Comments instantly available [Hack #54] to simplify debugging. Of course, you always specify use strict and use warnings, and probably use Carp as well.

A Mess of Modules

This adds up to a tediously long list of standard modules, most of which you need to load every time you write a new application:

#! /usr/bin/perl use strict; use warnings; use Carp; use Smart::Comments; use XML::Parser; use File::Spec; use IO::Prompt qw( prompt ); use File::Spec::Functions; use File::Slurp qw( slurp ); use DateTime; use DateTime::Duration; use DateTime::TimeZone; use DateTime::TimeZone::Antarctica::Mawson; # etc. # etc.

It would be great if you could shove all these usual suspects in a single file:

package Std::Modules; use strict; use warnings; use Carp; use Smart::Comments; use XML::Parser; use File::Spec; use IO::Prompt qw( prompt ); use File::Spec::Functions; use File::Slurp qw( slurp ); use DateTime; use DateTime::Duration; use DateTime::TimeZone; use DateTime::TimeZone::Antarctica::Mawson; # etc. 1;

and just use that one module instead:

#! /usr/bin/perl use Std::Modules;

Of course, that fails dismally. Using a module that uses other modules isn't the same as using those other modules directly. In most cases, you'd be importing the components you need into the wrong namespace (into Std::Modules instead of main) or into the wrong lexical scope (for use strict and use warnings).

The Hack

What you really need is a way to create a far more cunning module: one that cuts-and-pastes any use statements inside it into any file that uses the module. The easiest way to accomplish that kind of sneakiness is with the Filter::Macro CPAN module. As its name suggests, this module is a source filter that converts what follows it into a macro. Perl then replaces any subsequent use of that macro-ized module with the contents of the module. For example:

package Std::Modules; use Filter::Macro;     # <-- The magic happens here use strict; use warnings; use Carp; use Smart::Comments; use XML::Parser; use File::Spec; use IO::Prompt qw( prompt ); use File::Spec::Functions; use File::Slurp qw( slurp ); use DateTime; use DateTime::Duration; use DateTime::TimeZone; use DateTime::TimeZone::Antarctica::Mawson; # etc. # etc. 1;

Now, whenever you write:

#! /usr/bin/perl use Std::Modules;

all of those other use statements inside Std::Modules are pasted into your code, in place of the use Std::Modules statement itself.

Hacking the Hack

There's also a more modular and powerful variation on this idea available. The Toolkit module (also on CPAN) allows you to specify a collection of standard module inclusions as separate files in a standard directory structure. Once you have them set up, you can automatically use them all just by writing:

#! /usr/bin/perl use Toolkit;

The advantage of this approach is that you can also set up "conditional usages"files that tell Toolkit to import specific subroutines from specific modules, but only when something actually uses those subroutines. For example, you can tell Toolkit not to always load:

use IO::Prompt qw( prompt ); use File::Slurp qw( slurp );

but only to load the IO::Prompt module if something actually uses the prompt( ) subroutine, and likewise to defer loading File::Slurp for slurp( ) until actually necessary.

That way, you can safely specify dozens of handy subroutines and modules in your standard toolkit, but only pay the loading costs for those you actually use.



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net