Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Best way to dynamically use a .pm?

by TJPride (Pilgrim)
on Nov 28, 2011 at 19:04 UTC ( [id://940442]=perlquestion: print w/replies, xml ) Need Help??

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

I do work for a company that does marketing for nearly 100 car dealerships around the US. A big part of this is importing and maintaining data for each dealership from a variety of older systems, and doing this requires a large number of config variables and even custom subs. Obviously, dumping these all in one huge .pm isn't a good option, and as far as I know, I can't "use" a path containing a variable (a keyword representing the dealer).

Or to put it another way, I have a folder called Config that contains x.pm, y.pm, z.pm, etc. where x, y, and z are dealer keywords. When I run a data import, I have a variable containing the dealer keyword, and I want to use just that one .pm, let's say x.pm. What's the best way to go about doing this? Up to now, I've been loading the file contents and using eval, but I'm wondering if there's a more elegant / more efficient way to do it.

Replies are listed 'Best First'.
Re: Best way to dynamically use a .pm?
by BrowserUk (Patriarch) on Nov 28, 2011 at 19:15 UTC

    Use require:

    c:\test>type dealer\*.pm dealer\x.pm package config; our $dealer = 'x'; dealer\y.pm package config; our $dealer = 'y'; dealer\z.pm package config; our $dealer = 'z'; c:\test>perl -E"my $p=shift; require qq[dealer/$p.pm]; say $config::de +aler" x x c:\test>perl -E"my $p=shift; require qq[dealer/$p.pm]; say $config::de +aler" y y c:\test>perl -E"my $p=shift; require qq[dealer/$p.pm]; say $config::de +aler" z z

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Best way to dynamically use a .pm?
by CountZero (Bishop) on Nov 28, 2011 at 19:10 UTC
    Check out UNIVERSAL::require. I think it will do exactly what you want.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Best way to dynamically use a .pm?
by JavaFan (Canon) on Nov 28, 2011 at 19:54 UTC
    Why put configuration data in Perl modules? What's wrong with using a configuration file? At least that allows editing by "untrusted" people.
      I'm the only one editing the system, so that doesn't really matter, at least for now. But can you give an example of how a config file is different from a Perl module? If it's a superior way to organize my code and as simple to use as require, I'm open-minded.
        Uhm, a configuration file doesn't execute code? A typo in a configuration file doesn't prevent the program from compiling? For a configuration file, you wouldn't have had the need to ask how to dynamically use it? Differences enough for you?

        Whether it's superior enough, I do not know. It's your program after all.

Re: Best way to dynamically use a .pm?
by patcat88 (Deacon) on Nov 28, 2011 at 19:51 UTC
    Read use Module and require. PMs can put their subs in any package. PM names just look like packages, but they aren't, and a PM doesn't have to put subs in the package its named after (a good idea for unmaintainable code). PMs are simply text files given to the do EXPR function.

    Note, you can write the require and use functions yourself in pure perl.

    I think for your case 1 PM per data format, loaded using requires, or put a begin block read the data header and then do a require in the begin block, parse the file outside of the BEGIN block/normal runtime.
Re: Best way to dynamically use a .pm?
by choroba (Cardinal) on Nov 28, 2011 at 19:07 UTC
Re: Best way to dynamically use a .pm?
by Tux (Canon) on Nov 29, 2011 at 14:42 UTC

    Why put the data in .pm files? Can't it be controlled by data structures in some readable way, like JSON or YAML? Does it need to include code? If parameters in the config files can control program flow in the module, I'd say stick to config files and not dynamic modules. An alternative to JSON of YAML might be to look at any of the plethora of Config:: modules on CPAN.

    Then there is the long forgotten support for files in the do keyword:

    $ cat honda.pl #!perl print STDERR "Using Honda\n"; sub honda { print "Honda rulez\n"; } 1; $ perl -wE'do "honda.pl";say 2;honda()' Using Honda 2 Honda rulez $

    do does accept variables :)


    Enjoy, Have FUN! H.Merijn
      Queries, templates, and the data interface between the two can vary widely between dealers, with no way to predict in advance. The best way to handle this is custom-modified subs, as far as I can tell. Essentially, the same .pm only in many different flavors. Maybe this isn't the best approach, but it seems to be working - I was only really concerned with efficiency, now that it'll have to be done for large numbers of transactions rather than just a few data imports.
Re: Best way to dynamically use a .pm?
by cavac (Parson) on Nov 28, 2011 at 21:47 UTC

    Here's an example taken from Maplat::Web::MemCache.pm:

    my $memd; my $memd_loaded = 0; # Decide which Memcached module we want to use # First, we try the festest one, then the standard # one and if everything fails we use our own my $memdtype; { ## no critic (BuiltinFunctions::ProhibitStringyEval) if(eval('require Cache::Memcached::Fast')) { print " Cache::Memcached::Fast available.\n"; $memdtype = "Cache::Memcached::Fast"; $memd = Cache::Memcached::Fast->new ({ servers => [ $self->{service} ], namespace => $self->{namespace} . "::", connect_timeout => 0, }); $memd_loaded = 1; $self->{mctype} = "fast"; } elsif(eval('require Cache::Memcached')) { print " No Cache::Memcached::Fast ... falling back to C +ache::Memcached\n"; $memdtype = "Cache::Memcached"; $memd = Cache::Memcached->new ({ servers => [ $self->{service} ], namespace => $self->{namespace} . "::", connect_timeout => 0, }); $memd_loaded = 1; $self->{mctype} = "slow"; } else { print " No Cache::Memcached* available ... will try to +use Maplat::Helpers::Cache::Memcached\n"; } }
    This just looks up which Memcached modules are available and tries to load one of those.

    Don't use '#ff0000':
    use Acme::AutoColor; my $redcolor = RED();
    All colors subject to change without notice.
Re: Best way to dynamically use a .pm?
by TJPride (Pilgrim) on Nov 28, 2011 at 19:31 UTC
    "use if" requires a statement for every keyword, which gets a bit messy with 100+ keywords (possibly hundreds in the future). I suppose I could use a .pm which then has all the statements, but that seems an overly complicated way to do it.

    Similarly, I don't want to mess with extra Perl modules if it isn't absolutely necessary.

    require "$x.pm", however, does seems to work, and in a very simple way.

Re: Best way to dynamically use a .pm?
by Anonymous Monk on Nov 29, 2011 at 03:35 UTC
Re: Best way to dynamically use a .pm?
by sundialsvc4 (Abbot) on Nov 29, 2011 at 03:15 UTC

    The admonition to use UNIVERSAL is a very good one, because (having actually overlooked its existence until this moment ...) the logic for constructing a successful "require" is very messy indeed.

    Now, if you will pardon me while I go and fix a bunch of very smelly old code.

Re: Best way to dynamically use a .pm?
by Tux (Canon) on Nov 29, 2011 at 14:36 UTC

    Why put the data in .pm files? Can't it be controlled by data structures in some readable way, like JSON, YAML, or CSV? Does it need to include code? If parameters in the config files can control program flow in the module, I'd say stick to config files and not dynamic modules. An alternative to JSON, YAML, or CSV might be to look at any of the plethora of Config:: modules on CPAN.

    update: that was a browser hick-up. Sorry. Just view the other answer.


    Enjoy, Have FUN! H.Merijn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://940442]
Approved by choroba
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: (7)
As of 2024-04-18 02:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found