Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Dynamicaly loading modules

by Sinister (Friar)
on Feb 13, 2002 at 12:44 UTC ( [id://145148]=perlquestion: print w/replies, xml ) Need Help??

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

Fellow Monks,

I am working on a system with multiple states. Each state should have its own events, and in order to accomplish this, each state has it's own module. Right now we are talking about a mere four different states, which resulted in code like this:

use strict; use GGI; my $cgi = new CGI; my $state = $cgi->param("state"); my $pack; if ( $state eq "W" ) { $pack = 'Pack_W'; use Pack_W; } elsif ( $state eq "X" ) { $pack = 'Pack_X'; use Pack_X; } elsif ( $state eq "Y" ) { $pack = 'Pack_Y'; use Pack_Y; } elsif ( $state eq "Z" ) { $pack = 'Pack_Z'; use Pack_Z; } my $app = $pack->new(%stuff); $app->run;

Of course this solution is not very elegant, especialy not when you consider I am facing 20 or more states...

I am looking for a way to trick the use statement, to accept scalars and such...


Sinister greetings.
"With tying hashes you can do everything God and Larry have forbidden" -- Johan Vromans - YAPC::Europe 2001
perldoc -q $_

Replies are listed 'Best First'.
Re (tilly) 1: Dynamicaly loading modules
by tilly (Archbishop) on Feb 13, 2002 at 12:59 UTC
    First of all all of the modules got loaded at compile time, see use for why.

    So instead I would use require as follows:

    my %package = qw( W pack_W X pack_X Y pack_Y Z pack_Z ); unless (exists $package{$state}) { # Handle this error somehow... die "State '$state' is not implemented"; } my $package_file = "$package{$state}.pm"; $package_file =~ s~::~/~g; require($package_file); my $app = $package{$state}->new(%stuff); $app->run;
    Note that it is important to have a check on allowed packages for security reasons. (Never trust the user!) But for a CGI application if your naming scheme is fixed it may make sense to just use a grep to see that the package is implemented, and then produce $pack by a direct manipulation. That is slightly less code, but is less flexible.
Re: Dynamicaly loading modules
by broquaint (Abbot) on Feb 13, 2002 at 13:06 UTC
    You could always eval() your use() statements.
    my $include = shift @ARGV; eval "use $include";
    This also gets around the fact that use() is evaluated at compile-time. However, with that said, it would probably be nicer to use require() like so
    my $include = shift @ARGV; require $include; import $include;
    I believe this does essentially does the same thing as use() but gets around the eval() hack and is more tailored towards dynamically loading modules.
    HTH

    broquaint

      Thanks a lot tilly and broquaint...

      I have been staring at this problem (and many others more for this project) for so long, that I forgot to look at the obvious...

      I do feel a little blond now (no offense there! ;-)

      Sinister greetings.
      "With tying hashes you can do everything God and Larry have forbidden" -- Johan Vromans - YAPC::Europe 2001
      perldoc -q $_

        Hmz,
        both tricks work perfectly, and I now use the Evil eval hack (I didn't sell my soul without side-effects ;-)

        I only wonder though, I use mod_perl for this little bugger, and the following questions raised:

        • Will the modules be sucked into cache (good thing)
        • How can I detect what is in cache? (better thing, even!)

        If you have answers, fellow monks, don't hesitate to shout it out...

        Sinister greetings.
        "With tying hashes you can do everything God and Larry have forbidden" -- Johan Vromans - YAPC::Europe 2001
        `perl -e print; perldoc -q $_
Re: Dynamicaly loading modules
by adamk (Chaplain) on Feb 13, 2002 at 14:04 UTC
    Shameless self promotion yes, but Class::Autouse has a lot of stuff for dynamically loading classes.

    If your module naming scheme is purely internal you can always
    use Class::Autouse; Class::Autouse->autouse_recursive( 'Module::Root' );
    and then at any time in the code
    $state->method();


    Once you have specified the module root with the autouse_recursive, it will load anything under that namespace on demand the first time a method is called.

    Or if your lazy just...
    use Class::Autouse qw{:superloader}; $anyclass->anymethod;
    ...should work OK, but the superloader is a little bit of overkill... :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://145148]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-18 12:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found