views:

557

answers:

5

Hi,

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

+5  A: 
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";
Nathan Fellman
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
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
One problem with this is that although it looks like "use" it's really just a "require" and no importing seems to happen.
innaM
@Manni, that's what I mean. It's more canonical.
Nathan Fellman
It does import, unfortunately it imports into the eval block.
Brad Gilbert
OK. Thanks for clearing this up. Guess we all learned something here. To me, gpojd's answer is the clear winner.
innaM
+4  A: 

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
Should we really be linking to pirated copies of books?
innaM
Changed the link to go to Google Books, who I presume is authorized to distribute the information as a "Preview".
Adam Bellaire
Thank you. This feels a lot better.
innaM
+8  A: 

"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
+4  A: 

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
+3  A: 

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