Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

[SOLVED] Using eval: $@ isn't returning the error I expect

by doctormelodious (Acolyte)
on Feb 19, 2020 at 22:38 UTC ( [id://11113193]=perlquestion: print w/replies, xml ) Need Help??

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

EDIT: SOLVED! The eval was not only formatted incorrectly, it needed to be in a BEGIN block, due to the nature of the module's use by the host server. Thanks for all the help!

----

Greetings,

The host server where our intracompany site lives requires this on one of our CGI scripts:

use cPanelUserConfig;

My local machine is running its own Apache server, and I use it to test code. However, it doesn't have cPanelUserConfig installed. It's a pain to have to remember to comment that line out when I'm testing locally and then uncomment it before I upload it to the host server. So I tried this:

eval{"use cPanelUserConfig;"}; unless($@){use cPanelUserConfig}

The problem is that, even though that Perl module is not installed, $@ is empty, so the "use cPanelUserConfig" tries to execute and the script dies.

Any suggestions for making this work?

Thanks!

Replies are listed 'Best First'.
Re: Using eval: $@ isn't returning the error I expect
by haj (Vicar) on Feb 19, 2020 at 23:01 UTC

    The reason why this fails is that use statements are always evaluated at compile time, even if in a conditional. You could just drop the unless line because if the eval succeeds, then the module is actually loaded.

    However, in such a situation I'd just add my own dummy cPanelUserConfig somewhere into my include path and get rid of that ugly string eval in production which would silently hide any errors in the real cPanelUserConfig module.

      Hi haj,

      Thanks for the reply!

      >>I'd just add my own dummy cPanelUserConfig somewhere into my include path

      How would I go about doing that?

        Just create a file named cPanelUserConfig.pm that contains a single line of:
        1;
        Place that file in one of the @INC directories.
        You can get a list of those directories by running:
        perl -le "print for @INC;"
        Cheers,
        Rob
Re: Using eval: $@ isn't returning the error I expect
by haukex (Archbishop) on Feb 20, 2020 at 00:05 UTC

    I see a couple of issues here:

    • pryrt pointed out that you're using eval BLOCK syntax with a single string inside the block, that's basically like writing "use cPanelUserConfig;" in your code, i.e. it has no effect, and warnings would have told you "Useless use of a constant ("use cPanelUserConfig;") in void context". Always Use strict and warnings!
    • haj pointed out that unless($@){use cPanelUserConfig} will always attempt to load the module. There's the if.pm pragma, but in this case a simple eval "use cPanelUserConfig;" (that's an eval STRING) would be enough to either load the module or not.
    • The pattern of checking $@ after an eval is unfortunately common, but it has issues: Bug in eval in pre-5.14.

    All in all, since it sounds like you only need to load the module or not, and not actually use any of its functions (?), I would have gone with: eval "use cPanelUserConfig; 1" or warn "Didn't load cPanelUserConfig: $@";.

      need to load the module or not, and not actually use any of its functions (?)

      cPanelUserConfig sets up library paths for modules installed using the cPanel interface -- basically a series of use lib ...; necessary if the script uses any non-core modules that you've installed on your shared hosting server

        Exactly. The script in question uses a module I installed on the shared server, so cPanelUserConfig must be used for the script to work in that environment -- but not on my local server, where all the modules are in the same place. Thanks!

      Thanks, haukex. I tried this:

      eval "use cPanelUserConfig; 1" or warn "Didn't load cPanelUserConfig: $@";

      as a replacement for the explicit "use" command:

      use cPanelUserConfig;

      and it ran fine on my own machine, but failed on the host server because on that machine cPanelUserConfig is required in order that a different module be loaded after cPanelUserConfig is loaded. (They treat user-installed modules differently from modules that are part of their default setup.) It would seem that the "eval" command isn't actually loading the cPanelUserConfig module on the host server. Only the explicit "use" statement seems to work there.

        It would seem that the "eval" command isn't actually loading the cPanelUserConfig module on the host server. Only the explicit "use" statement seems to work there.

        If it's not showing a warning, then it is loading it, but there's a difference: eval STRING delays the execution of the use until runtime, while normally it would run at compile time. Try adding a BEGIN { ... } block around the whole line, that'll move the execution back into compile time (see BEGIN in perlmod).

Re: Using eval: $@ isn't returning the error I expect
by pryrt (Abbot) on Feb 19, 2020 at 23:05 UTC
    This might help:

    $ perl -le 'eval { "use gobbledygook;" }; print "ok"' ok $ perl -le 'eval { use gobbledygook; }; print "ok"' Can't locate gobbledygook.pm in @INC ... $ perl -le 'eval "use gobbledygook;"; print "msg = ($@)" if $@; print + "ok"' msg = (Can't locate gobbledygook.pm in @INC ...) ok

    What you were doing was evaluating the code (the braces make it a code block) that contains a non-empty string; the non "0", non-empty string evaluates true, and the eval block doesn't error, so $@ doesn't get set. What you need to do is either evaluate block of real code in braces, or evaluate a string, not evaluate a string inside a block of code. The second and third in my example both try to use the module; the first (equivalent to your code) does not try to load the module.

      Thanks, pryrt

      I tried this:

      $ perl -le 'eval "use cPanelUserConfig;"; print "msg = ($@)" if $@; print "ok"'

      and got this error:

      syntax error at /Library/WebServer/CGI-Executables/orders/orderFormSalesDisplayPreRollout.cgi line 13, near "$ perl "

      I don't think I'm correctly translating what you typed, into a literal line for my script. Can you tell me what I'm doing wrong? Thanks again.

        The $ perl -le ... indicates that this is a command typed at the command line (as a demo), not something you should simply copy & paste into your script as a whole line - the code is inside the single quotes after the -e switch here (see also perlrun).

Re: Using eval: $@ isn't returning the error I expect
by 1nickt (Canon) on Feb 19, 2020 at 22:47 UTC

    Hi, try

    use Module::Load eval { autoload 'cPanelUserConfig'; 1 } or do_something_else();

    Hope this helps!


    The way forward always starts with a minimal test.
      Thanks, 1nickt

      I tried this:

      use Module::Load; eval { autoload 'cPanelUserConfig'; 1 } or print "toast";

      and got this error:

      syntax error at /Library/WebServer/CGI-Executables/orders/orderFormSal +esDisplayPreRollout.cgi line 15, near "autoload 'cPanelUserConfig'" Execution of /Library/WebServer/CGI-Executables/orders/orderFormSalesD +isplayPreRollout.cgi aborted due to compilation errors.

      When I commented out the eval statement, the script ran, which would indicate that Module::Load is indeed installed.

      Thanks again!

        use Module::Load; eval { autoload 'cPanelUserConfig'; 1 } or print "toast";

        This code works fine for me. Are you sure this is exactly the code you tried?

        Also, just to make sure, tell us what version of Perl and the module you're using, as given by perl -MModule::Load -le 'print $]; print $Module::Load::VERSION' (on the command line).

Re: Using eval: $@ isn't returning the error I expect
by doctormelodious (Acolyte) on Feb 20, 2020 at 00:52 UTC

    Seems that after a certain number of indented replies, the text of mine stop showing up on this page. There are just grey rectangles saying that I replied, and I have to click the links therein to actually read them. I'm assuming that's standard for the format used here, yes?

    Anyhoo, thanks for the help, everyone. Problem solved! (The eval was not only formatted incorrectly, it needed to be in a BEGIN block, due to the nature of its use by the host server).

      In your home node, follow the Settings link ("Edit your: Profile, Settings").

      Under "User Settings" (which should come up automatically) there's a table with "Note Configuration" in the bottom lefthand corner. Change the values for "Replies header depth:" and "Replies text depth:" to suit.

      — Ken

        Ah, that's what I was looking for. Thank you!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (None)
    As of 2024-04-25 01:05 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found