29

I need to dynamically include a Perl module, but if possible would like to stay away from eval due to work coding standards. This works:

$module = "My::module";
eval("use $module;");

But I need a way to do it without eval if possible. All google searches lead to the eval method, but none in any other way.

Is it possible to do it without eval?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
user226723
  • 325
  • 1
  • 4
  • 6
  • 1
    Duplicate: http://stackoverflow.com/questions/442710/how-do-i-use-a-perl-package-known-only-in-runtime – Sinan Ünür Dec 16 '09 at 20:41
  • Sorry about that. I searched but couldn't find anything. – user226723 Dec 16 '09 at 20:45
  • 2
    I'd get your coding standards updated. There's nothing wrong or insecure about eval'ing what is basically a hard coded string. It's the simplest way to accomplish what you want. If you're passing in user input, that's another story... – runrig Dec 16 '09 at 22:45

6 Answers6

50

Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.

eval {
    require My::Module;
    My::Module->import();
    1;
} or do {
   my $error = $@;
   # Module load failed. You could recover, try loading
   # an alternate module, die with $error...
   # whatever's appropriate
};

The reason for the eval {...} or do {...} syntax and making a copy of $@ is because $@ is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.

If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:

my $module = 'My::Module';

eval {
    (my $file = $module) =~ s|::|/|g;
    require $file . '.pm';
    $module->import();
    1;
} or do {
    my $error = $@;
    # ...
};
Michael Carman
  • 30,628
  • 10
  • 74
  • 122
  • Hmm. This is good because you wrap the require in an eval, but your require isn't particularly dynamic. If one could merge answers, Dan's and your's would be my top candidates. – innaM Dec 16 '09 at 20:08
  • While his require wasn't dynamic, I was easily able to make it so (as Picard would say). Thanks for the answer! – user226723 Dec 16 '09 at 20:17
  • This is not very threadsafe, e.g. see http://www.perlfoundation.org/perl5/index.cgi?exception_handling – Ether Dec 16 '09 at 20:22
  • @Ether: The standard advice is to make checking `$@` the very first thing you do, but you're right that there's a race condition. I'll update the answer. – Michael Carman Dec 16 '09 at 20:39
  • 2
    @Ether: You're right to say it's not safe, (before the edit) but it's not related to threads. – tsee Dec 16 '09 at 21:01
  • 3
    `s@'|::@/@g` -- for hysterical raisins, `'` and `::` are interchangeable as package delimiters. – ephemient Dec 16 '09 at 22:50
  • 3
    Anyone who uses `'` as a package delimiter outside of a JAPH deserves to have their code break. – Michael Carman Dec 17 '09 at 00:04
  • How do you access a symbol from the imported module? I tried `$module::$symbol`, but that just gives me `Bad name after ::`. Trying `$module::symbol` gives `Name "module::symbol" used only once: possible typo` – Chris Dodd Sep 10 '18 at 03:29
  • @ChrisDodd: (non-imported) symbols are accessed in the usual way, e.g. `$My::Module::varname` or `My::Module::subname()`. The "used only once" message is just a warning that you may have fat-fingered something. Either reference the variable a second time or disable it with `no warnings 'once'` (in the smallest reasonable lexical scope!) – Michael Carman Sep 10 '18 at 19:11
  • @MichaelCarman: That only works for non-dynamic names. I eventually got it to work with `eval '$' . $module . "::" . $symbol` -- complex but does the job. Seems like there should be simpler way. – Chris Dodd Sep 11 '18 at 01:08
  • @ChrisDodd: "Non-dynamic" names? It sounds like you're using symbolic references. That's almost always a bad idea. See [How can I use a variable as a variable name in Perl?](https://stackoverflow.com/questions/1549685/how-can-i-use-a-variable-as-a-variable-name-in-perl). (And, if necessary, post a new question for the issue you're trying to solve.) – Michael Carman Sep 11 '18 at 14:17
  • @MichaelCarman: I'm trying to solve the problem in the title of this question. "dynamic" names are names that you don't know when writing the code -- they come at run time, perhaps from a command line argument or a configuration file. – Chris Dodd Sep 11 '18 at 20:55
17

How about using the core module Module::Load

With your example:

use Module::Load;
my $module = "My::module";
load $module;

"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
    It's a core module, so should be used. – alexk Jun 20 '14 at 01:03
  • Do you have an example of how to make this work with a dynamic string? When I try it, I just get `Useless use of hash element in void context` and/or `Can't call method "autoload" on unblessed reference` – Chris Dodd Sep 10 '18 at 03:08
10

Well, there's always require as in

require 'My/Module.pm';
My::Module->import();

Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.

Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.

Dan
  • 10,990
  • 7
  • 51
  • 80
4

No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).

EDIT: Code amended below, but I'm leaving the first version up for completeness.

I use I used to use this little sugar module to do dynamic loads at runtime:

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;
    eval "require $class" or do { die "Ack, can't load $class: $@" };
}

1;

PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this: $class->export_to_level(1, undef, @imports);... it should work, but is not tested.

EDIT: version 2 now, much nicer without an eval (thanks ysth): :)

package MyApp::Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
    my ($class) = @_;

    (my $file = $class) =~ s|::|/|g;
    $file .= '.pm';
    require $file;  # will die if there was an error
}

1;
Ether
  • 53,118
  • 13
  • 86
  • 159
  • 4
    "require() needs the bareword module name" - no, it doesn't; just s#::#/#g; and append '.pm' to get a pathname. – ysth Dec 16 '09 at 20:30
  • @ysth: wow, you're right... the docs are very vague about this but it does indeed work. Well that's splendid, now I can revise my module to eliminate that evil eval :) – Ether Dec 16 '09 at 21:16
1

Class::MOP on CPAN has a load_class method for this: http://metacpan.org/pod/Class::MOP

szabgab
  • 6,202
  • 11
  • 50
  • 64
Terrence Brannon
  • 4,760
  • 7
  • 42
  • 61
0

i like doing things like..

require Win32::Console::ANSI if ( $^O eq "MSWin32" );

ShoeLace
  • 3,476
  • 2
  • 30
  • 44