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

I'm pretty inexperienced with perl but I'm trying to broaden my experience by writting a build process in perl. I have the script divided into sub routines which vary from compiling the code to publishing it to the server. I would like to be able to call a sub routine from the command line when I run the script so that I can just run the one part of the script (such as the compile part).

I thought I could use ARGV but it doesn't seem to work the way I've written it.

if (@ARGV == "clean"){ print "cleaning up dirs"; clean(); }
Where the clean() function would be called if the user types clean from the command line when the script runs.

Does anyone know a better way to do this? Thanks

edit (broquaint): added formatting

Replies are listed 'Best First'.
Re: using a sub routing as an argument
by Zaxo (Archbishop) on Jun 22, 2004 at 23:19 UTC

    Your clean routine will never run unless @ARGV does not contain "clean" or anything else. @ARGV in scalar context will evaluate to the number of elements in @ARGV ( that's the reason perl doesn't have or need $ARGC). The '==' comparison puts its arguments in numeric context. The numification of 'clean' is zero. Therefore you will call clean() only if @ARGV is empty.

    You can detect the presence of build targets with grep {$_ eq $target} @ARGV or by @hash{@ARGV} = (); clean() if exists $hash{'clean'};, or you can have a look at the Getopt family of modules.

    ExtUtils::MakeMaker is really very good at this sort of thing; it relies on make to do the heavy lifting. The trouble is that POSIX-standard make is not shipped with some OS and that many authors use gnu make extensions that other makes (standard or not) do not understand.

    After Compline,
    Zaxo

Re: using a sub routing as an argument
by FoxtrotUniform (Prior) on Jun 22, 2004 at 23:30 UTC
    if (@ARGV == "clean"){ print "cleaning up dirs"; clean(); }

    @ARGV is a list of command-line parameters. What you probably want to do is check the first of these parameters:

    if($ARGV[0] eq "clean") { # eq, not ==, for strings print "cleaning up dirs"; clean(); }
    instead of comparing "the list".

    A more advanced issue (feel free to skip this bit for now, while you get your code working) is that code like this (a huge chain of if..elsif...elsif...else) is likely to be difficult to maintain, if only because large blocks of code are daunting to mess with. Instead, I'd suggest building a dispatch table. First, write a bunch of handler functions, for instance:

    sub clean_handler { print "cleaning up dirs"; clean(); } sub make_handler { print "making project"; make(); } # ...
    Next, build a hash of these handlers, keyed on the commands:
    my %cmds = ( 'clean' => \&clean, # reference to the subroutine 'clean' 'make' => \&make, # reference to 'make' # ... );
    Now, when you get a command, retrieve the handler function from the %cmds hash and call it:
    my $cmd = $cmds{$ARGV[0]}; # get the coderef &$cmd(); # call it

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    % man 3 strfry

Re: using a sub routing as an argument
by NetWallah (Canon) on Jun 23, 2004 at 04:01 UTC
    I think what you are looking for is "Dispach Subroutines".

    Here is an example...

    #Setup a Dispach table.... command => \&Dispatch_Sub my %cmd = (clean=> \&Clean , quit=> \&Quit); my $entry=shift; # Get user input from @ARGV or Elsewhere #This is the Main dispatch. # First - check to see if the user command is valid. # If so, Dispatch (Call the corresponding sub). If not, complain. $cmd{$entry} ? $cmd{$entry}() : print qq/no such comand $entry\n/; sub Clean{ # This is the called DISPACH sub print qq/Running clean\n/; } sub Quit{ exit; }

    Earth first! (We'll rob the other planets later)

Re: using a sub routing as an argument
by Anonymous Monk on Jun 22, 2004 at 23:29 UTC
    @ARGV is an array, so if you want to look at the arguments passed to the program, you look at $ARGV[0], $ARGV[1], $ARGV[2], etc. (for the first, second, third, etc. paramaters)
Re: using a sub routing as an argument
by data64 (Chaplain) on Jun 23, 2004 at 00:58 UTC

    Other's have pointed out why the construct you are trying to use is not quite right. I would like to point out that for what you are trying to do (read command-line parameters) you should also consider using one of the GetOpt::* modules from cpan eg: GetOpt::Long.


    Just a tongue-tied, twisted, earth-bound misfit. -- Pink Floyd

Re: using a sub routing as an argument
by broquaint (Abbot) on Jun 23, 2004 at 02:36 UTC
    This is a perfect opportunity to take advantage of can e.g
    &$_ for map { __PACKAGE__->can($_) || () } @ARGV;
    That map provides the for with a list of subroutines that exist in the current package whose names correspond to the values in @ARGV.
    HTH

    _________
    broquaint

Re: using a sub routing as an argument
by gitarwmn (Beadle) on Jun 23, 2004 at 17:51 UTC
    Great suggestions, thanks. I'm learning more everyday.