16

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

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Oren Sarid
  • 175
  • 1
  • 7

7 Answers7

9
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";
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
  • That's neat, I wonder why it's not covered in PCB? Is there any difference between this and eval'ing a require? Do you still have to import symbols manually? – Adam Bellaire Jan 14 '09 at 13:15
  • I see the quote, Nathan. But where does it say that require is better in our case? Do you mean "better" like in "less esoteric"/canonical? – innaM Jan 14 '09 at 13:49
  • One problem with this is that although it looks like "use" it's really just a "require" and no importing seems to happen. – innaM Jan 14 '09 at 13:53
  • @Manni, that's what I mean. It's more canonical. – Nathan Fellman Jan 14 '09 at 20:11
  • It does import, unfortunately it imports into the eval block. – Brad Gilbert Jan 14 '09 at 23:23
  • OK. Thanks for clearing this up. Guess we all learned something here. To me, gpojd's answer is the clear winner. – innaM Jan 15 '09 at 08:45
9

"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";
innaM
  • 47,505
  • 4
  • 67
  • 87
6

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:  ' . $@;
gpojd
  • 22,558
  • 8
  • 42
  • 71
4

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.

Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
4

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).

Frederico
  • 81
  • 2
3

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: ...".

DavidGamba
  • 3,503
  • 2
  • 30
  • 46
1

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775