The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Module::UseFrom - Safe compile-time module loading from a variable

SYNOPSIS

 use Module::UseFrom;
 BEGIN {
   our $var = 'Scalar' . '::' . 'Util';
 }
 use_from $var; # use Scalar::Util;

DESCRIPTION

Many people have written about Perl's problem of loading a module from a string. This module attempts to solve that problem in a safe and useful manner. Using the magic of Devel::Declare, the contents of a variable are translated into a bareword use statement. Since Module::UseFrom leans on this, the safest of the loading mechanisms, it should be every bit as safe.

Said a different way, the final result is a bareword use statement, so even if the translations/hueristics used internally fail, the system is not exposed to the insecurities introduced when translating to require FILE statments or wrapping in a string eval.

Further, Module::UseFrom can do some rudimentary checking before writing the use statement. Most usefully, it can be told only to write the use statement if the module is installed or even of a high enough version.

INSTALLATION

During installation, one may see warnings like Name "ExtUtils::Packlist::FY1" used only once: possible typo at .... This seems to be related to ExtUtils::Installed bug 50315. A patch has been submitted which should fix it. It is not a concern and does not affect any functionality whatsoever, just ignore it.

FUNCTION use_from

The function use_from is the basic interface provided by Module::UseFrom. It takes one argument, a variable, called WITHOUT round braces (see "SYNOPSIS"). The variable can be a scalar, array, or hash (not a list), the usage for each of these forms will be discussed later.

Some things to keep in mind:

  • The variable must come after use_from on the same line. This is a limitation stemming from Devel::Declare.

  • The use_from injects a use statement taking the place of the original call and variable. This means if anything exists on the same line, it is left intact (even the ending semicolon is not affected). This behavior is by design, allowing the user to pass version or import directives as if use_from $var was simply a regular use Bareword::Module statement. For an alternative method of passing these directives see "HASH".

THE VARIABLE

Since Devel::Declare and use both do their work at compile-time, your variable must be populated by then. BEGIN blocks allow you to do this. Module::UseFrom examines the given variable's contents, therefore the variable must be accessible from outside the package, this usually will mean using an our variable. See the "SYNOPSIS" to see an example.

Module::UseFrom will inspect the variable for information. This variable must be a simple Scalar, Array or (not quite as simple) Hash. Each usage will have slightly different effects.

SCALAR

The most basic usage is as follows

 use Module::UseFrom;
 BEGIN {
   our $var = 'Scalar::Util';
 }
 use_from $var; # use Scalar::Util;

If you need to import or specify a version, just do it as you would have if this was a simple use call where your variable replaces the module.

 use Module::UseFrom;
 BEGIN {
   our $var = 'Scalar::Util';
 }
 use_from $var qw/dualvar/; # use Scalar::Util qw/dualvar/;

ARRAY

Rather than making repeated calls to use_from (which is fine), a shortcut is to pass an array which contains multiple module names. These will be translated to muliple use directives. The last one will not be terminated, so conceivably this mechanism can be used to pass additional arguments to the last module in the array. Rather than do this though, check out the more useful "HASH" type of calling when doing this.

 use Module::UseFrom;
 BEGIN {
   our @var = qw'Scalar::Util List::Util';
 }
 use_from @var; # use Scalar::Util; use List::Util;

HASH

When called with a hash, the interface suddenly becomes a little more flexible. The keys are always the module to be used.

SIMPLE SCALAR

If the value is a simple scalar, which are interpreted as version directives. Use 0 to allow any version (and in fact not even write the version to the use directive).

ARRAY REFERENCE

If the value is an array reference, which is interpreted as import directives. These must (for now) be simple strings, not object/references etc. These are written out as a single quoted list, i.e. ('item0', 'item1', ..., 'itemN').

HASH REFERENCE

If the value is a hash reference. This may contain the keys version and import which behave just like the two previous calling types (taking a scalar and an array reference repectively). In fact this calling style is used internally by the "SIMPLE SCALAR" and "ARRAY REFERENCE" types anyway.

Further it also can take the key check_installed with a true value. When this is done the module will only be written to a use statement if Module::CoreList or ExtUtils::Install can find them. This prevents the embarrassing not found in @INC errors when the module isn't installed; of course this means that it will not be loaded at all, so only use this functionality when it is deserved. To check if the module was loaded, Module::UseFrom adds the key found_version which contains the imformation that the aforementioned modules obtained in checking for the module. If the module isn't loaded then found_module will be zero. N.B. if you intend to inspect your variable after wards you might need to declare it before the BEGIN block.

Finally, if a version and check_installed are both specified and the module is installed but of insufficient version, the use directive will not be writte, just as in the check_installed scenario.

 use Module::UseFrom;
 our %var;
 BEGIN {
   our %var = (
     'Carp' => {
       check_installed => 1,
       version => 0.01,
       'import' => [ qw/carp croak/ ]
     },
   );
 }
 use_from %var; # use Carp 0.01 ('carp', 'croak');
 print $var{Carp}{found_version}; # prints version of Carp found by Module::CoreList

OPTIONS

Module::UseFrom has a few options, controlled by package variables. These also must be inside a BEGIN block, so that they are set in time to be useful.

$Module::UseFrom::verbose

When set to a true value, some additional information is printed to STDERR (via warn). In the special case that it is set to a reference to a scalar, the information is kept in that scalar rather than printing.

$Module::UseFrom::check_installed

When set to a true value, all modules inspected by use_from are treated as though the check_installed option from "HASH REFERENCE" was enabled, even if using the "SCALAR" and "ARRAY" forms.

SOURCE REPOSITORY

http://github.com/jberger/Module-UseFrom

AUTHOR

Joel Berger, <joel.a.berger@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2012 by Joel Berger

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.