Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Has anyone ever done this before when the name of the module is not known until runtime? Here is what I'm dealing with: At some point in the flow of my code, I pull a value from a database and store it in, say, $module. The value in $module is the fully-qualified package name of the module. Now, all modules pulled from the database adhere to a strict API, and must export the run() method, so I at least know that. However, I'm having trouble loading the module at all:
if ($module) {
   eval "use $module";
   eval "$module::run()";
}
I end up getting "Use of uninitialized value in concatenation (.)" on stderr, and it points to the line where I perform the `use'. Why? Shouldn't the EXPR version of `eval' be able to interpolate $module and hand it off to `use'? I even put parentheses around $module so that it might evaluate first, but to no avail. Now, hardcoding it with the name of the module that is getting assigned to $module works perfectly, so I know that the module is loadable (its path is in @INC and everything, and I can call it like foo::bar::run() just fine if I hardcode it). So, what's the story? Is it even possible to load a module during runtime when the module name is stored in a scalar? Michael

Replies are listed 'Best First'.
Re: Loading a module at runtime...
by jand (Friar) on Apr 08, 2003 at 05:03 UTC
    I would assume that the error actually comes from your second eval. It is actually the same as:
    eval $module::run . "()";
    interpolating the $run variable from the module:: package. You should write this as
    eval "${module}::run()";
      I've figured it out, though the solution doesn't make sense according to my understanding. Here is what now works:
         eval "require $module; import $module";
         eval "$module->run()";
      
      What's odd is that the class::method() syntax is usually used for class method invocation, whereas $object_ref->method() is used after you've already instantiated the class/module.
      In my case above, I haven't instantiated $module at all. If $module is Foo::Bar, then, after interpolation, it looks like Foo::Bar->run()
      Oh, well. It's odd (to me, at least), but it works. Michael
      Or, same thing:
      eval "$module\::run()";
Re: Loading a module at runtime...
by simon.proctor (Vicar) on Apr 08, 2003 at 08:14 UTC
    A while ago I wrote a plugin factory where it returns a new object based on a name passed. Here is the core of the routine:
    $module =~ s/\.(pm|PM)$//; my $mainmodule = PLUGIN_BASE . $module . ".pm"; require $mainmodule; import $mainmodule; return $module->new();
    Where $module was passed in and PLUGIN_BASE is just the dir where I keep the modules.

    I then did this in the main program
    eval{ my $obj = $facory->get_instance('thingy'); $obj->run(); $obj->closedown(); }; if($@) { print $@; }
    On a different note, if anyone spots something wrong with this then please do let me know. This is something that I got working and then left well alone ;)

    HTH

    SP
Re: Loading a module at runtime...
by bart (Canon) on Apr 08, 2003 at 09:12 UTC
    Perhaps you should rethink your approach, and go for require instead of use, and use an OO approach, even though you have no objects, by calling the subs as class methods. That way, you can get rid of the eval, and even have it pass strict without problem.

    One problem when calling require with a variable scalar, is that the format must be different: the magic conversion you get when writing require Foo::Bar; no longer works: you have to convert 'Foo::Bar' to 'Foo/Bar.pm' yourself. So this should, basically, work:

    use strict; our $module = 'Foo::Bar'; my $file = join('/', split /::/, $module) . '.pm'; require $file; $module->run();
    Note that any class method ("run") you call this way, will get one extra argument prepended, in front of any of your own: the class name, the string that's currently in $module.

    p.s. For reasons of sanity, I personally would prefer an extra root in front of the actual module names, for example 'MyDrivers' (bad example :-), so you actually load and run MyDrivers::Foo::Bar, if the user supplies the string 'Foo::Bar'. That way, you can make sure you can only load modules that are especially prepared to be used this way.

    p.p.s. People using older perls than 5.6.0 should replace the 'our' with another appropriate solution (use vars or my), or simply not use strict :-). This has nothing to do with the functionality of the code I described here. I would think that should still work.

      Just thought I'd add that, as far as I know, 'use' happens at compile time only, so you have to 'require' modules at runtime. Also, for OO modules, is there any need to do an import?
        Well, that depends on what the module wants to do, doesn't? I sometimes let OO modules export constants, or a subroutine that returns an object. And there are other things you might want to do in an import.

        Abigail

Re: Loading a module at runtime...
by andrewc (Acolyte) on Apr 08, 2003 at 08:51 UTC
    I'm sure others are already pointing this out, but the second eval line uses double quotes, so an interpolation is being done before eval "" even sees it.

    My preferred form is:
    if (defined $module) { # Detaint $module =~ m/^(My_Safe_Namespace(?:\:\:\w+)*)$/ or die "Unsafe module name: $module\n"; $module = $1; eval "use $1;"; die if $@; # Call 'run' as a method to avoid eval-string $module->run(); }
    Eval-string is generally a bad idea for security reasons, assuming you're relying on data external to the program. This is just a way of minimising its use.
Re: Loading a module at runtime...
by zby (Vicar) on Apr 08, 2003 at 07:26 UTC
    I can't answer your question (perhaps jand is right). Just as a side note you might try require in place of use - and you would not need the eval.
Re: Loading a module at runtime...
by hawtin (Prior) on Apr 08, 2003 at 13:05 UTC