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

I'm trying to be lazy and create a generic order-processing script that will take a value from a database and use that value to determine which package whould be 'use'd at run-time for vendor-specific functions. For example, I would like to do something similar to the following:
sub getVendorData { my ($code) = @_; my $returnedVal = 0; if($code =~ m/&lt%(\w+)%>/) { # need to do something special with this vendor my $module = $1; # $module is the package name # (it could be one of 7 different values) # where we'll add any custom stuff that needs to happen for a # particular vendor use Modules::$process; # for example my $vendor = $process->new(); # for example my $returnedVal = $vendor->getVendorData(); } return $returnedVal; }
I would prefere to do something like the above, instead of a large if/else statement, that way, when I add a new vendor - I need only add the associated package to the Modules directory and be up and running - instead of modifying the if/else to include the new condition. Any ideas if this is even possible? Richard Luck Pif Magazine

Replies are listed 'Best First'.
Re: How do I dynamically declare a package name for
by hdp (Beadle) on Apr 27, 2001 at 08:44 UTC
    eval "use $module"; $@ and die $@; # or warn $@, etc. die seems appropriate here my $vendor = $module->new(); # ...
    eval is necessary because use is normally a compile-time directive. You could get a similar effect with require and import; for your purposes, use is probably easier.

    $@ is where eval puts its error messages. See perlvar for more details.

    hdp.

Re: How do I dynamically declare a package name for
by gildir (Pilgrim) on Apr 27, 2001 at 13:36 UTC
    I use this for long-running mod_perl modules:
    my $class = fetch_from_somewhere; my $object; eval { $object = $class->new; }; if ($@) { eval ("use $class"); die ($@) if $@; $object = $class->new; }
    This will include $class.pm only once, the first time it is refferenced. Ideal for mod_perl modules. So performance penalty of compiling "use $class .." code is suffered only once.
      This is actually unnecessary. Both use and require will look in %INC to make sure the file has not yet been included before loading it. (use will still call import again unless you explicitly pass it an empty list of symbols to import.)

      hdp.

        Yes, but there is big difference when calling:
        eval { $object = $class->new; };
        and eval " $object = $class->new; "; In the former case, code is compiled as soon as it is first encountered by perl compiler, that is at compile time and it is compiled only once. While in the later case the code is compiled at run-time and is compiled every time the eval() is run.
        There is no way to do eval { use $class; }; so I must use eval " use $class; "; version, and I try to execute it as seldom as possible.
Re: How do I dynamically declare a package name for
by Rhandom (Curate) on Apr 27, 2001 at 16:43 UTC
    From yesterday, you might look at Re: Re: Re: OO design question. The only difference is that you might want to wrap the require (such as eval{ require $class }; like some have shown here).

    Also, be sure to benchmark the difference between
    eval{ $t = 1; }
    and
    eval "$t = 1;"
    Your getting a very big server hit if you try to dynamically write perl syntax. If you don't need to create syntax on the fly, put braces around it. It will do much better and you can still catch bugs at compile time.

    my @a=qw(random brilliant braindead); print $a[rand(@a)];
Re: How do I dynamically declare a package name for
by jepri (Parson) on Apr 27, 2001 at 08:33 UTC
    I know a clumsy work-around. Export all your functions as strings to be eval'd, or as references. Export them in a hash, maybe. Then when you want to use them just set the tempory function variable to the right hash key and you'll be executing the right function in your subroutine.

    You're probably going to want to do something with references to functions, it just depends on your exact circumstance.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

Re: How do I dynamically declare a package name for
by busunsl (Vicar) on Apr 27, 2001 at 09:53 UTC
    I'd use require:
    require $module; import $module;
      The caveat here is that since you're not giving require a bareword, you don't get the benefit of the filename niceties it would give you; in other words, you can't use $module = "Foo::Bar" and have require do the right thing (unless the right thing is to load a file called, literally, 'Foo::Bar').

      It's been my experience that people don't really expect that, and sometimes miss the fact that the error message says "Can't find Foo::Bar in @INC..." instead of "Can't find Foo/Bar.pm in @INC..."

      hdp.

Re: How do I dynamically declare a package name for
by Anonymous Monk on Apr 27, 2001 at 08:35 UTC
    sorry for the typo above.... every occurance of $process should read $module.