0

Based on the answer provided here, I am attempting to validate whether or not a perl module is installed. For this, I have:

# &getYN and &prompt are only included here for completeness
sub getYN {
    unless ( $autoyes =~ /[Yy]/ ) {
        my ( $prompt, $default ) = @_;
        my $defaultValue = $default ? "[$default]" : "";
        print "$prompt $defaultValue: ";
        chomp( my $input = <STDIN> );
        return $input ? $input : $default;
    } else {
        return "Y";
    }
}

sub prompt {
    my ( $prompt, $default ) = @_;
    my $defaultValue = $default ? "[$default]" : "";
    print "$prompt $defaultValue: ";
    chomp( my $input = <STDIN> );
    return $input ? $input : $default;
}

&chklib("RRDTool::OO");
sub chklib {
    my $lib = shift;
    eval { require $lib; };
    if ($@) {
        print "You are missing a required Perl Module: $lib\n";
        my $ok = &getYN( "Shall I attempt to install it for you?", "y" );
        if ( $ok =~ /[Yy]/ ) {
            require CPAN;
            CPAN::install($lib);
        } else {
            print "Installation requires $lib\n";
            exit;
        }
    }
}

This runs as expected, but for some reason, the eval returns that I don't have RRDTool::OO installed, when, in fact, I do.

If I create an empty file and run:

# File foo.pl
use strict;

$| = 1; 

use RRDTool::OO;

Then I get no errors.

But when I run the first file with print $@;, it returns:

Can't locate RRDTool::OO in ...

What am I doing wrong?

Community
  • 1
  • 1
Clayton Dukes
  • 1,297
  • 2
  • 11
  • 30

2 Answers2

2

You have to check the result of the eval, like

if (eval("require xxx;")) {
     print "you have it\n";
} else {
     print "you don't\n";
}
ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
  • 1
    And you can check the docs on "require" to see why the quotes are helpful in this case: http://perldoc.perl.org/functions/require.html – oalders Apr 04 '12 at 17:22
  • @oalders yes, I've done it thinking about xxx written as "the right thing" (without even asking myself what it would be): I was just pointing the way I would check if eval is successful or not. – ShinTakezou Apr 04 '12 at 17:29
  • 1
    @ShinTakezou Sorry, I meant the comment to be for the OP and not for you. I just wanted to point out that I didn't think his example would work without the quotes, which you correctly supplied in your answer. :) – oalders Apr 04 '12 at 18:09
  • Hmm, now that it is working. If I add a use blah: after the check, the script still fails. How do I test for it, install it and then use it after it is installed? – Clayton Dukes Apr 04 '12 at 20:26
  • @ClaytonDukes At this point your script has compiled, so you'll need a second "require" rather than a "use". – oalders Apr 05 '12 at 03:09
  • @ClaytonDukes You may also want to have a look at https://metacpan.org/module/Class::Load – oalders Apr 05 '12 at 11:39
2

What is happening is that

$lib = "RRDTool::OO";
eval { require $lib }

is executed with the stringified expression

require "RRDTool::OO"

not the bareword style

require RRDTool::OO

so it is looking for a file called RRDTool::OO in your @INC path instead of a file called RRDTool/OO.pm.

If you want to use require at run-time with a variable expression, you'll want to either use the stringy form of eval

eval "require $lib"

or process the arg to require yourself

$lib = "RRDTool::OO";
$lib =~ s{::}{/}g;
eval { require "$lib.pm" }
mob
  • 117,087
  • 18
  • 149
  • 283