http://www.perlmonks.org?node_id=472212

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

Learned monks,

I'd like to prevent modules from being loaded.

Many Perl modules are built on top of other modules, and some even acknowledge that There Is More Than Way To Do It by offering different implementations depending on what helper modules are present. For writing test cases that trigger all possible choices, I would like to pretend that certain modules are not available.

The documentation for require states that require works similar to

if (exists $INC{$filename}) { return 1 if $INC{$filename}; die "Compilation failed in require"; }
which led me to believe that I could do
use strict; BEGIN{ $INC{'CGI.pm'} = undef; } use CGI;
But that does not work. While the module (CGI) is not loaded, the code does not die as it should.

Replies are listed 'Best First'.
Re: Simulating the absence of a module
by gellyfish (Monsignor) on Jul 04, 2005 at 12:55 UTC

    It's evil and bad and I'm sure there are many reasons why you don't want to do this, but you can use a CODEREF in @INC to do something like:

    BEGIN { @main::OINC = @INC; unshift @INC, sub { if ( $_[1] eq 'CGI.pm') { @INC = ($_[0]); } else { @INC = ($_[0], @main::OINC); } + return undef; + }; } + use strict; use CGI;

    /J\

      That's clever. Thanks++;
Re: Simulating the absence of a module
by grinder (Bishop) on Jul 04, 2005 at 16:33 UTC
    I would like to pretend that certain modules are not available.

    I'm doing something like this for the next version of Regexp::Assemble. In trying to improve the coverage of my test suite, I handled it slightly differently.

    I use eval to load modules in the module, and set package variables to 1 or 0 according to whether I succeed or not. From there, I have conditional code that runs one way or another in the module, according to that result.

    In the test suite, I can simply use local to override the variable, and the module then thinks that the module is loaded one instant, and then isn't the next, all in the same run.

    In the main module:

    use vars '$have_Storable'; $have_Storable = do { eval { require Storable; import Storable 'dclone'; }; $@ ? 0 : 1; }; # ... # code predicated on the setting of $have_Storable

    Now in the test suite, I test stuff as usual, and to ensure I test both code paths exercised according to whether Storable is loaded or not, I just do something like this:

    { local $Regexp::Assemble::have_Storable = 0; my $orig = Regexp::Assemble->new->add( qw/ dig dug dog / ); my $clone = $orig->clone; is_deeply( $orig, $clone, 'clone path' ); }

    If someone else installs my module and they don't have Storable installed, they'll just exercise the same codepath twice. I don't really care about that. But as the module author, I'll see if I mess up when my coverage statistics decline. That's good enough for me.

    Another example of the dictum "any computer problem can be solved with another level of indirection".

    - another intruder with the mooring in the heart of the Perl

Re: Simulating the absence of a module
by brian_d_foy (Abbot) on Jul 05, 2005 at 05:44 UTC
Re: Simulating the absence of a module
by anonymized user 468275 (Curate) on Jul 04, 2005 at 14:06 UTC
    Perhaps the reason this $INC{'CGI.pm'} = undef; does not work is that it is overridden by @INC (the list of paths to search for the modules).

    If you want to disable a module, the simple way is to write a dummy for it - perhaps others know a way to (shudder) hack the symbol table instead. To change preferences you could re-order the @INC array in the BEGIN block.

    One world, one people

Re: Simulating the absence of a module
by Mutant (Priest) on Jul 04, 2005 at 16:35 UTC
      I think Test::MockObject is what you're looking for.

      Nope. T::MO is about faking existing packages, not pretending a package doesn't exist.

        You can use it for that purpose though. See the tutorial on perl.com.
Re: Simulating the absence of a module
by jhourcle (Prior) on Jul 04, 2005 at 15:02 UTC

    What exactly are you trying to do?

    This sounds as if you have a problem, you've selected a solution, but then come up problems in implementing the solution.

    You're trying to 'pretend that certain modules are not available', but if you explain why you're trying to do this (ie, what the original problem was), people might be able to give other, potentially better, alternatives.

      What exactly are you trying to do?

      I thought the OPs

      For writing test cases that trigger all possible choices, I would like to pretend that certain modules are not available.

      was pretty clear :-)

      Test::Without::Module is one way.

      Personally I thought:

      For writing test cases that trigger all possible choices, I would like to pretend that certain modules are not available.
      was quite explanatory.

      /J\