Getopt::Long is a basic part of the Perl toolset. However one minor nit that Ive had up to now is that specifying the arguments and their destinations, along with defaults seemed a bit clumsy under strict. Take an example from the documentation
use GetOpt::Long;
my $verbose = ''; # option variable with default value (false)
my $all = ''; # option variable with default value (false)
GetOptions ('verbose' => \$verbose, 'all' => \$all);
To me this is inelegant. I have two "declarations" about a variable in separate locations, one the real declaration along with the default value, and the other the association of the option name (which may be different from the variable name) to the variable. If I want to rename a variable for clarity later on I have to change two items. Now perhaps this is blindingly obvious to the rest of you but I just realized that you can instead write this
use GetOpt::Long;
#Adjust bractes and commas to taste
GetOptions (
'verbose' => \(my $verbose = ''),
'all' => \(my $all = ''),
);
Which to me seems preferable. Everything is in one place. It says "this variable normally comes from outside", it puts the declaration of the variable next to the declaration of the option handling it is associated with, and it provides a way to document the whole lot in one place if you need to.
Any thoughts?
---
demerphq
(jeffa) Re: GetOpt::Long usage style
by jeffa (Bishop) on Mar 08, 2003 at 14:06 UTC
|
This kind of redundancy has never really bothered me. I
usually use Getopt::Long in conjunction with Pod::Usage and
my 'skeleton' usually looks like:
use Getopt::Long;
use Pod::Usage;
our ($user,$pass,$numb,$help);
GetOptions(
'user|u=s' => \$user,
'pass|p=s' => \$pass,
'numb|n=i' => \$numb,
'help|h|?' => \$help,
);
$numb ||= 42;
pod2usage(-verbose=>2) if $help;
pod2usage(-verbose=>1) unless $user and $pass;
__END__
Considering that the variables used to hold user options are
being shared across two (or more) packages, this doesn't
seem overly redundant to me. But that's just me. ;)
UPDATE: hmmm, here is something evil:
our ($user,$pass,$numb,$help);
my @tmpl = (
'user|u=s',
'pass|p=s',
'numb|n=i',
'help|h|?',
);
@tmpl = map {"'$_' => \\\$@{[(split('\|',$_))[0]]},"} @tmpl;
eval "GetOptions(@tmpl);";
jeffa
L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
our ($user,$pass,$numb,$help);
my @cmdopt = (
[qw(user u=s)],
[qw(pass p=s)],
[qw(numb n=i)],
[qw(help h ?)],
);
GetOptions(map { +(join '|', @$_) => *{$main::{$_->[0]}}{SCALAR} } @cm
+dopt);
It will even bomb out if your variable and option names mismatch:
Use of uninitialized value in ref-to-glob cast at t.pl line ##.
Can't use string ("") as a symbol ref while "strict refs" in use at t.pl line ##.
Of course, this assumes that the variables live in package main. If you need them elsewhere, the $main:: bit will need adjustment. It is possible to generalize even that bit, but that requires some painful twisting - or disabling the ref stricture.
Makeshifts last the longest. | [reply] [Watch: Dir/Any] [d/l] |
Re: GetOpt::Long usage style
by robartes (Priest) on Mar 08, 2003 at 11:58 UTC
|
Purely from a code clarity and locality point, this is better. It is however a bit difficult to figure out why it works (anything but blindingly obvious, at least to me). Let me try to figure it out for my own good - correct me if I'm wrong:
my $verbose='';
That's easy - $verbose becomes an empty scalar. This is also easy:
(my $verbose='');
This is an empty list (or better, a list containing that particular piece of emptiness referenced by $verbose.
And here comes the hairy part:
\(my $verbose='');
This is a reference to that particular piece of emptiness pointed to by $verbose, hence in a sense (though strictly speaking not) a reference to $verbose. We're basically pointing to the same scalar thingy as $verbose is pointing to, so when GetOpt::Long uses this reference to stash the option value, we can use $verbose to get at that value. Correct?
That is a very neat trick, sir! Despite the minor headache in figuring it out (for me anyway), I think I shall be using it from now on. Perhaps you need to figure out a catchy name for it :) ?
CU Robartes- | [reply] [Watch: Dir/Any] [d/l] [select] |
|
\(my $verbose='');
my returns what has been declared. (Although the behaviour of it as a function is a little interesting, I dont think it can be prototyped, and I can't find complete documentation for it off hand.) The parenthesis required because the precedence of the assignment operator causes
GetOptions(x=>my $x=1,y=>my $y);
to be parsed something like
GetOptions('x',(my $x=1,y=>my $y));
which is a syntax error. They aren't required when the variable isn't initialized as part of the my. Also I personally think that they add visual calrity when the reference to the variable is taken. Since the my returns the variable declared (as an lvalue) we can take a reference to it with \. The reference operator \ can technically go inside the parens or outside in this case as
\($x,$y,$z)
is shorthand for
(\$x,\$y,\$z)
Hope that clarifys things. ;-) Er, and yes. You analysed it correctly. :-)
A couple of related tricks are:
my $txt="Foo bar";
(my $clean=$txt)=~s/oo/u/g;
open my $fh,"File" or die "File $!";
if (my ($x,$y,$z)=/A(..)(..)(..)Z/) { }
---
demerphq
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I know this is ancient, but since it's high on the Google hit list, I wanted to mention one thing...
This very cool trick does not work for @arrays. :-(
This:
use Getopt::Long;
GetOptions(
'single=s' => \(my $single = ''),
'multi=s' => \(my @multi = ()),
);
does *NOT* DWIM. According to "perlref":
As a special case, "\(@foo)" returns a list of references to the contents of @foo, not a reference to @foo itself.
I tried all kinds of permutations, and the best I could come up with was:
use Getopt::Long;
GetOptions(
'single=s' => \(my $single = ''),
'multi=s' => do { use vars '@multi'; \@multi },
);
which, isn't quite as clean, IMHO.
(It *DOES*, however, keep the variable declarations and command-line options on the same line, at least, so you don't have to make changes in multiple places when adding new options. *shrug*) | [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
This is also easy:
(my $verbose='');
This is an empty list (or better, a list containing that particular piece of emptiness referenced by $verbose.
You might call it easy, but it's wrong. Twice. First of all,
parenthesis do NOT make lists. Context makes lists. Parenthesis
are used for precedence.
Furthermore, if the context would demand a list (which in
this case it does), it's not an empty list. How could it be?
There's a scalar inside it. It's a one element list.
Abigail
| [reply] [Watch: Dir/Any] [d/l] |
|
Goes to show again that I feel perfectly comfortable with my foot in my mouth. Thanks for the heads up, demerpq, zby and Abigail-II!
CU Robartes-
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: GetOpt::Long usage style
by mattriff (Chaplain) on Mar 08, 2003 at 18:41 UTC
|
my %opt;
GetOptions(\%opt,'verbose','all');
Sure, $verbose is a few less characters than $opt{verbose},
but for me it's a nice way to separate the data that came
from outside my script.
- Matt Riffle | [reply] [Watch: Dir/Any] [d/l] |
|
Yeah I do use this style as well. However it still presents duplication when you want to provide defaults or multiple names or types for options (which rules out a quick key %opts), in fact its worse because you dont have compile time var name checking of the var names if they get out of synch. In other words the connection between destination and source becomes too loose and it becomes really easy to make a subtle error
my %opt={verbose=>0,all=>0);
GetOptions(\%opt,'talkative|verbose','everything|all');
So what happens if we werent careful and do it like
GetOptions(\%opt,'talkative|verbose','all|everything');
Oops, now the --all options goes to the wrong place.
Anyway, I still would use the %hash style as well for some situations, and as the interface to Getopt::Long is so flexible you can mix the two:
GetOptions(\%opts,'Debug=i'=>\(my $Debug=0),'verbose','all');
And then theres also using subs for the options... Mmm fun!
---
demerphq
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Personally, I tend to keep thingsl ike synonyms in a data structure of their own. So, I might do something like:
my %options = (
verbose => 0,
everything => 1,
);
my %synonyms = (
verbose => [ qw(
talkative
)],
everything => [ qw(
all
)],
);
GetOptions(
\%options,
(
map { join\('|', $_, @{ $synonyms{$_} || []}) } keys %options
),
);
This way you can, at a glance, see exactly what your synonyms are, laid out nice as can be. A similar thing can be done with the "=i", "=s", etc.
------ 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. | [reply] [Watch: Dir/Any] [d/l] |
Re: GetOpt::Long usage style
by Abigail-II (Bishop) on Mar 08, 2003 at 23:11 UTC
|
Assuming that you actually use the variables you can set
with a command line switch, if you rename one of those
variables, you'd need to change the variable at least twice,
even with style you are discussing.
I've used that style for years (but not always), but not
for the reason you mention. Renaming a variable more than
once requires only two keystrokes per extra occurrence in
an editor like vi (n.), so that expect doesn't bother
me at all. Of course, that's assuming :g/$oldvar/s//$newvar/g
wouldn't do the trick, in which case there wouldn't be any
extra keystrokes.
Abigail | [reply] [Watch: Dir/Any] |
|
I suppose tis amatter of coding style, but often the process that occurs is like this: I know I need to handle options, x, y, z and that I want them have defaults. I write the Getoptions code, and then start working on the code that uses those options. If during that process I realize that the names i have chosen for the vars dont have the right names, I change them then and there, once finished the code that uses the vars, (and settling on the right names) I go back and adjust afterwards. Why not search and replace? Usually these vars are lexical for me, and usually I dont want to change every instance at once, yes I could hover on the search/replace button, changing the appropriate ones, but often I dont bother, its less effort to go to the one place in my code that I know is relevent and make he changes by hand, and quickly.
Having said that your suggestions are welcome, but even more welcome would be an explanation of the motivations you had for using this style, and the motivations for not chosing it as well.
Cheers,
---
demerphq
| [reply] [Watch: Dir/Any] [d/l] |
Re: GetOpt::Long usage style
by ihb (Deacon) on Mar 08, 2003 at 19:57 UTC
|
The one thing I don't like about it is that there are variable declarations that aren't at BOL. (There are exceptions to my own rule here. if (my $foo = bar()) { ... } and foreach my $foo (...) { ... } are such. They're special and scope related.)
I want variable declarations to be at BOL because then I easily find them when I need to, like when moving code out to a subroutine. It's also easier to realize what scope my change will be effective in when patching.
But it's quite possible that GetOptions make you realize that you have variable declarations in it, and then it's not an issue (until someone like me wants to patch it ;)).
Besides that; nice touch.
ihb
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: GetOpt::Long usage style
by pg (Canon) on Mar 08, 2003 at 18:28 UTC
|
This is a very nice style, and I will start to use it.
The main point why it works is that, Perl allows you to my variables on fly (you only need to declare it when you need it), and it would be valid all the way to the end of the scope in which it is declared. (In this particular case, we don't see a scope change)
| [reply] [Watch: Dir/Any] |
Re: GetOpt::Long usage style
by hangareighteen (Monk) on Mar 09, 2003 at 17:23 UTC
|
I've always felt that gathering up options for use in any program was rather
inelegant anyways. While it's nice to wrap up declaration, default value,
and paramater value into one convenient statement it seems to pass over the
structure of the problem.
## this is a poorly written demonstrative example
use GetOpt::Long;
my $args = {
verbose => 0, # default false
all => '', # default undef
skip => [], # default empty
};
GetOptions(
'verbose|v' => sub { \$args->{verbose} += 1 },
'debug|d=i' => \$args->{verbose},
'all' => \$args->{all},
'skip|s=s' => sub { push(@{$args->{skip}}, $_[1]) }
);
# get a default from the environment.
$args->{all} = $ENV{FOO_DEFAULT_ALL} unless (defined($args->{all}));
# get a default from a parsed configuration file.
$args->{all} = $rcfile->{foo_default}->{all} unless (defined($args->{a
+ll}));
# get defaults from some arbitrary source.
get_foo_defaults($args);
I like to have all my arguments grouped in one place. In other words, I
really hate using global variables, especially for something like this.
Typically, I'll use a hash reference for convenience. This allows me to
group the arguments, pass them around (and change) them easily, and define
my 'default' values all in once place. Plus I have once place to look to see
what paramaters I expect to keep track of, and one variable to Dump if
necessary.
Most of the time I'm gathering paramaters from other sources as well. Such
as a configuration file, or environment variables, or sometimes even
network sources. So there tends to be more than one place where these values
are getting 'filled-in' anyways, and I'm not always starting with the command
line options. So it seems wasteful to try and make everything line up under
a GetOptions call, especially if you intend to change anything down the line.
Occasionally I enjoy using the subroutine reference 'mode' of GetOpt
to do simple things like incrementing a value depeding on how many times it
appears on the command line, or doing simple paramater validation before it
gets stored to a variable, or even accepting multiple values for a single
paramater. These are really handy sometimes, and lining up all my
declarations under the GetOptions call simply dosen't work -- I'll need to
predeclare a variable anyways.
I also tend to have a few options which modify the same variable anyways,
which also keeps you from getting away with a 1:1 mapping. I like to let the
user set debugging output specifically: '-d 3', as well as incrementally:
'-v -v -v'. So predeclaring my paramater values here is also convenient.
Also, in my own preference, I don't care wether or not the named
paramater 'verbose' actually modifies a variable named 'verbose', it
could well be named 'debug' or 'output_level' or any other name that
makes sence for the context it's being used in. What matters is, the
rest of my program looks for a variable named 'verbose'; the name of
the paramater is really kind of irrelevant -- and is only used once
in once place, whereas the value is used in multiple places.
It all comes down to personal preference, and necessity, I guess. And
my preferences and needs have resulted in my using a structure similar to
the above almost exclusively. That's just me, though. | [reply] [Watch: Dir/Any] [d/l] |
|
how to set variables to default values...if user doesn`t specifies using Getopt::Long???
| [reply] [Watch: Dir/Any] |
Re: GetOpt::Long usage style
by hsmyers (Canon) on Mar 09, 2003 at 08:05 UTC
|
Under the general heading of 'ever so slightly embarrassing' I would admit to having to stick opt_ as a prefix to my GetOpt::Long variables---I attribute this to too many years as a machine code morlock (i.e. too many globals) That aside I like your reasoning and results, will adopt forthwith!!
--hsm
"Never try to teach a pig to sing...it wastes your time and it annoys the pig." | [reply] [Watch: Dir/Any] |
|
|