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

Dual personality: Module and script

by Anonymous Monk
on Aug 03, 2004 at 14:45 UTC ( [id://379666]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,
I want a module to detect if it was loaded by "require" or "system". Can this be done in elegant way, or just adding and checking different argument passed by the caller?

More info.

I have working programs, where a Perl script, loaded from command line, will later "require" a module, and jump to a subroutine inside the module, and the rest of the package thereafter.

I checked that Perl will run a .pm script from command line, not neccessary have to be .pl.

I want to add to the .pm file more code that will only be executed if loaded from command line or "system" because I want to share most of the code in the module. The functionality of the module should stay as before. So I guess I need an "if statemt" at the beginning to check who was calling, but check what? :(

I am on Windows XP, Active State v5.8.3 built for MSWin32-x86-multi-thread

Thanks.

Replies are listed 'Best First'.
•Re: Dual personality: Module and script
by merlyn (Sage) on Aug 03, 2004 at 15:11 UTC
    If I read you correctly (and it is still early in the morning here), you want caller:
    caller EXPR caller Returns the context of the current subroutine call. In sca +lar context, returns the caller's package name if there is a c +aller, that is, if we're in a subroutine or "eval" or "require", +and the undefined value otherwise. [....]
    So, unless (defined caller) { ... } will execute that code if it's being brought in as the main level of the program, rather than a module.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Dual personality: Module and script
by tachyon (Chancellor) on Aug 03, 2004 at 15:07 UTC

    As pointed out you really don't want to do this, but here is how anyway* ;-) This only works if you use the module not if you require if as when you use a module the modules import() method is called at the start of proceedings. This is not true for require when import is not called.

    package MyModule; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT $MOD_CALL ); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = qw( func1 ); sub func1 { return reverse @_ } sub import { $MOD_CALL++; } CHECK{ print $MOD_CALL ? "Called as a module\n" : "Called as a script\ +n" } 1;

    On the rare occasions I have made a module a stand alone executable (usually for all the wrong laziness reasons) I have just used the presence of values in @ARGV to initiate script like behaviour. Generally you want to pass some data to a script anyway......

    if ( @ARGV ) { print "I'm a script!\n"; # do stuff exit 0; } # only get to here if you we are a module

    * Recall the story about getting enough rope to hang yourself?

    cheers

    tachyon

Re: Dual personality: Module and script
by BrowserUk (Patriarch) on Aug 03, 2004 at 22:34 UTC

    I do this all the time. Nearly all my modules have the skeleton:

    #! perl -slw package MyPackage; ... return 1 if caller; package main; use Devel::StealthDebug; our $ITERS ||= 10; our $OTHER ||= 'default'; ## run test code here

    That allows me to embed the unit test code for the module directly into the module itself, keeping it all together.

    The testcode then also serves as sample code for users (should any of my half-baked ideas ever get refined enough that I feel able to let it loose on the world :).


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Dual personality: Module and script
by eserte (Deacon) on Aug 03, 2004 at 15:53 UTC
    I usually use the following code lines:
    package My::Module; use Getopt::Long; sub process { local @ARGV = @_; # handle command line or named parameter options: GetOptions(...) or die ...; # here follows the rest of the script } return 1 if caller; # This is executed only in "script" mode: process(@ARGV); # In "module" mode I have to write: # use My::Module; # My::Module::process(-bla => "foo", ...)
    Of course there are variations of these scheme possible --- you just need the "return 1 if caller" line to distinguish between module code and script-only code.
Re: Dual personality: Module and script
by dragonchild (Archbishop) on Aug 03, 2004 at 14:56 UTC
    It sounds like you're trying to be too clever. Modules are generally meant to be sourced in from other entities, like scripts. I wouldn't have executable modules, personally.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      In the Python world, the sentiment is exactly the opposite. I remember reading in "Programming Python" this common idiom:
      #!/usr/bin/env python # module mymod2.py def cube(n): return n ** 3 # when 'import'ed, __name__ is 'mymod2' # when executed, __name__ is '__main__' if __name__ == '__main__': if cube(15) != 3375: print "Error, cube(15) is not correct"
      _____________________________________________________
      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Dual personality: Module and script
by bgreenlee (Friar) on Aug 03, 2004 at 15:23 UTC

    You could also check the value of $0. If your module is executed rather than imported, it will return the name of the module. Otherwise it will return the name of the script that imported it.

    Brad

      Thank everybody for the replies.

      I was looking to what user bgreenlee replied.
      I do not think it is that terrible to have, on occasion and for private use,
      a module that is "require" as this is more similar to DLL,
      that can also be started from command line or "system"

      Solution works like charm.
      If loaded as stand alone, the suffix is .pm. If 'required' then the suffix is .pl all that is needed then
      if ($0 =~ /\.pm$/i) { # execute stand alone ) # fall thru for module.
      Thanks again for all replies.

        Of course, that's also the least robust solution of the four.

        Makeshifts last the longest.

Re: Dual personality: Module and script
by Fletch (Bishop) on Aug 03, 2004 at 14:56 UTC

    The Parse::RecDescent does somthing similar to this with its import mechanism to generate a precompiled dump of a grammar. You might look at what it does.

Re: Dual personality: Module and script
by fergal (Chaplain) on Aug 03, 2004 at 15:23 UTC
    Here's a solution that works with require and use. Assuming it's saved in mod.pm
    print "I'm a ".($INC{"mod.pm"} ? "module" : "script")."\n";
    output is
    fergal@linux:~> perl mod.pm
    I'm a script
    fergal@linux:~ perl -e 'require mod'
    I'm a module
    
Re: Dual personality: Module and script
by TomDLux (Vicar) on Aug 04, 2004 at 02:30 UTC

    I too have occassionally hidden test code in my modules, though not as cleanly as BrowserUK

    In the fine tradition of TMTOWTDI, note that $0 doesn't change, but __FILE does, as you go from x.pl to x.pm, whether by 'use' or by 'require'.

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-04-19 21:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found