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?

3
  • 1
    Duplicate: stackoverflow.com/questions/442710/… Commented Dec 16, 2009 at 20:41
  • Sorry about that. I searched but couldn't find anything. Commented Dec 16, 2009 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... Commented Dec 16, 2009 at 22:45

6 Answers 6

51

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 = $@;
    # ...
};
Sign up to request clarification or add additional context in comments.

12 Comments

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.
While his require wasn't dynamic, I was easily able to make it so (as Picard would say). Thanks for the answer!
@Ether: You're right to say it's not safe, (before the edit) but it's not related to threads.
s@'|::@/@g -- for hysterical raisins, ' and :: are interchangeable as package delimiters.
Anyone who uses ' as a package delimiter outside of a JAPH deserves to have their code break.
|
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: ...".

2 Comments

It's a core module, so should be used.
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
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.

1 Comment

Thanks for the answer. I voted you up since I can't select both answers :).
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;

2 Comments

"require() needs the bareword module name" - no, it doesn't; just s#::#/#g; and append '.pm' to get a pathname.
@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 :)
1

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

Comments

0

i like doing things like..

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.