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

I've just (very) recently gotten past the "trying to use require and strict" hurdle, thanks to the thread that turned up when I searched on strict and require here .... I'm now using:

use lib '/path/to/module/location'; use ModuleName;
The issue/difficulty I've run into now is when I try to throw a little logic into the equation.

I'd like to call one of a handful of modules based on a submitted parameter. For example:

use lib '/path/to/module/location'; if ( param('yo') =~ /inyourface/) { use UpYours; }
The interesting thing I've encountered when trying this is that the logic/conditional seems to be ignored, and the functions within the module are available regardless of whether the parameter matches.

I'm just cutting my teeth on this strict/module stuff, so maybe there's something obvious I'm missing. Rather then call half a dozen modules I don't need, I'd like to be able to call the only one I need based on a parameter value.

Any insights would be appreciated.

Replies are listed 'Best First'.
Re: Using a paramter value to call a module
by jasonk (Parson) on Feb 07, 2003 at 02:47 UTC

    'use' is evaluated at compile-time, not run time (as the documentation indicates, it's essentially the same as calling require and import from a BEGIN block), so by the time your logic is evaluated, the use has long since executed. You can delay that by putting it in an eval though...

    use lib '/path/to/module/location'; if( param('yo') =~ /inyourface/) { eval "use UpYours;"; }

    You could also copy the code that use runs when it imports the module, and do "require UpYours; import UpYours;" instead of the eval (check the perl documentation for 'use').

Re: Using a paramter value to call a module
by pfaut (Priest) on Feb 07, 2003 at 02:52 UTC

    'use' is processed at compile time. If you need to include modules at runtime, use 'require'. There are some other differences between the two so look them up in the documentation. For one thing, 'use' may import symbols from the module automatically. You need to call the module's import method yourself if you use 'require'.

    Why are you using 'use lib'? You shouldn't need to do this for properly installed modules. If this is a library of your own modules, you might be better off using an environment variable such as PERLLIB or PERL5LIB to locate these rather than embedding the path in all your programs.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
      If this is a library of your own modules, you might be better off using an environment variable such as PERLLIB or PERL5LIB to locate these rather than embedding the path in all your programs.
      Nope, because even though you might be setting that variable, there's no guarantee that someone else running your program has that same variable set. But if you use lib, then everyone wins.

      use lib is generally preferred to an environment variable for this reason.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Ooops,

        merlyn, I do not belive that. Please explain further, because I would say everybody looses if you use lib.

        My experience tells me, to avoid hardcoded variables whenever possible, especially paths to files, for the following reasons:

        1. if you move the script, it possibly does not run anymore, the path does not exist for a different user on the network. So you have to modify the script and have dozens of version after a while. (Think of big networks, different usergroups with access rights etc.)

        2. You have a testbed with your modules and a different production environment. You will have to modify your programm after the release-test.For the stuff with legal impacts, I will never get through revision, even if I do the same with PERL5LIB, because of the remaining risk of further changes.

        3. use lib is at the beginning, other constants maybe not, but somewhere hidden in a module etc. This is hard to maintain.

        4. You have a well coded script, that can be used for different purposes, you change a setting in an ini-file instead of the code itself.

        5. customization or internationalization can be solved with a module on a different path (use Perl code to set constants). You have to switch the path maybe repeatedly.

        etc. etc.

        But for the use lib; I consider the discussion not necessary, because it is quite easy to avoid it most times:
        - have the modules in a subdirectory
        - install them properly, so they are in .../site/lib and in the path beneath the runtime.

        --
        And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
        (Terry Pratchett, Small Gods)

        ++, I'm in the unfortunate position of having to support and migrate some perlies that rely heavily on environment variables. Moving these into a production environment has been made more difficult than necessary by poorly implemented and documented code..
Re: Using a paramter value to call a module
by hawtin (Prior) on Feb 07, 2003 at 09:33 UTC

    I have faced this issue enough times to construct the following function:

    sub require_if_present { # So here is a trick for discovering if the module is # available (and loading it if it is). This function returns # True if the module is there and this generally sets a # flag to tell the rest of the program how to behave my($module_name,$loaded) = @_; my($module_found); $module_found = 0; eval(<<"LoadModule"); # Use require so we don't load the module if it is not there require $module_name; \$module_found = 1; LoadModule return($module_found); }

    So now I can load different modules depending on run time features such as the OS being used or the value of a command line option.

    # Load different modules depending on OS if($operating_system =~ /^MSWin/i) { if(!&require_if_present("Win32")) { $no_win32 = 1; } } # The $no_tk etc vars are set by command line # options before I get here if(!$no_tk) { if(&require_if_present("Tk")) { &require_if_present("Tk::DialogBox"); if($no_fileselect || !&require_if_present("Tk::FileSelect")) { $no_fileselect = 1; } if($no_progress || !&require_if_present("Tk::ProgressBar")) { $no_progress = 1; } if($no_dirtree || !&require_if_present("Tk::DirTree")) { $no_dirtree = 1; } } else { $no_tk = 1; } } # Then later I can... if($no_tk) { # Run without an interface ... } else { $main_win = new Tk::MainWindow( -title => "My App", ); ... }
      Interesting solution, but could you please explain the eval statement in the require_if_present sub? It looks as if you are using a here document, but would a try-catch-block eval not be more appropriate here? E.g.

      sub require_if_present { my $mod = shift; eval { require $mod; return 1; } return 0 if $@; }

      pike

        require() has different meanings depending on the argument. See perlfunc. It even has an example of what you're trying to do, and why it's helps to use eval EXPR.

        <nit>eval requires a semi-colon after it.</nit>

        ihb

        Interesting solution, but could you please explain the eval statement in the require_if_present sub? It looks as if you are using a here document, but would a try-catch-block eval not be more appropriate here?

        TMTOWTDI: That just happens to be the way I implemented it. A here document is convenient for some of the other things I do this way, but that is not a good reason to use it here. Using an eval as you suggest sounds like a cleaner approach. But against that this works (I have used it many times in the last year) and I try not to fix things that work.

        Update: Thinking about this last night I realised why I used a here document to do an eval, its because this was a very common construct in Perl 4 (now that is a really bad reason for doing it here).