2

Based on the solution provided in Test for existence of perl mod inside script, I came up with the following test:

my @mods = (qw(Cwd DBI Date::Calc Term::ReadLine File::Copy Digest::Perl::MD5
               LWP::Simple Switch POSIX Text::LevenshteinXS File::Spec
               File::Basename String::CRC32 MIME::Lite IO::Socket::INET));

foreach my $mod (@mods) {
    ( my $fn = "$mod.pm" ) =~ s|::|/|g;    # Foo::Bar::Baz => Foo/Bar/Baz.pm
    if ( eval { require $fn; 1; } ) {
        print "Module $mod loaded ok\n";
    } else {
        print "Could not load $mod. Error Message: $@\n";
    }
}

When I originally just had use something, I also sometimes had imports, which I now find will not work with require, i.e.:

use Digest::Perl::MD5 'md5_hex';

After the @mods test, I would like to load them, so:

require Cwd;
require DBI;
require Date::Calc;
require Term::ReadLine;
require File::Copy;
require Digest::Perl::MD5 'md5_hex';
require LWP::Simple;
require Switch;
require POSIX;
require Text::LevenshteinXS qw(distance);
require File::Spec;
require File::Basename;
require String::CRC32;
require MIME::Lite;
require IO::Socket::INET;

But this throws an error on run:

syntax error at ./mod.pl line 78, near "require Digest::Perl::MD5 'md5_hex'"
syntax error at ./mod.pl line 82, near "require Text::LevenshteinXS qw(distance)"

How can I do this?

EDIT: For anyone else who stumbles upon this thread later on, here's the working code:

use strict;

$| = 1;

################################################
# Help user if Perl mods are missing
################################################
my @mods = (qw(DBI Date::Calc Term::ReadLine File::Copy Digest::MD5 LWP::Simple Text::LevenshteinXS File::Spec String::CRC32 MIME::Lite IO::Socket::INET Getopt::Long));

foreach my $mod (@mods) {
    ( my $fn = "$mod.pm" ) =~ s|::|/|g;    # Foo::Bar::Baz => Foo/Bar/Baz.pm
    if ( eval { require $fn; 1; } ) {
        ##print "Module $mod loaded ok\n";
    } else {
        print "You are missing a required Perl Module: $mod\n";
        my $ok = &getYN( "Shall I attempt to install it for you?", "y" );
        if ( $ok =~ /[Yy]/ ) {
            require CPAN;
            CPAN::install($mod);
        } else {
            print "LogZilla requires $mod\n";
            exit;
        }
    }
}

use feature "switch";
use Cwd;
use File::Basename;
use POSIX;
require DBI;
require Date::Calc;
require Term::ReadLine;
require File::Copy;
require Digest::MD5->import("md5_hex");
require LWP::Simple;
require Text::LevenshteinXS->import("distance");
require File::Spec;
require String::CRC32;
require MIME::Lite;
require IO::Socket::INET;
require Getopt::Long;

my ($autoyes);

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;
}
Community
  • 1
  • 1
Clayton Dukes
  • 1,297
  • 2
  • 11
  • 30
  • Cwd, File::Spec, File::Basename, even POSIX are core modules. Having said that, Switch was once a core module and isn't any more, but that is quite unusual. (And Digest::MD5 is a core module; why do you prefer Digest::Perl::MD5?) – Jonathan Leffler Apr 07 '12 at 15:03
  • 2
    I am not clear what you are trying to achieve. If you simply `use` all the modules at the start of the program you will get an error message telling you if one is unavailable. Please explain. – Borodin Apr 07 '12 at 16:11
  • @JonathanLeffler - no reason, just lack of knowledge on my part. – Clayton Dukes Apr 07 '12 at 17:43
  • Would [Module::Find](https://www.metacpan.org/module/Module::Find) do what you want? – brian d foy Apr 08 '12 at 04:20
  • 1
    Concentrate on solving new problems, rather than reinventing the wheel: `use Test::More; use_ok($_) foreach qw(your modules here);` You could also use `'try_load_class'` from [Class::Load](http://metacpan.org/module/Class::Load). – Ether Apr 08 '12 at 16:24

1 Answers1

9

You need to call the modules' import method, e.g.

Digest::Perl::MD5->import("md5_hex");
Text::LevenshteinXS->import("distance");

use Module is exactly equivalent to

 BEGIN { require Module; Module::->import( LIST ); }
ikegami
  • 367,544
  • 15
  • 269
  • 518
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • Thanks. This works. Now, when I run my code, Switch is acting like it isn't loaded: String found where operator expected at ./install.pl line 90, near "case 'update_paths'" – Clayton Dukes Apr 07 '12 at 18:04
  • Figured out an alternative to Switch http://perldoc.perl.org/perlsyn.html#Switch-statements and it works well. thanks! – Clayton Dukes Apr 07 '12 at 18:12
  • @Clayton Dukes, Did you remove the `BEGIN`? It sounds like you loaded the module after you needed it (at compile-time). – ikegami Apr 07 '12 at 21:13
  • @eugene y, it's not *exactly* equivalent. (Try doing `sub Module;` before them.) Fixed so they are. – ikegami Apr 07 '12 at 21:16