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

Hi Monks,

While I was searching for examples related to Getopt::Long I came across this code http://perlbuzz.com/mechanix/2008/05/use-getoptlong-even-if-you-don.html that I just cannot figure out.

use Getopt::Long; GetOptions( 'user=s' => \$user, 'password=s' => \$pass, forms => sub { push( @actions, \&dump_forms ); }, links => sub { push( @actions, \&dump_links ); }, images => sub { push( @actions, \&dump_images ); }, all => sub { push( @actions, \&dump_forms, \&dump_link +s, \&dump_images ); }, absolute => \$absolute, 'agent=s' => \$agent, 'agent-alias=s' => \$agent_alias, help => sub { pod2usage(1); }, ) or pod2usage(2);

This is what I've added and what I'm working with:

use strict; use warnings; use Getopt::Long; my ($user, $pass, $absolute, $agent, $agent_alias, $forms ); my @actions; GetOptions( 'user=s' => \$user, 'password=s' => \$pass, forms => sub { push( @actions, \&dump_forms ); }, links => sub { push( @actions, \&dump_links ); }, images => sub { push( @actions, \&dump_images ); }, all => sub { push( @actions, \&dump_forms, \&dump_link +s, \&dump_images ); }, absolute => \$absolute, 'agent=s' => \$agent, 'agent-alias=s' => \$agent_alias, help => sub { pod2usage(1); }, ) or pod2usage(2); print "$user\n"; print "$pass\n"; $actions[dump_forms()]; sub dump_forms { my @vars = @_; print "@vars\n"; print "we're now in dump_forms\n";}

In particular, where | how | why would I use forms => sub { push( @actions, \&dump_forms ); }, ? I mean why would I want to push a subroutine to an array? Also, I can't seem to get the parameters passed to my  sub dump_forms {

Here's example output

$ ./mygetopt3.pl --user fred --password password --forms a Useless use of array element in void context at ./mygetopt3.pl line 35 +. fred password we're now in dump_forms
Thank-you for your consideration.

UPDATE

I was asked below about what I'm trying to do, why I didn't look at the examples from mech-dump and why I'm using the command line options that are geared more for mech-dump.
I suppose the questions were asked somewhat in a rhetorical sense but since monks were kind enough to respond to my question, I thought I'd provide context.
The long answer is that I'd asked a couple of questions What's the best way to make my script execute different sections without using goto? and Adding a dispatch table and getting "Variable $x will not stay shared" errors. over the last few weeks about how to have multiple actions in a script. Mostly the responses pointed to Getopt::Long. But I couldn't figure out from Getopt::Long how to make it work. Yes I know that's lame because now that I understand how it works, it's dead simple. So I went on a quest to find examples and http://perlbuzz.com/mechanix/2008/05/use-getoptlong-even-if-you-don.html was one of the only google matches out of the first 30 that didn't point me right back to the docs at Getopt::Long. Being desperate and frustrated I used that as my guide and when I looked at ack or prove I didn't see the examples for using Getopt::Long.
The one place I didn't look was the source for mech-dump, which as it turns out, does explain it so that I could have understood it.
What's crazy is that I was thinking about writing a tutorial and just found that one already exists Parsing your script's command line that I didn't see previously despite searching a few different times.
So I hope that provides a little context and is useful to someone. And I really do appreciate the help and advice.

Replies are listed 'Best First'.
Re: Getopt::Long. forms => sub { push( @actions, \&dump_forms ); },
by ikegami (Patriarch) on Mar 12, 2009 at 04:49 UTC

    I mean why would I want to push a subroutine to an array?

    To create a list of actions to take once the program has finished being configured. These actions can be executed as followed:

    $_->() for @actions;
Re: Getopt::Long. forms => sub { push( @actions, \&dump_forms ); },
by ELISHEVA (Prior) on Mar 12, 2009 at 05:14 UTC

    Code never stands in isolation - when a text says it is drawing its code from somewhere and the code doesn't make sense on its lonesome, the first thing to do is to look up the code.

    The article you are reading drew its code from mech-dump as it states: "Take a look at prove or ack for examples. mech-dump is pretty decent as an example as well:...". It even gave you a link to the code in question so you could see it in context. So the first help I can give is to suggest you look up the source code (either via the link given in the article or via CPAN).

    The list of options is not magic - they reflect the command line syntax for a specific command. Unless you are trying to reproduce the command mech-dump, your command line and list of options should look entirely different. Which brings me to a question of my own: why are you using the command line options for mech-dump? If as a learning exercise I would start with a simpler set of options. When you can get that working, experiment with additional features. If you would update your question to tell what features you are trying to learn about GetOpt::Long, perhaps we might be able to suggest a better sequence of learning problems.

    As for your second question, "why push a function onto an array?", that too will be made clearer reading the code for mech-dump. Each of the options --forms, --links, --images is a boolean flag. mech-dump uses these flags to tell what code is needed to carry out the user's wishes.

    It could, of course, set a boolean variable to true whenever the flag is set and then use that boolean variable in an if statement. However, the author of mech-dump probably anticipated that the list of optional actions might change. Or maybe he didn't want to maintain a long sequence of if..elsif.... So instead, everytime a flag is set, the code for handling the flag is added to the list of optional bits of code to exectute. The subroutine is the optional code needed to extract images or whatever. The array holds a list of subroutine references to the optional code.

    As you read through the mech_dump source code you may find it instructive to look for the place where the array is being used. Using an array to hold optional bits of code is a good pattern to learn and mech_dump is a fairly simple example of good production use of that pattern.

    Best, beth

Re: Getopt::Long. forms => sub { push( @actions, \&dump_forms ); },
by Marshall (Canon) on Mar 12, 2009 at 10:35 UTC
    I am answering a bit of a different question than what you asked because I'm not sure what you are really trying to do?

    I would suggest before launching off into one of the more complex modules and its implementation of Getopt::Long, that you play around with and learn the basics of how to use the Std version of Getopt (one option letter) - that's the way that thousands of unix programs have been written and you can go a long way with this!

    I personally haven't needed the long version of getopts yet. "Yet" doesn't mean never will need it, it just means not yet.

    I don't know how much you know about what the purpose of these things are. I'll summarize perhaps as useful info for others:
    1. Parse the @ARGV list (I guess that's obvious!)
    2. Identify problems with the comand line grammar. A missing parameter or an invalid option.
    3. Put the option and its optional arg into a structure that is easy for the program to use
    4. Remove everything that it knows about from @ARGV! There can be things on the command line that are not options! After getopts is finished @ARGV will have what is left over. Maybe its a regex pattern, or some filename that has to be there or whatever. The important part is that the getopts thing will remove the stuff that it knows about which simplifies whatever you have to do with what is left in @ARGV. This perhaps is one of the most important parts about what these getopts things do!

    Ok, so here some simple code for a hypothetical DB application. The important parts for the program:
    1. check that getopts has no error (it will have an error if an illegal option is found)
    2. check that the number of things left in @ARGV is what you expect. In code below it is zero.
    3. check that the number of options is consistent with what you expect, here only one option is allowed.
    4. if there is the possibility of inconsistent options, check that too! Maybe we can't add and delete at the same time or whatever!

    In the below, getopts takes a "grammar" statement which says that -a and -s have to be followed by a parameter and that -l (the list option) takes no parameter. If there is say a "-x", getopts will return false. So we check the return value. Next we see if what has happened to @ARGV is what we expected. In this case, nothing should be in the list. Then we check if the number of options is what we expected. In this case, I only allowed one option at a time as this is a simple example. If there are incompatible options, say -x and -y, then you should check that the aren't both present. BTW, if -l doesn't take a parm, $opts{l} = 1.

    It is possible to build what I would call "dispatch tables", that call subs based upon some list of "list of things to do". All of that is a separate discussion from getopts(). There are very good reasons to do that(and I have programs that do exactly that - great for GUI I/F where the user can select a whole bunch of things, but might not understand what the interaction is going to be). But you shouldn't be worried about some few "if" statements! Performance of an "if" statement is so fast that this doesn't matter below.

    use Getopt::Std; my %opts; die "Usage: $0 -a file | -s state | -l\n". "-a adds to database (or create), -s lists state -l lists whole D +B\n" if (!getopts("a:s:l", \%opts) || @ARGV !=0 || keys %opts !=1; Add() if $opts{a}; ListState() if $opts{s}; ListAll() if $opts{l}; sub ListState { ...use $opts{s} here, the state name.... }