I have a Perl program, that needs to use packages (that I also write). Some of those packages are only chosen in Runtime (based on some environment variable). I don't want to put in my code a "use" line for all of those packages, of course, but only one "use" line, based on this variable, something like:
use $ENV{a};
Unfortunately, this doesn't work, of course. Any ideas on how to do this?
Thanks in advance,
Oren
eval "require $ENV{a}";
"use
" doesn't work well here because it only imports in the context of the eval
.
As @Manni said, actually, it's better to use require. Quoting from man perlfunc
:
If EXPR is a bareword, the require assumes a ".pm" extension and
replaces "::" with "/" in the filename for you, to make it easy to
load standard modules. This form of loading of modules does not
risk altering your namespace.
In other words, if you try this:
require Foo::Bar; # a splendid bareword
The require function will actually look for the "Foo/Bar.pm" file
in the directories specified in the @INC array.
But if you try this:
$class = 'Foo::Bar';
require $class; # $class is not a bareword
#or
require "Foo::Bar"; # not a bareword because of the ""
The require function will look for the "Foo::Bar" file in the @INC
array and will complain about not finding "Foo::Bar" there. In this
case you can do:
eval "require $class";
"use" Statements are run at compilation time, not at run time. You will need to require your modules instead:
my $module = "Foo::Bar";
eval "require $module";
I would use UNIVERSAL::require. It has both require and use methods to use a package. The use method will also call import for the package.
use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package: ' . $@;
You probably want to use require
instead of use
if you don't want it to happen at compile time, and then manually import any symbols you might need. See this link to the Perl Cookbook (from Google Books) for a good discussion of methods you can use to achieve what you want.
I think that a module loaded in runtime can be a Plugin. I have this kind of problem, having specific modules to some cases that are loaded in run time as plugins with Module::Pluggable.
Maybe you need to change the logic of your modules, but it works and scale very well (my app started with four modules and now have twenty and it's growing).
How about using the core module Module::Load
With your example:
use Module::Load;
load $ENV{a};
"Module::Load - runtime require of both modules and files"
"load eliminates the need to know whether you are trying to require either a file or a module."
If it fails it will die with something of the like "Can't locate xxx in @INC (@INC contains: ...".
Many years later, eval "use $mod_name";
seems to work just fine (as of at least 5.8.8).
The advantage over eval "require $mod_name";
is that the loaded module's default exports are automatically imported; in other words:
eval "use $mod_name";
is the shorter equivalent of
eval "require $mod_name"; $mod_name->import();
Here's a test command, which passes the name of the module via env. variable mod_name
, loads and imports the module, then uses an imported function (assumes a POSIX-like shell):
$ mod_name='Data::Dumper' perl -e 'eval "use $ENV{mod_name}"; print Dumper("hi!")'
$VAR1 = 'hi!';
I may be missing subtleties; if so, please let me know.