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

Hi Monks,

I am working on several web scripts, most of which also use some perl modules I wrote. Because the scripts are heavily used, I keep a "production" copy and a "developement" copy of each one. Due to some new work going on, I now need to start making changes to the modules as well. I don't want to goof up a module and have it impact my users, so I thought perhaps I could get away with something like this at the begining of each of the scripts:
my $version = '7.54beta1'; #if this were production, it would simply b +e '7.54' if ($version =~ /beta/){ use lib('/path/to/development/copies/of/modules'); } else { use lib('/path/to/production/copies/of/modules'); } use module1; use module2; use module3; #etc
I tested this out and it doesn't seem to be working very well. It looks as though the perl interpreter scans the code for "use" statements and loads whatever modules they request before it executes the rest of the code (e.g. the if statement). So whichever the module used is whichever ends up closer to the front in @INC.

Is there a way to get this to work? Is it possible to have perl execute or not execute "use lib" statements based on conditionals? I'm using perl 5.6.1.

Replies are listed 'Best First'.
Re: Dynamic "use lib"
by dragonchild (Archbishop) on May 21, 2004 at 16:16 UTC
    Wrap all the statements above the uses in a BEGIN block. Perl does indeed scan the code for "use" statements prior to anything else, because they are implicitly wrapped in BEGIN blocks.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      That won't work. The compile-time effect of 'use' will not be affected by a run-time 'if' block, even if it's inside a BEGIN. You need to wrap it in an 'eval' inside a BEGIN:

      BEGIN { if ($version =~ /beta/){ eval "use lib('/path/to/dev/modules')"; } else { eval "use lib('/path/to/prod/modules')"; } }

      Or, simpler, just manipulate @INC directly since that's what 'use lib' is doing:

      BEGIN { if ($version =~ /beta/){ unshift @INC, '/path/to/dev/modules'; } else { unshift @INC, '/path/to/prod/modules'; } }

      -sam

        Actually 'use lib' does a little more than just push into @INC (it also considers architecture specific subdirectories) so you may want to use it after all.
        BEGIN { require lib; if ($version =~ /beta/){ lib->import('/path/to/dev/modules'); } else { lib->import('/path/to/prod/modules'); } }
        Now, that makes absolutely no sense. BEGIN blocks are supposed to happen AT compile-time, meaning they happen simultaneous with the use statements.

        Or, does each BEGIN-block get its own BEGIN-CHECK-INIT-END sequence?

        ------
        We are the carpenters and bricklayers of the Information Age.

        Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

        I shouldn't have to say this, but any code, unless otherwise stated, is untested

Re: Dynamic "use lib"
by LTjake (Prior) on May 21, 2004 at 18:48 UTC

    You might check out the if module.

    See "using 'use' conditionally" for mode details.

    --
    "Go up to the next female stranger you see and tell her that her "body is a wonderland."
    My hypothesis is that she’ll be too busy laughing at you to even bother slapping you.
    " (src)

Re: Dynamic "use lib"
by dimar (Curate) on May 21, 2004 at 17:42 UTC

    I have always disliked using BEGIN blocks to achieve dynamic module inclusion. As a workaround, the 'do' command has been useful for me, in combination with 'do-included' files to achieve this kind of functionality. It has worked for me, but I've never seen anyone else use this approach, not sure what you can conclude from that.

    BENEFITS:

    • Since the code calls external files, you can make site-wide changes simply by changing the content of the 'do-included' file. You dont have to re-edit your main scripts.
    • Fewer lines of code in your main script file.
    • You can make as many different 'modes' as you want without adding new lines of code.

    HASSLES:

    • You have to put the 'use' statements in the 'do-included' file, not the main script.
    • Each time you want to make a new 'mode' you have to create a new 'do-include' file.

    foo_main_script.pl

    my $sMode = 'beta'; ### 'beta' or 'prod' do"/path/to/scripts/".$sMode."_modules.pl"; ### insert script code here

    beta_modules.pl

    use lib '/path/to/dev/modules'; use module1; use module2; use module3;

    prod_modules.pl

    use lib '/path/to/prod/modules'; use module1; use module2; use module3;