in reply to Detecting broken modules

adds the modules it finds to %INC whether or not they can be fully compiled..

Prove it

Replies are listed 'Best First'.
Re^2: Detecting broken modules
by ELISHEVA (Prior) on Jun 29, 2009 at 22:30 UTC
    I knew someone would ask that question. :-)

    Sample broken module:

    use strict; use warnings; $x=1;

    Sample code using string eval (the above example from Anonymous dies before the print statement because it uses a constant module name within the non-string eval form and hence is fully evaluated at compile time.)

    my $sFile = 'Monks/Foo/Bar.pm'; my $result = eval("require Monks::Foo::Bar"); my $error = $@; print "=== Eval results ===\n"; print "result=<". (defined($result)?$result:'undef') .">\n\$@=<". (defined($error)?$error:'undef') .">\n"; print "=== Contents of %INC ===\n"; print "\$INC{$sFile}=<" . (defined($INC{$sFile}) ? $INC{$sFile} : 'undef') . ">\n";

    Which outputs

    === Eval results === result=<undef> $@=<Global symbol "$x" requires explicit package name at Monks/Foo/Bar +.pm line 3. Compilation failed in require at (eval 1) line 3. > === Contents of %INC === $INC{Monks/Foo/Bar.pm}=<Monks/Foo/Bar.pm>

    Q.E.D.

    Best, beth

    P.S. Using eval { $result=require($sFile); } yields the same output, so its not just the string version of eval.

    Update: scripts run on Perl 5.8.8

      What version of Perl are you using? I get the same results as you on an old box with 5.8.4 installed, but on my main box with 5.10.0, I get different results: $INC{module.pm} is undef if require module dies, and calling require module a second time fails.

      In both versions, I can trick the require into trying again, and producing the original error message for me, simply by wrapping my own call in a little localisation:

      { local %INC = %INC; delete $INC{$sFile}; $result = eval "require Monk::Foo::Bar"; $error = $@; }

      Though, on reflection, that has obvious issues for modules that really don't want to be loaded more than once, so maybe it's not a good idea.

      I'm not convinced :) but the argument could be made that strict/warnings is throwing an exception after module loaded OK

        This isn't strictly a warnings issue but it may be exception related. Pure compilation errors also will leave %INC populated with the module.

        If Foo::Bar loads without compilation errors but its final statement evaluates to 0 in its last line, then $INC{$file} is undefined:

        use strict; use warnings; 0;

        Outputs

        === Eval results === result=<undef> $@=<Monks/Foo/Bar.pm did not return a true value at (eval 1) line 3. > === Contents of %INC === $INC{Monks/Foo/Bar.pm}=<undef>

        But if it contains a reason for a compilation error (i.e. no warnings) then $INC{$file} is defined, even if the final line is 0. If, the whole file were in fact being processed and an exception thrown after the fact, I would expect undef as above. If, for example, Foo::Bar contains merely:

        { 0;

        the output is

        result=<undef> $@=<Missing right curly or square bracket at Monks/Foo/Bar.pm line 2, +at end of line syntax error at Monks/Foo/Bar.pm line 2, at EOF Compilation failed in require at (eval 1) line 3. > === Contents of %INC === $INC{Monks/Foo/Bar.pm}=<Monks/Foo/Bar.pm>

        I don't know where to look for the source code for "require" without having to download a tarball and grepping my way through it (my google efforts found only the tarballs), but my best guess looking at the pseudocode in require is that some internal implementation of do? is dying when it finds a compilation error. I'm assuming there is some internal implementation because even though do returns undef, a compilation error causes do to set $@ to the compilation error message. Require maybe is calling this internal method but isn't trapping that properly. As a result the code that clears %INC is not being processed. But this is just a guess. Someone with internals knowledge would be better equipped to answer it.

        Best, beth

        Update: scripts run on Perl 5.8.8

Re^2: Detecting broken modules
by Anonymous Monk on Jun 29, 2009 at 22:22 UTC
    BrokenModule.pm
    package BrokenModule; $BrokenModule::VERSION='BROKEN'; 0;
    test.pl
    #!/usr/bin/perl -- use strict; use warnings; eval q{ use BrokenModule; 1 } or warn $@; eval q{ use BrokenModule; 1 } or warn $@; eval { require BrokenModule; 1 } or warn $@; eval { require BrokenModule; 1 } or warn $@; print $_,$/ for grep /BrokenModule/, %INC; __END__ BrokenModule.pm did not return a true value at (eval 1) line 1. BEGIN failed--compilation aborted at (eval 1) line 1. BrokenModule.pm did not return a true value at (eval 2) line 1. BEGIN failed--compilation aborted at (eval 2) line 1. BrokenModule.pm did not return a true value at test.pl line 8. BrokenModule.pm did not return a true value at test.pl line 9.