Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: Best/possible ways to dynamically use modules

by chipmunk (Parson)
on Dec 18, 2001 at 09:21 UTC ( #132791=note: print w/replies, xml ) Need Help??


in reply to Best/possible ways to dynamically use modules

Conditionally loading a module is very easy. The only thing to avoid is a bare use statement, because use is executed at compile time. For example:
if ($use_socket) { use Socket; # oops! Socket will get loaded at compile-time # before $use_socket is even evaluated }
So, you can either eval a use statement, or require the module and then call import. (I prefer the second approach.)
if ($use_socket) { eval "use Socket"; # ok: Socket gets loaded at run-time # if $use_socket is true }
if ($use_socket) { require Socket; # ok: Socket gets loaded at run-time Socket->import(); # if $use_socket is true }

 

However, you may need more than that, because you're planning to load the modules from a controller module. If the modules you're loading export anything, you probably want to export them into the package that called the controller module. That is, maybe you'll have the controller module load Socket, but then you want to call the Socket functions from the main script.

The Exporter module, which provides a basic import() method, also provides export_to_level(). export_to_level() does an import to a package farther up in the call tree. For modules which inherit from Exporter, such as the Socket module, you can call the export_to_level() method to get the behavior you need:

if ($use_socket) { require Socket; Socket->export_to_level(1, @_); }
Unfortunately, not every module inherits from Exporter or defines its own export_to_level() method. CGI, for example, doesn't have an export_to_level() method. I'm afraid I don't know a good approach for a situation like this. But I hope this was enough to get to you started!

Replies are listed 'Best First'.
Re (tilly) 2: Best/possible ways to dynamically use modules
by tilly (Archbishop) on Dec 18, 2001 at 10:20 UTC
    You can always fool around with a goto:
    { my %is_imported; sub lazy_use { my ($class, @args) = @_; unless ($is_imported{"$class @args"}++) { my $file = $class; $file =~ s-::-/-g; $file .= ".pm"; require $file; my $importer = UNIVERSAL::can($class, "import"); goto &$importer if defined $importer; } } }
    and now you can issue many calls to the lazy_use routine and it will parse once and import once. In fact this routine could be exported to other namespaces and should work correctly.
      Is there any reason to use that goto instead of simply calling the sub, or are you just being perverse?
        There is an extremely good reason to use it.

        Most import routines look at caller to figure out where they are exporting stuff to. If you want the function that I gave to be usefully called from multiple packages (and it is complicated enough that I would), then that function to not appear on the call-stack.

        The alternative would be to interact with the import to let it know where to export to. Unfortunately if the import does not use Exporter, the odds are low that there is any way to do that. And what I was promising was a way of getting the job done that would work with handrolled import methods.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://132791]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (4)
As of 2020-01-25 06:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?