Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Avoid using a module if it's not available

by perfluffle (Initiate)
on Jun 12, 2008 at 17:51 UTC ( [id://691741]=perlquestion: print w/replies, xml ) Need Help??

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

Hi - I've been knocking my head against this for hours now, and I can't seem to get it right. (v5.8.8 from Activestate on Windows XP).

I have a list of modules I want to use, but only if they're available (i.e. installed on the system the script is running on and included in @INC). If they're not available, I want the code that calls them to be skipped. Installing them isn't an option, period. Oh, how I wish it were, but it's not.

Here is an example (line numbers added for clarity):
000: my $fname = $ARGV[0]; 001: open(FILE, $fname) or die "Can't open file!"; 002: 003: my $can_foo=1; 004: eval "use FOO::bar"; 005: if($@) { $can_foo=0; } #Don't try to use if unavailable 006: 007: #later on in the program, maybe multiple times. 008: 009: if ($can_foo) { 010: my $foobarzlot=sprintf("%d,",bar(FILE)->zlot); 011: print "FOOBARZLOT=".$foobarzlot."\n"; 012: }
My goals are:
1. Avoid a compile-time error when FOO::bar is unavailable. The "eval" in line 004 prevents this quite nicely.
2. Avoid a run-time error on line 010 when FOO::bar is available.

I'm not doing so well with the second objective. Everything I've tried seems to result in a run time error like "Can't call method "zlot" without a package or object reference at foobarzlot.pl line 10." Yet, FOO:bar is right there on the development system and should return a valid "zlot" with no problem at all. If I put the use (or require) statement outside the eval, everything works perfectly. Unfortunately, having no influence on what's installed on the target system(s), it's virtually guaranteed that some systems will barf at compile time.

P.S. If you replace FOO::bar with File::stat and zlot with size, you'll get a better idea. I just didn't want people to get hung up on the choice of module. I have about ten different modules I need to use or not-use based on availability.

Replies are listed 'Best First'.
Re: Avoid using a module if it's not available
by linuxer (Curate) on Jun 12, 2008 at 18:23 UTC

    This works for me without a bad message:

    #!/usr/bin/perl # vi:ts=4 sw=4 et: use strict; use warnings; my $fname = $ARGV[0]; my $scan_foo = 1; eval "use File::stat"; if ( $@ ) { $scan_foo = 0; } if ( $scan_foo ) { my $foobarzlot = sprintf("%d", File::stat::stat($fname)->size ); print "FOOBARZLOT=" . $foobarzlot . $/; } __END__

    update1: 1st answer removed due to bad reading of OP

    update2: adjusted code to better match original code example

Re: Avoid using a module if it's not available
by psini (Deacon) on Jun 12, 2008 at 18:27 UTC

    Sorry, it works for me.

    If I execute your code exactly as you wrote it I obtain>

    Name "main::FILE" used only once: possible typo at ./x.pl line 4.

    I avoided this adding a "close FILE;" at the end and it works w/o errors.

    If I substitute FOO::bar with the name of an existing module (namely Data::Dumper) and the conditional code with

    if ($can_foo) { print Dumper(undef); }

    I get:

    $VAR1 = undef;

    which is correct too.

    Perhaps the problem you get is NOT independant from which module you try and load.

    Careful with that hash Eugene.

Re: Avoid using a module if it's not available
by jacques (Priest) on Jun 12, 2008 at 22:29 UTC
    use HTML::Perlinfo::Modules; my $m = HTML::Perlinfo::Modules->new(); my $module = $m->print_modules( show_only => qr/FOO::bar/i ); if ($module) { my $foobarzlot=sprintf("%d,",bar(FILE)->zlot); print "FOOBARZLOT=".$foobarzlot."\n"; }
    Note that it is very easy to look up multiple modules by simply adding them to the precompiled regular expression. For example:
    my $modules = $m->print_modules( show_only => qr/FOO::bar|File::Which| +File::stat/i );
Re: Avoid using a module if it's not available
by ww (Archbishop) on Jun 12, 2008 at 23:20 UTC

    Maybe I'm looking at this the wrong way, but your comment,

    I have a list of modules I want to use, but only if they're available (i.e. installed on the system the script is running on and included in @INC). If they're not available, I want the code that calls them to be skipped. .... I have about ten different modules I need to use or not-use based on availability.

    has me perplexed.

    What will your script do (aside from skipping calls) when it runs on a system lacking the modules?

    Are you going to reinvent the wheel for each missing module (on who knows how many systems)? Are you going to lift the code from pure perl, non-core modules and insert it in your package? Is one of those or some other workaround in your plan, so your script will function without regard to the target system's lack of one or more of your ten modules.

    And how do you plan to distribute your script? (My suspicion is that if you can distribute it and have the sysadmin/owner agree to employ it, you can find a means to get the missing modules installed.)

    In short: You've stated your perceived problem clearly, but is it the real problem? (Cf: jdporter's excellent XY Problem.

      I found this node while looking for a way to do exactly what the OP is trying to do, and I believe there are legitimate reasons to do such a thing.

      For example, sometimes you want to use whichever XML parsing module is available.

      Or maybe you want to provide enhanced functionality to people who have some special module installed. Term::ReadLine, for example, lets people on GNU systems do more stuff.

      I need additional modules to reliably guess stuff; my script asks the user for confirmation anyway, so if a good guess is not available — it's not a huge problem, we'll just ask the user.

Re: Avoid using a module if it's not available
by ady (Deacon) on Jun 13, 2008 at 05:39 UTC
    Hmmm, since you're on Windows with Active State Perl, I'd recommend perl_dev_kit/deploy as a means to solve your issue of asserting the presence of all needed modules for your application on all target pc's for your distribution.

    That's the way I do it. --Best regards,
    allan dystrup
Re: Avoid using a module if it's not available
by QM (Parson) on Jun 13, 2008 at 15:08 UTC
    A different example, maybe it will help. My script gets used by others on different platforms. Since Windows/DOS doesn't glob the way *nix does, this module isn't necessary on *nix.
    # This BEGIN block avoids including File::DosGlob::Param for non-windo +ws systems BEGIN { if ( $^O =~ /win/i ) { require File::DosGlob::Param; import File::DosGlob::Param qw( dosglob ); } } # convert filename wildcards to actual filenames if ( $^O =~ /win/i ) # only if DOS { if ( exists( $INC{'File/DosGlob/Param.pm'} ) ) # only if loaded { dosglob( "Array_Ref" => \@ARGV, "Remove_Empty_Matches" => 1, "Warn_On_Empty_Matches" => 1 ); } END { if ( ( $^O =~ /win/i ) and not exists( $INC{'File/DosGlob/Param.pm'} ) ) { warn "Consider installing module File::DosGlob::Param...\n"; } } }

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://691741]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2024-04-19 12:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found