Chris Dolan wrote:
Advice? While this example is contrived, the "eval { require ... }" idiom is used often in the wild, so this is not a wholly unrealistic scenario.

Real-world example. SVN::Web uses this idiom to determine whether to use CGI or CGI::Fast.

Even if CGI::Fast is installed it can still fail is FCGI.pm is missing.

Normally this isn't a problem, since if you're running as a CGI script you only do this test once. The first time around trying to load CGI::Fast it fails.

But... if you then think "Ah, I'll use HTTP::Server::Simple to provide an easy way for people to test SVN::Web" then this doesn't work, as the request triggered (that code's going away soon) a second C<require CGI::Fast;> which succeeds.

To work around it you have to delete the relevant key from %INC if you detect that the require failed the first time.

Here's an example (which assumes you have CGI::Fast installed, but not one of its dependencies).

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $r = 0;

  foreach (1..2) {
      foreach my $module (qw(CGI::Fast)) {
          $r = eval "require $module;";
          $r = 0 unless defined $r;
          if($@ and $ARGV[0]) {
              my $path = $module;
              $path =~ s{::}{/}g;
              $path .= '.pm';
              delete $INC{$path};
          }
          print "$module: $r\n";
      }
  }

Run that and see:

  CGI::Fast: 0
  CGI::Fast: 1

indicating that the second time around the loop the 'require' worked.

Pass a true value as the first command line argument to exercise the if() block, and see:

  CGI::Fast: 0
  CGI::Fast: 0

to force the second 'require' to fail.

N

Reply via email to