Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Conditional module use

by Nkuvu (Priest)
on Apr 21, 2006 at 18:46 UTC ( [id://544962]=perlquestion: print w/replies, xml ) Need Help??

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

Forgive me monks, for I have been slacking. It has been far too long since I wrote a useful Perl script. My Perl skills are a bit rusty, and I've super searched with overwhelming results. That is, too many results, I couldn't find what I needed (I searched for BEGIN, eval, and require).

I'm attempting to update a script to request a password from a user. The current implementation has the password sent in on the command line in clear text. I'd like to make it so that the password is not echoed to the screen, which is simple enough using Term::ReadKey. The problem is that the script will be used on multiple machines, and I can't guarantee that the module will be installed. I can't even guarantee that the version of Perl installed will be greater than 5.6 or so. So rather than have someone install a module on each machine (which is feasible, really, just not my preferred route) I'd like to warn the user if their password is going to be echoed. And not die if the module is not installed, of course.

I wrote a very quick hack of a script to see if I could get this to work:

#!/usr/bin/perl use strict; BEGIN { eval { require Term::ReadKey; }; }; my $use_readkey = 1 unless $@; print "Enter a secret message", (not $use_readkey ? " (NOTE: message will be visible)" : ''), ": "; if ($use_readkey) { Term::ReadKey::ReadMode 2; } my $secret = <STDIN>; if ($use_readkey) { Term::ReadKey::ReadMode 0; } print "\nYour message: $secret\n"; print "More typing, to verify normal input echo: "; my $answer = <STDIN>; print "You said: $answer\n";

On a machine with Term::ReadKey installed, it works just fine. But a machine without Term::ReadKey fails with the following:

Number found where operator expected at try.pl line 15, near "Term::Re +adKey::ReadMode 2" (Do you need to predeclare Term::ReadKey::ReadMode?) Number found where operator expected at try.pl line 19, near "Term::Re +adKey::ReadMode 0" (Do you need to predeclare Term::ReadKey::ReadMode?) syntax error at try.pl line 16, near "Term::ReadKey::ReadMode 2" syntax error at try.pl line 20, near "Term::ReadKey::ReadMode 0" Execution of try.pl aborted due to compilation errors.

It's the end of a long week, and I've spent a few hours looking at various require and BEGIN nodes. I'm not seeing why this would fail, and I've used similar Perl code in other scripts (requiring a different module). I'm sure I'm missing something obvious.

Replies are listed 'Best First'.
Re: Conditional module use
by ikegami (Patriarch) on Apr 21, 2006 at 19:15 UTC

    Once you fix the problem identified by gaal, a runtime error will be revealed. $@ is no longer set when you get around to executing $use_readkey's initialization, as shown in the following snippet:

    BEGIN { eval { die }; print($@ ? 1 : 0, "\n"); # 1 } print($@ ? 1 : 0, "\n"); # 0

    Change

    BEGIN { eval { require Term::ReadKey; }; }; my $use_readkey = 1 unless $@;

    to (minimal change)

    or (simpler)

    or (even simpler, but done at compile time)

    my $use_readkey = eval { require Term::ReadKey };

    Update: There's yet a third error.
    not $use_readkey ? ... : ...
    means
    not ($use_readkey ? ... : ...)
    Use
    !$use_readkey ? ... : ...
    or
    (not $use_readkey) ? ... : ...
    Operator precedence is documented in perlop. Note that
    ! has higher precedence than ?:, and
    not has lower precedence than ?:.

Re: Conditional module use
by gaal (Parson) on Apr 21, 2006 at 19:13 UTC
    Try

    Term::ReadKey::ReadMode(2); ... Term::ReadKey::ReadMode(0);

    The parens help Perl disambiguate subroutine call vs. method invocation.

      That works perfectly, thank you.

      But I'm a little unclear on the reason. What's the difference between a subroutine and a method in Perl?

        I don't know what gaal was thinking, but that's not it. The problem is that Term::ReadKey::ReadMode in Term::ReadKey::ReadMode 2; is a bareword unless you load Term::ReadKey. With strict enabled, Perl gives a warning instead of trying to disambiguate what you meant.

        For this reason, a lot of people recommend always using parentheses around all subroutine and method call arguments.

Re: Conditional module use
by hesco (Deacon) on Apr 21, 2006 at 19:40 UTC
    Or you might consider the Test::More package with its use_ok method, or which package is it that has the ->can method? Off the top of my head. Thanks for the heads up about Term::Readkey. That looks useful. I might could use that. -- Hugh
Re: Conditional module use
by strat (Canon) on Apr 22, 2006 at 10:06 UTC

    Btw: IO::Prompt should be an easier alternative

    Best regards,
    perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (7)
As of 2024-04-23 10:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found