interesting perl problem

geoff on 2004-04-02T15:52:21

so, someone asked me today if there was a way in perl to accomplish something bizarre. I didn't have a quick answer, yet the problem seemed sufficiently interesting that I thought I'd post it here...



say you have script.pl that defines package Foo. now, for complex legacy reasons, your stuck with this and need to call script.pl both from the command-line as well as

require "script.pl"; 
Foo->import;


how do you create a chunk of code that only executes from the command-line and not when script.pl is loaded or imported?



I might be missing something obvious, but the only thing I could come up with was requiring some random command-line argument and checking @ARGV. apparently that's not an option.


just off the top of my head

jhorwitz on 2004-04-02T16:17:27

  • end the script with a false value like "0;" -- that will prevent 'require' and 'use' from successfully loading it
  • write your own import handler that just throws an error

Re:just off the top of my head

geoff on 2004-04-02T16:24:58

well, the idea is that require(), etc is ok and in fact required. the problem is that the mainline code in the script needs to be suppressed when calling require(). for instance:
#!/usr/bin/perl

print "I should only print when '$ perl script.pl' ;

package Foo;

# lots of stuff that is ok to be pulled in via 'require "script.pl"

Re:just off the top of my head

jhorwitz on 2004-04-02T16:28:49

okay, now i see why this is painful. this will require some more gears to turn in my brain.

Re:just off the top of my head

jhorwitz on 2004-04-02T16:44:12

well, now all i can think of is checking $ARGV[0] for the script name. simple, but certainly not elegant or bulletproof.

perhaps...

jmm on 2004-04-02T16:51:38

off the top of my head, no warrantee, YMMV, IANAL,... ...

my $imported = 0;

sub import { ... ++$imported; ... }

END { unless( $imported ) { # script code goes here } }

Re:perhaps...

jmm on 2004-04-02T17:02:09

Drat, it looked fine when I previewed it, but the ECODE got lost somehow. Trying again:
...

my $imported = 0;

sub import {
    ...
    ++$imported;
    ...
}

...

END {
    unless( $imported ) {
        # script code goes here
    }
}

Will caller() do what you need?

wnodom on 2004-04-02T17:10:07

Try this:

#! /usr/bin/perl -w
#
# script.pl
#

if (scalar caller)
    {
        print "Called via a sub, eval, or require.\n";
    }
else
    {
        print "Called directly.\n";
    }

print "Within script.pl\n";


You could get fancier with caller() if you need to, but I think this will do the trick.

There's more info in this recent journal entry by brian.

--Bill

Re:Will caller() do what you need?

chromatic on 2004-04-02T17:49:45

Yep; that's exactly the trick in Pod::ToDemo.