[commits] [Wiki] created: Doc/Dev/HordeArgvAdvanced
Jan Schneider
jan at horde.org
Mon Feb 4 19:02:58 UTC 2013
jan Mon, 04 Feb 2013 20:02:58 +0100
Created page: http://wiki.horde.org/Doc/Dev/HordeArgvAdvanced
+ Horde_Argv
[[toc]]
++ Advanced Usage
This is reference documentation. If you haven't read the
((Doc/Dev/HordeArgv|Basic Usage)) tutorial document yet, do so now.
+++ Creating and populating the parser
There are several ways to populate the parser with options. One way is
to pass a list of {{Horde_Argv_Option}}s to the {{Horde_Argv_Parser}}
constructor:
<code type="php">
$parser = new Horde_Argv_Parser(array('optionList' => array(
new Horde_Argv_Option(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')),
new Horde_Argv_Option(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose'))
)));
</code>
For long option lists, it's often more convenient/readable to create
the list separately:
<code type="php">
$option_list = array(
new Horde_Argv_Option(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')),
// ... 17 other options ...
new Horde_Argv_Option(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose'))
);
$parser = new Horde_Argv_Parser(array('optionList' => $option_list));
</code>
Or, you can use the {{addOption()}} method of {{Horde_Argv_Parser}} to
add options one at a time:
<code type="php">
$parser = new Horde_Argv_Parser();
$parser->addOption(
'-f', '--filename',
array('action' => 'store', 'type' => 'string', 'dest' => 'filename')
);
$parser->addOption(
'-q', '--quiet',
array('action' => 'store_false', 'dest' => 'verbose')
);
</code>
This method makes it easier to track down exceptions raised by the
{{Horde_Argv_Option}} constructor, which are common because of the
complicated interdependencies among the various keyword arguments --
if you get it wrong, //Horde_Argv// throws an
{{!InvalidArgumentException}}.
{{addOption()}} can be called in one of two ways:
* pass it an {{Horde_Argv_Option}} instance
* pass it any combination of positional and keyword arguments that are
acceptable to {{new Horde_Argv_Option()}} (ie., to the
{{Horde_Argv_Option}} constructor), and it will create the
{{Horde_Argv_Option}} instance for you (shown above)
+++ Defining options
Each {{Horde_Argv_Option}} instance represents a set of synonymous
command-line options, ie. options that have the same meaning and
effect, but different spellings. You can specify any number of short
or long option strings, but you must specify at least one option string.
To define an option with only a short option string:
<code type="php">
new Horde_Argv_Option('-f', ...)
</code>
And to define an option with only a long option string:
<code type="php">
new Horde_Argv_Option('--foo', ...)
</code>
The ... represents a set of keyword arguments that define option
attributes, i.e. attributes of the {{Horde_Argv_Option}} object. Just
which keyword args you must supply for a given {{Horde_Argv_Option}}
is fairly complicated (see the various {{_check*()}} methods in the
{{Horde_Argv_Option}} class if you don't believe me). If you get it
wrong, //Horde_Argv// throws an {{!InvalidArgumentException}}
explaining your mistake.
The most important attribute of an option is its action, ie. what to
do when we encounter this option on the command-line. The possible
actions are:
: {{store}} : store this option's argument [default]
: {{store_const}} : store a constant value
: {{store_true}} : store a {{TRUE}} value
: {{store_false}} : store a {{FALSE}} value
: {{append}} : append this option's argument to a list
: {{count}} : increment a counter by one
: {{callback}} : call a specified function
: {{help}} : print a usage message including all options and the
documentation for them
(If you don't supply an action, the default is {{store}}. For this
action, you may also supply {{type}} and {{dest}} option attributes;
see below.)
As you can see, most actions involve storing or updating a value
somewhere. //Horde_Argv// always creates an instance of
{{Horde_Argv_Values}} (referred to as options) specifically for this
purpose. Option arguments (and various other values) are stored as
attributes of this object, according to the {{dest}} (destination)
option attribute.
For example, when you call
<code type="php">
$parser->parseArgs();
</code>
one of the first things //Horde_Argv// does is create the options object:
<code type="php">
$options = new Horde_Argv_Values();
</code>
If one of the options in this parser is defined with
<code type="php">
new Horde_Argv_Option('-f', '--file', array('action' => 'store',
'type' => 'string', 'dest' => 'filename'))
</code>
and the command-line being parsed includes any of the following:
<code>
-ffoo
-f foo
--file=foo
--file foo
</code>
then //Horde_Argv//, on seeing the "-f" or "--file" option, will do
the equivalent of this:
<code type="php">
$options->filename = 'foo';
</code>
Clearly, the {{type}} and {{dest}} arguments are almost as important
as {{action}}. {{action}} is the only attribute that is meaningful for
all options, though, so it is the most important.
+++ Option actions
The various option actions all have slightly different requirements
and effects. Most actions have several relevant option attributes
which you may specify to guide //Horde_Argv//'s behaviour; a few have
required attributes, which you must specify for any option using that
action.
* {{store}} [relevant: {{type}}, {{dest}}, {{nargs}}, {{choices}}]
> The option must be followed by an argument, which is converted to a
> value according to {{type}} and stored in {{dest}}. If {{nargs}} >
> 1, multiple arguments will be consumed from the command line; all
> will be converted according to {{type}} and stored to {{dest}} as an
> array. See the "Option types" section below.
> If {{choices}} is supplied (an array of strings), the {{type}}
> defaults to {{choice}}.
> If {{type}} is not supplied, it defaults to {{string}}.
> If {{dest}} is not supplied, //Horde_Argv// derives a destination
> from the first long option strings (e.g., "--foo-bar" implies
> "foo_bar"). If there are no long option strings, //Horde_Argv//
> derives a destination from the first short option string (e.g., "-f"
> implies "f").
> Example:
<code type="php">
$parser->addOption('-f');
$parser->addOption('-p', array('type' => 'float', 'nargs' => 3, 'dest'
=> 'point'));
</code>
> Given the following command line:
> {{-f foo.txt -p 1 -3.5 4 -fbar.txt}}
> //Horde_Argv// will set
<code type="php">
$options->f = 'foo.txt';
$options->point = array(1.0, -3.5, 4.0);
$options->f = 'bar.txt';
</code>
* {{store_const}} [required: {{const}}; relevant: {{dest}}]
> The value {{const}} is stored in {{dest}}.
> Example:
<code type="php">
$parser->addOption('-q', '--quiet', array('action' => 'store_const',
'const' => 0, 'dest' => 'verbose'));
$parser->addOption('-v', '--verbose', array('action' => 'store_const',
'const' => 1, 'dest' => 'verbose'));
$parser->addOption('--noisy', array('action' => 'store_const', 'const'
=> 2, 'dest' => 'verbose'));
</code>
> If "--noisy" is seen, //Horde_Argv// will set
<code type="php">
$options->verbose = 2;
</code>
* {{store_true}} [relevant: {{dest}}]
> A special case of {{store_const}} that stores a {{TRUE}} value to {{dest}}.
* {{store_false}} [relevant: {{dest}}]
> Like {{store_true}}, but stores a {{FALSE}} value.
> Example:
<code type="php">
$parser->addOption(null, '--clobber', array('action' => 'store_true',
'dest' => 'clobber'));
$parser->addOption(null, '--no-clobber', array('action' =>
'store_false', 'dest' => 'clobber'));
</code>
* {{append}} [relevant: {{type}}, {{dest}}, {{nargs}}, {{choices}}]
> The option must be followed by an argument, which is appended to the
> array in {{dest}}. If no default value for {{dest}} is supplied, an
> empty array is automatically created when //Horde_Argv// first
> encounters this option on the command-line. If {{nargs}} > 1,
> multiple arguments are consumed, and an array of length {{nargs}} is
> appended to {{dest}}.
> The defaults for {{type}} and {{dest}} are the same as for the
> {{store}} action.
> Example:
<code type="php">
$parser->addOption('-t', '--tracks', array('action' => 'append',
'type' => 'int'));
</code>
> If "-t3" is seen on the command-line, //Horde_Argv// does the equivalent of:
<code type="php">
$options->tracks = array();
$options->tracks[] = intval('3');
</code>
> If, a little later on, "--tracks=4" is seen, it does:
<code type="php">
$options->tracks[] = intval('4');
</code>
* {{count}} [relevant: {{dest}}]
> Increment the integer stored at {{dest}}. {{dest}} is set to zero
> before being incremented the first time (unless you supply a default
> value).
> Example:
<code type="php">
$parser->addOption('-v', array('action' => 'count', 'dest' => 'verbosity'));
</code>
> The first time "-v" is seen on the command line, //Horde_Argv// does
> the equivalent of:
<code type="php">
$options->verbosity = 0;
$options->verbosity += 1;
</code>
> Every subsequent occurrence of "-v" results in
<code type="php">
$options->verbosity += 1;
</code>
* {{callback}} [required: {{callback}}; relevant: {{type}}, {{nargs}},
{{callback_args}}, {{callback_kwargs}}]
> Call the function specified by {{callback}}. The signature of this
> function should be
<code type="php">
func(Horde_Argv_Option $option,
string $opt,
mixed $value,
Horde_Argv_Parser $parser,
array $args,
array $kwargs)
</code>
> See Option Callbacks for more detail.
* {{help}} [relevant: none]
> Prints a complete help message for all the options in the current
> option parser. The help message is constructed from the {{usage}}
> string passed to {{Horde_Argv_Parser}}'s constructor and the
> {{help}} string passed to every option.
> If no help string is supplied for an option, it will still be listed
> in the help message. To omit an option entirely, use the special
> value {{Horde_Argv_Option::SUPPRESS_HELP}}.
> Example:
<code type="php">
$parser = new Horde_Argv_Parser();
$parser->addOption('-h', '--help',
array('action' => 'help'));
$parser->addOption('-v',
array('action' => 'store_true', 'dest' => 'verbose',
'help' => 'Be moderately verbose'));
$parser->addOption('--file',
array('dest' => 'filename',
'help' => 'Input file to read data from'));
$parser->addOption('--secret',
array('help' => Horde_Argv_Option::SUPPRESS_HELP));
</code>
> If //Horde_Argv// sees either "-h" or "--help" on the command line,
> it will print something like the following help message to stdout
> (assuming $_SERVER['argv'][0] is "foo.php"):
<code>
usage: foo.py [options]
options:
-h, --help Show this help message and exit
-v Be moderately verbose
--file=FILENAME Input file to read data from
</code>
> After printing the help message, //Horde_Argv// terminates your
> process with {{exit(0)}}.
* {{version}} [relevant: none]
> Prints the version number supplied to the {{Horde_Argv_Parser}} to
> stdout and exits. The version number is actually formatted and
> printed by the {{printVersion()}} method of {{Horde_Argv_Parser}}.
> Generally only relevant if the version argument is supplied to the
> {{Horde_Argv_Parser}} constructor.
+++ Option types
//Horde_Argv// has six built-in option types: {{string}}, {{int}},
{{long}}, {{choice}}, {{float}} and {{complex}}. If you need to add
new option types, see ((Doc/Dev/HordeArgvExtend|Extending Horde_Argv)).
Arguments to string options are not checked or converted in any way:
the text on the command line is stored in the destination (or passed
to the callback) as-is.
Integer arguments are passed to {{intval()}} to convert them to PHP
integers. If {{intval()}} fails, so will //Horde_Argv//, although with
a more useful error message. (Internally, //Horde_Argv// throws
{{Horde_Argv_OptionValueException}} from
{{Horde_Argv_Option#checkBuiltin()}}; {{Horde_Argv_Parser}} catches
this exception higher up and terminates your program with a useful
error message.)
Likewise, float arguments are passed to {{floatval()}} for conversion,
long arguments also to {{intval()}}, and complex arguments are not
handled yet. Apart from that, they are handled identically to integer
arguments.
{{choice}} options are a subtype of {{string}} options. The
{{choices}} option attribute (an array of strings) defines the set of
allowed option arguments. {{Horde_Argv_Option#checkChoice()}} compares
user-supplied option arguments against this master list and throws
{{Horde_Argv_OptionValueException}} if an invalid string is given.
+++ Querying and manipulating your option parser
Sometimes, it's useful to poke around your option parser and see
what's there. {{Horde_Argv_Parser}} provides a couple of methods to
help you out:
: {{boolean hasOption(string $opt_str)}} : Given an option string such
as "-q" or "--verbose", returns {{true}} if the {{Horde_Argv_Parser}}
has an option with that option string.
: {{Horde_Argv_Option getOption(string $opt_str)}} : Returns the
{{Horde_Argv_Option}} instance that implements the supplied option
string, or {{null}} if no options implement it.
: {{removeOption(string $opt_str)}} : If the {{Horde_Argv_Parser}} has
an option corresponding to {{$opt_str}}, that option is removed. If
that option provided any other option strings, all of those option
strings become invalid. If {{$opt_str}} does not occur in any option
belonging to this {{Horde_Argv_Parser}}, throws
{{!InvalidArgumentException}}.
+++ Conflicts between options
If you're not careful, it's easy to define conflicting options:
<code type="php">
$parser->addOption('-n', '--dry-run', ...);
[...]
$parser->addOption('-n', '--noisy', ...);
</code>
(This is even easier to do if you've defined your own
{{Horde_Argv_Parser}} subclass with some standard options.)
Every time you add an option, //Horde_Argv// checks for conflicts with
existing options. If it finds any, it invokes the current
conflict-handling mechanism. You can set the conflict-handling
mechanism either in the constructor:
<code type="php">
$parser = new Horde_Argv_Parser(..., array('conflictHandler' => '...'));
</code>
or with a separate call:
<code type="php">
$parser->setConflictHandler('...');
</code>
The available conflict-handling mechanisms are:
: {{error}} (default) : assume option conflicts are a programming
error and throws {{Horde_Argv_OptionConflictException}}
: {{resolve}} : resolve option conflicts intelligently (see below)
Here's an example: first, define an {{Horde_Argv_Parser}} that
resolves conflicts intelligently:
<code type="php">
$parser = new Horde_Argv_Parser(array('conflictHandler' => 'resolve'));
</code>
Now add all of our options:
<code type="php">
$parser->addOption('-n', '--dry-run', ..., array('help' => 'original
dry-run option'));
[...]
$parser->addOption('-n', '--noisy', ..., array('help' => 'be noisy'));
</code>
At this point, //Horde_Argv// detects that a previously-added option
is already using the "-n" option string. Since {{conflictHandler}} is
"resolve", it resolves the situation by removing "-n" from the earlier
option's list of option strings. Now, "--dry-run" is the only way for
the user to activate that option. If the user asks for help, the help
message will reflect that, e.g.:
<code>
options:
--dry-run original dry-run option
[...]
-n, --noisy be noisy
</code>
Note that it's possible to whittle away the option strings for a
previously-added option until there are none left, and the user has no
way of invoking that option from the command-line. In that case,
//Horde_Argv// removes that option completely, so it doesn't show up
in help text or anywhere else. E.g. if we carry on with our existing
{{Horde_Argv_Parser}}:
<code type="php">
$parser->addOption('--dry-run', ..., array('help' => 'new dry-run option'));
</code>
At this point, the first "-n/--dry-run" option is no longer
accessible, so //Horde_Argv// removes it. If the user asks for help,
they'll get something like this:
<code>
options:
[...]
-n, --noisy be noisy
--dry-run new dry-run option
</code>
More information about the commits
mailing list