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.
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
).
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.
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.
Get Perl Hacks now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.