Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Possible to have a module act as a standalone??

by snafu (Chaplain)
on Mar 18, 2003 at 21:42 UTC ( [id://244162]=perlquestion: print w/replies, xml ) Need Help??

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

I've rewritten a script that works very similar to pidof for the use as a support script for a set of scripts.

I have written it as a standalone script because that is what it was before. However, I started thinking that it would be really cool to be able to call it as a module from another script as well as being able to use it from command line. The name of the script right now is 'npid'. Now, if npid had a package statement then simply detected its caller() (not sure if I can do that yet...gotta look up the docs on caller()) then I am thinking that this kind of thing is feasable. If the caller is a parent script then it works by returning the data to the caller and the caller prints it. Otherwise, it prints output in another format.

I am thinking that this would be the best way to go about this because if I call npid as a module then I'm not wasting resources on another instance of the interpretter while at the same time I am allowing the user to use this program from CLI without calling the support scripts to use it.

Is there something I am missing? Is this possible? Is it recommended? What are the snags?

_ _ _ _ _ _ _ _ _ _
- Jim
Insert clever comment here...

Replies are listed 'Best First'.
Re: Possible to have a module act as a standalone??
by BrowserUk (Patriarch) on Mar 18, 2003 at 22:49 UTC

    I think that including a test script into the same file as a module (and its pod) is a good idea (I said as much in RFC: Runnable test code integrated into Modules.), and now do this regularly in my own modules. If that test code happened to be useful standalone, then it is serving two possible uses which seems like a good thing to me.

    A short example of doing this is a module I originally wrote to see if I could profile regexes Re: Profiling regular expressions. It now looks like this.

    E:\Perl\site\lib\My>type Filter.pm #! perl -slw package My::Filter; use Filter::Simple; use Benchmark::Timer; our $t = Benchmark::Timer->new(); FILTER_ONLY regex => sub { $_ = "(?{{ \$My::Filter::t->start('$_$/') }})" . "(?:$_)" . "(?{{ \$My::Filter::t->stop('$_$/') }})"; }, ; sub report{ return $t->report() } return 1 if caller(); use strict; use My::Filter; my $stuff = 'abcdefghijklmnopqrstuvwxyz'; for (1..1000) { if ( $stuff =~ m[pqr] ) { $stuff =~ s/(\G(?:.{3})+?)(?<=...)(.)(.)/$1$3$2/g; } $_ = $stuff; my $OK = 1 if m[pqr]; } print $stuff; print '=' x 20, 'Timing of regexs in ', $0, '=' x 20; print My::Filter::report();

    It can be run standalone like this

    E:\Perl\site\lib\My>perl Filter.pm Subroutine report redefined at E:/Perl/site/lib/My/Filter.pm line 16. abcdefghijklmnopqrstuvwxyz ====================Timing of regexs in Filter.pm==================== 2000 trials of pqr (260.000ms total), 130us/trial 5000 trials of (\G(?:.{3})+?)(?<=...)(.)(.) (640.000ms total), 128us/trial

    Or used from a script like this.

    C:\test>perl -MMy::Filter -e"$s='abc'; print 'ok' if $s =~ m[b]; print + My::Filter::report();" ok1 trial of b (0s total) C:\test>

    The only downside is having to switch to the directory where the module lives or specify the full path to in order to invoke it standalone, but there are several ways around that.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Possible to have a module act as a standalone??
by perrin (Chancellor) on Mar 18, 2003 at 22:44 UTC
    Separate your data from its presentation. Put the code that does the actual program logic in a module, and then call it from either a standalone script or a CLI script. Make it simply return data and not print anything. Then the standalone script and CLI script get to decide how they want to display the data that is being returned.

      Bravo. That is precisely what I think dragonchild was trying to suggest without spelling it out explicitly (as in: "if I think it through fer ye, ya won't learn nuthin'").

      It's how I interpreted the original question as I read it, as well.

      There seems to sometimes be a tendency amongst (us) developers/programmers/technocrats to overcomplicate, at least in my case, in the sense that the obvious can be overlooked in favor of a literal interpretation that misses the point. Being guilty of the same, however, does not preclude being able to detect when it happens to someone else. Nay, it can make it stand out sometimes (we must all remember "it takes one to know one" from childhood).

      It seems to me that asking some questions implies a need for understanding of the realm that the answers might take, and lacking that understanding, the question may understandably suggest to an otherwise knowledgable individual, an unintended specificity that is not actually there.

      In this case, the original poster snafu seems (to me) to be asking how to write a block of code in such a way that it may be used as a module (e.g., using user by a larger program and also standalone. The answer as I would deliver it is that it should be written as a module, with an entry point (sub) written to accept what might be command-line arguments. Then, a trivial command-line script (i.e., shell) could be written in several lines which simply loads the module and passes its comand-line arguments directly into the sub, without manipulating them.

      My .02 ...

      dmm

Re: Possible to have a module act as a standalone??
by dragonchild (Archbishop) on Mar 18, 2003 at 21:46 UTC
    You're thinking about the problem wrong. A module isn't anything more than a collection of (possibly) related functions (and maybe some data). Perl doesn't actually have support for "modules", per se. There are packages and there are files. Most of the time, the "One package, one file" rule tends to hold, so those things are often called modules.

    What I understand you wanting to do is to have a set of functionality that can return its output in 2 different ways. Ok - have the functions in the module accept a flag that determines what it should do with that data.

    Then, you have your CLI thingy do its thing and you have a stand-alone script that does its thing. (The stand-alone script will, most likely, be extremely short, but that's a good thing.)

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

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      Hmmm... I read this as him wanting a way to write, say, Npid.pm (for lack of a better name) such that a script can "use Npid;" and the right thing happens, but he can also do (from the command-line) "perl Npid.pm" and the right thing also happens.

      --rjray

        You're correct - that was the actual question. The question presupposes an incorrect analysis of whatever problem he's attempting to solve. I could've given him an answer to his problem (cause this is a do-able thing), but he would not have grown as a programmer. The analysis of the problem was wrong. Ultimately, that is a goal of PerlMonks. (At least, that's how I've come to see this community.)

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

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      Whoa there. It sounds like he's trying to do what they do in java /w main()
Re: Possible to have a module act as a standalone??
by zengargoyle (Deacon) on Mar 18, 2003 at 23:44 UTC

    while do-able, doing so makes life much more complicated for your users.

    you want a module that can be run as a script, but the search paths for scripts (OS determined) and modules (Perl determined) are different. if it's in a place where it could be run as a script, then it can't be loaded as a module w/o hackery. ditto for the reverse, if it's in a place where it could be loaded as a module (use Foo;) then it's not in a place where it could be called as a script.

    create a module Foo.pm in the usual place. write a small foo wrapper script to put in the OS's search path.

    this doesn't stop you from placing the script code in the module. infact it's probably wise to do so.

    # Foo.pm package Foo; ... sub foo { for (@_) { Foo->new($_)->blah->print; } } 1; #!/usr/bin/perl # Foo wrapper script use Foo; Foo::foo(@ARGV);

    i can't see a way around having two files when you want to be able to do 'foo "blah"' from the command line and 'use Foo;' in perl.

      you want a module that can be run as a script, but the search paths for scripts (OS determined) and modules (Perl determined) are different. if it's in a place where it could be run as a script, then it can't be loaded as a module w/o hackery. ditto for the reverse, if it's in a place where it could be loaded as a module (use Foo;) then it's not in a place where it could be called as a script.
      Jigga-what? There is nothing saying that @INC and your PATH environment variable have to be disjoint. I'm not saying that it's a good idea to have overlap (nor am I saying that it's a bad idea; kinda titilating, actually), but you could put a new directory that is understood to contain such hybrid scripts at the end of both @INC and PATH:
      push @INC, "/path/to/hybrids" setenv PATH $PATH:/path/to/hybrids export PATH=$PATH:/path/to/hybrids ...
      You get the idea.

      thor

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (7)
As of 2024-03-19 03:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found