Thread overview
optparse.d -- good enough to be std.optparse?
May 30, 2005
derick_eddington
May 30, 2005
derick_eddington
May 31, 2005
Kris
May 31, 2005
derick_eddington
May 31, 2005
kris
May 31, 2005
James Dunne
Re: optparse.d -- updated
Jun 01, 2005
derick_eddington
May 31, 2005
Andrew Fedoniouk
Re: optparse.d -- static
Jun 01, 2005
derick_eddington
Jun 01, 2005
Andrew Fedoniouk
May 30, 2005
I've made a command-line option helper similar to Python's optparse.  It allows you to specify what D-type you want the option as, short name, long name, help, and more.  It automatically creates a formatted help message and prints it on errors.  It checks that clients' usage of the module is proper; and it checks that the command-line arguments meet what was specified.  It has a compehensive unittest that demonstrates more.  The source is attached.

: /**
:  * Example usage:
:  */
: int main (char[][] args)
: {
:     int verbosity;
:     char[] outfile;
:     char[][] files;
:
:     // Constructor parameters are used in printing help.
:     // -h / --help is always added by default
:     // and uses program-name and usage.
:     // --version (no short name) is added by
:     // default if version is given.
:     //                                   program-name
:     OptionParser op = new OptionParser(__FILE__[0..$-2],
:     //                 usage                version
:         "[options] --files=f1,fN [outfile]", "0.2");
:
:     // int, short and long, help, metavar,
:     // no default, not mandatory
:     op.addOption!(int)("v", "verbose",
:         "Be more and more and more and more and more "
:         "and more and more verbose.", "LEVEL");
:     // comma-separated string list, short and long, help,
:     // metavar, no default, mandatory
:     op.addOption!(char[][])("fs", "files",
:         "Files to process, and make this a really long help "
:         "string as well to test aligning.", "FILE,FILE,...",
:         null, true);
:     // float, long-only, help, metavar, default, not mandatory
:     op.addOption!(float)(null, "thing", "Do it with this.",
:         "FLOAT", -4.297e21f);
:     // no-value, short-only, with help, no metavar,
:     // no default, not mandatory
:     op.addOption!()("a", null, "Use alternate method.");
:
:     // Parse command-line arguments, including args[0]
:     // program-name (it's skipped).
:     // args will be reset to the remaining non-option
:     // command-line arguments in the order they appeared.
:     Options options = op.parse(args);
:
:     // Check if option was given on the command-line
:     // by using (char[] in Options).
:     // If the option has both short and long names,
:     // either can be used.
:     if ("verbose" in options)
:         // If option was given and it has a value,
:         // retrieve it by indexing Options with short
:         // or long name (or only one if only one)
:         // and do getValue!(T)
:         verbosity = options["verbose"].getValue!(int);
:
:     if (verbosity > 0)
:         writefln("I'll say a little.");
:     if (verbosity > 1)
:         writefln("I'll say a lot more.");
:
:     // args was reset by parse to the remaining
:     // non-option command-line arguments
:     if (args.length == 1)
:         // use the first non-option argument
:         outfile = args[0];
:     else if (args.length > 1)
:         // OptionError.errorExit("message") can be used to
:         // print help and exit process;
:         // useful when checking non-option arguments
:         op.errorExit("more than one output file specified");
:
:     // mandatory options can be assumed to be
:     // there after successful parse
:     assert ("files" in options);
:     files = options["files"].getValue!(char[][]);
:     if (files.length == 0)
:         op.errorExit("need to specifiy at least one input file");
:
:     if (verbosity > 0)
:     {
:         if ("thing" in options)
:             writefln("my thing is: ",
:                 options["thing"].getValue!(float));
:
:         // no-value options are simply tested for being in Options
:         if ("a" in options)
:             writefln("I would process files using alternate method:");
:         else
:             writefln("I would process files using normal method:");
:         foreach (char[] f; files)
:             writefln("\t",f);
:         writefln("and output to ",
:             outfile.length ? outfile : "<stdout>");
:     }
:
:     return 0;
: }

Example command-line output of above program:

---------------------------------------------------------------

$ ./example -h
usage:  optparse [options] --files=f1,fN [outfile]

options:
-h, --help            Show this help message and exit.
--version             Show program's version number and exit.
-vLEVEL, --verbose=LEVEL
Be more and more and more and more and more and more
and more verbose.
-fsFILE,FILE,..., --files=FILE,FILE,...
Files to process, and make this a really long help
string as well to test aligning.
--thing=FLOAT         Do it with this.
-a                    Use alternate method.

---------------------------------------------------------------

$ ./example -v2 --files=somefile,anotherfile,nextfile --thing -4.23e-6 -a
outputfile
I'll say a little.
I'll say a lot more.
my thing is: -4.23e-06
I would process files using alternate method:
somefile
anotherfile
nextfile
and output to outputfile

---------------------------------------------------------------

$ ./example --asdf
optparse: error: no such option: --asdf

[help]

---------------------------------------------------------------

$ ./example
optparse: error: -fs / --files option is mandatory

[help]



May 30, 2005
In article <d7g5nd$3i3$1@digitaldaemon.com>, derick_eddington@nospam.yashmoo.com says...
>
>Example command-line output of above program:
>
>---------------------------------------------------------------
>
>$ ./example -h
>usage:  optparse [options] --files=f1,fN [outfile]
>
>options:
>-h, --help            Show this help message and exit.
>--version             Show program's version number and exit.
>-vLEVEL, --verbose=LEVEL
>Be more and more and more and more and more and more
>and more verbose.
>-fsFILE,FILE,..., --files=FILE,FILE,...
>Files to process, and make this a really long help
>string as well to test aligning.
>--thing=FLOAT         Do it with this.
>-a                    Use alternate method.
>

Arg, forgot to : these. The help print is nicely formatted...



May 31, 2005
Very useful. I'd like to add this to Mango, if that would be OK?

- Kris

<derick_eddington@nospam.yashmoo.com> wrote in message news:d7g5nd$3i3$1@digitaldaemon.com...
> I've made a command-line option helper similar to Python's optparse.  It
allows
> you to specify what D-type you want the option as, short name, long name,
help,
> and more.  It automatically creates a formatted help message and prints it
on
> errors.  It checks that clients' usage of the module is proper; and it
checks
> that the command-line arguments meet what was specified.  It has a
compehensive
> unittest that demonstrates more.  The source is attached.
>
> : /**
> :  * Example usage:
> :  */
> : int main (char[][] args)
> : {
> :     int verbosity;
> :     char[] outfile;
> :     char[][] files;
> :
> :     // Constructor parameters are used in printing help.
> :     // -h / --help is always added by default
> :     // and uses program-name and usage.
> :     // --version (no short name) is added by
> :     // default if version is given.
> :     //                                   program-name
> :     OptionParser op = new OptionParser(__FILE__[0..$-2],
> :     //                 usage                version
> :         "[options] --files=f1,fN [outfile]", "0.2");
> :
> :     // int, short and long, help, metavar,
> :     // no default, not mandatory
> :     op.addOption!(int)("v", "verbose",
> :         "Be more and more and more and more and more "
> :         "and more and more verbose.", "LEVEL");
> :     // comma-separated string list, short and long, help,
> :     // metavar, no default, mandatory
> :     op.addOption!(char[][])("fs", "files",
> :         "Files to process, and make this a really long help "
> :         "string as well to test aligning.", "FILE,FILE,...",
> :         null, true);
> :     // float, long-only, help, metavar, default, not mandatory
> :     op.addOption!(float)(null, "thing", "Do it with this.",
> :         "FLOAT", -4.297e21f);
> :     // no-value, short-only, with help, no metavar,
> :     // no default, not mandatory
> :     op.addOption!()("a", null, "Use alternate method.");
> :
> :     // Parse command-line arguments, including args[0]
> :     // program-name (it's skipped).
> :     // args will be reset to the remaining non-option
> :     // command-line arguments in the order they appeared.
> :     Options options = op.parse(args);
> :
> :     // Check if option was given on the command-line
> :     // by using (char[] in Options).
> :     // If the option has both short and long names,
> :     // either can be used.
> :     if ("verbose" in options)
> :         // If option was given and it has a value,
> :         // retrieve it by indexing Options with short
> :         // or long name (or only one if only one)
> :         // and do getValue!(T)
> :         verbosity = options["verbose"].getValue!(int);
> :
> :     if (verbosity > 0)
> :         writefln("I'll say a little.");
> :     if (verbosity > 1)
> :         writefln("I'll say a lot more.");
> :
> :     // args was reset by parse to the remaining
> :     // non-option command-line arguments
> :     if (args.length == 1)
> :         // use the first non-option argument
> :         outfile = args[0];
> :     else if (args.length > 1)
> :         // OptionError.errorExit("message") can be used to
> :         // print help and exit process;
> :         // useful when checking non-option arguments
> :         op.errorExit("more than one output file specified");
> :
> :     // mandatory options can be assumed to be
> :     // there after successful parse
> :     assert ("files" in options);
> :     files = options["files"].getValue!(char[][]);
> :     if (files.length == 0)
> :         op.errorExit("need to specifiy at least one input file");
> :
> :     if (verbosity > 0)
> :     {
> :         if ("thing" in options)
> :             writefln("my thing is: ",
> :                 options["thing"].getValue!(float));
> :
> :         // no-value options are simply tested for being in Options
> :         if ("a" in options)
> :             writefln("I would process files using alternate method:");
> :         else
> :             writefln("I would process files using normal method:");
> :         foreach (char[] f; files)
> :             writefln("\t",f);
> :         writefln("and output to ",
> :             outfile.length ? outfile : "<stdout>");
> :     }
> :
> :     return 0;
> : }
>
> Example command-line output of above program:
>
> ---------------------------------------------------------------
>
> $ ./example -h
> usage:  optparse [options] --files=f1,fN [outfile]
>
> options:
> -h, --help            Show this help message and exit.
> --version             Show program's version number and exit.
> -vLEVEL, --verbose=LEVEL
> Be more and more and more and more and more and more
> and more verbose.
> -fsFILE,FILE,..., --files=FILE,FILE,...
> Files to process, and make this a really long help
> string as well to test aligning.
> --thing=FLOAT         Do it with this.
> -a                    Use alternate method.
>
> ---------------------------------------------------------------
>
> $ ./example -v2 --files=somefile,anotherfile,nextfile --thing -4.23e-6 -a
> outputfile
> I'll say a little.
> I'll say a lot more.
> my thing is: -4.23e-06
> I would process files using alternate method:
> somefile
> anotherfile
> nextfile
> and output to outputfile
>
> ---------------------------------------------------------------
>
> $ ./example --asdf
> optparse: error: no such option: --asdf
>
> [help]
>
> ---------------------------------------------------------------
>
> $ ./example
> optparse: error: -fs / --files option is mandatory
>
> [help]
>
>
>
>


May 31, 2005
Certainly.  I'll keep you updated as I enhance and fix bugs.

In article <d7g9q7$7b3$1@digitaldaemon.com>, Kris says...
>
>Very useful. I'd like to add this to Mango, if that would be OK?
>
>- Kris
>
><derick_eddington@nospam.yashmoo.com> wrote in message news:d7g5nd$3i3$1@digitaldaemon.com...
>> I've made a command-line option helper similar to Python's optparse.  It
>allows
>> you to specify what D-type you want the option as, short name, long name,
>help,
>> and more.  It automatically creates a formatted help message and prints it
>on
>> errors.  It checks that clients' usage of the module is proper; and it
>checks
>> that the command-line arguments meet what was specified.  It has a
>compehensive
>> unittest that demonstrates more.  The source is attached.


May 31, 2005
derick_eddington@nospam.yashmoo.com wrote:
> Certainly.  I'll keep you updated as I enhance and fix bugs.

Excellent ~ thx!
May 31, 2005
In article <d7gqjo$nth$2@digitaldaemon.com>, kris says...
>
>derick_eddington@nospam.yashmoo.com wrote:
>> Certainly.  I'll keep you updated as I enhance and fix bugs.

Who doesn't love to enhance bugs? =P

>
>Excellent ~ thx!

Regards,
James Dunne
May 31, 2005
Cool, Derick!

What about using box values there?

Having them and use TypeList instead of

  optionParser = new OptionParser(__FILE__[0..$-2], "[option [value]]",
"0.0");
  optionParser.addOption!()("v","verbose");
  optionParser.addOption!(float)("f","foo",null,null,null,true);
  optionParser.addOption!(int)("x","xeno","does this and that","THING",123);

will allow to build such declarations in compile time - statically.

Just hypothesis....

Andrew.



<derick_eddington@nospam.yashmoo.com> wrote in message news:d7g5nd$3i3$1@digitaldaemon.com...
> I've made a command-line option helper similar to Python's optparse.  It
> allows
> you to specify what D-type you want the option as, short name, long name,
> help,
> and more.  It automatically creates a formatted help message and prints it
> on
> errors.  It checks that clients' usage of the module is proper; and it
> checks
> that the command-line arguments meet what was specified.  It has a
> compehensive
> unittest that demonstrates more.  The source is attached.
>
> : /**
> :  * Example usage:
> :  */
> : int main (char[][] args)
> : {
> :     int verbosity;
> :     char[] outfile;
> :     char[][] files;
> :
> :     // Constructor parameters are used in printing help.
> :     // -h / --help is always added by default
> :     // and uses program-name and usage.
> :     // --version (no short name) is added by
> :     // default if version is given.
> :     //                                   program-name
> :     OptionParser op = new OptionParser(__FILE__[0..$-2],
> :     //                 usage                version
> :         "[options] --files=f1,fN [outfile]", "0.2");
> :
> :     // int, short and long, help, metavar,
> :     // no default, not mandatory
> :     op.addOption!(int)("v", "verbose",
> :         "Be more and more and more and more and more "
> :         "and more and more verbose.", "LEVEL");
> :     // comma-separated string list, short and long, help,
> :     // metavar, no default, mandatory
> :     op.addOption!(char[][])("fs", "files",
> :         "Files to process, and make this a really long help "
> :         "string as well to test aligning.", "FILE,FILE,...",
> :         null, true);
> :     // float, long-only, help, metavar, default, not mandatory
> :     op.addOption!(float)(null, "thing", "Do it with this.",
> :         "FLOAT", -4.297e21f);
> :     // no-value, short-only, with help, no metavar,
> :     // no default, not mandatory
> :     op.addOption!()("a", null, "Use alternate method.");
> :
> :     // Parse command-line arguments, including args[0]
> :     // program-name (it's skipped).
> :     // args will be reset to the remaining non-option
> :     // command-line arguments in the order they appeared.
> :     Options options = op.parse(args);
> :
> :     // Check if option was given on the command-line
> :     // by using (char[] in Options).
> :     // If the option has both short and long names,
> :     // either can be used.
> :     if ("verbose" in options)
> :         // If option was given and it has a value,
> :         // retrieve it by indexing Options with short
> :         // or long name (or only one if only one)
> :         // and do getValue!(T)
> :         verbosity = options["verbose"].getValue!(int);
> :
> :     if (verbosity > 0)
> :         writefln("I'll say a little.");
> :     if (verbosity > 1)
> :         writefln("I'll say a lot more.");
> :
> :     // args was reset by parse to the remaining
> :     // non-option command-line arguments
> :     if (args.length == 1)
> :         // use the first non-option argument
> :         outfile = args[0];
> :     else if (args.length > 1)
> :         // OptionError.errorExit("message") can be used to
> :         // print help and exit process;
> :         // useful when checking non-option arguments
> :         op.errorExit("more than one output file specified");
> :
> :     // mandatory options can be assumed to be
> :     // there after successful parse
> :     assert ("files" in options);
> :     files = options["files"].getValue!(char[][]);
> :     if (files.length == 0)
> :         op.errorExit("need to specifiy at least one input file");
> :
> :     if (verbosity > 0)
> :     {
> :         if ("thing" in options)
> :             writefln("my thing is: ",
> :                 options["thing"].getValue!(float));
> :
> :         // no-value options are simply tested for being in Options
> :         if ("a" in options)
> :             writefln("I would process files using alternate method:");
> :         else
> :             writefln("I would process files using normal method:");
> :         foreach (char[] f; files)
> :             writefln("\t",f);
> :         writefln("and output to ",
> :             outfile.length ? outfile : "<stdout>");
> :     }
> :
> :     return 0;
> : }
>
> Example command-line output of above program:
>
> ---------------------------------------------------------------
>
> $ ./example -h
> usage:  optparse [options] --files=f1,fN [outfile]
>
> options:
> -h, --help            Show this help message and exit.
> --version             Show program's version number and exit.
> -vLEVEL, --verbose=LEVEL
> Be more and more and more and more and more and more
> and more verbose.
> -fsFILE,FILE,..., --files=FILE,FILE,...
> Files to process, and make this a really long help
> string as well to test aligning.
> --thing=FLOAT         Do it with this.
> -a                    Use alternate method.
>
> ---------------------------------------------------------------
>
> $ ./example -v2 --files=somefile,anotherfile,nextfile --thing -4.23e-6 -a
> outputfile
> I'll say a little.
> I'll say a lot more.
> my thing is: -4.23e-06
> I would process files using alternate method:
> somefile
> anotherfile
> nextfile
> and output to outputfile
>
> ---------------------------------------------------------------
>
> $ ./example --asdf
> optparse: error: no such option: --asdf
>
> [help]
>
> ---------------------------------------------------------------
>
> $ ./example
> optparse: error: -fs / --files option is mandatory
>
> [help]
>
>
>
> 


June 01, 2005
I've updated optparse.d:

Option groups for help printout.
Example:

: optionParser = new OptionParser("myapp", "[option [value]]");
: optionParser.addOption!()("v", "verbose");
: optionParser.addOption!(float)("f", "foo", null, null, null, true);
: optionParser.addOption!(int)("x", "xeno", "does this and that", "THING");
: optionParser.addOption!(int[])("a", "apple", "make applesauce", null);
: optionParser.addOption!(long)("l", "long", "be longer", "LONG");
: optionParser.addOption!(double)("d", "double", null, "DOUBLE");
: optionParser.addOption!(uint[])("ui", "uint", null, "UINT,...");
: // make a group, options must have previously been added
: optionParser.makeGroup("number options", "f", "x", "a", "l", "d", "ui");
: optionParser.addOption!(char[])(null, "bar", "make it happen", "BLOB");
: optionParser.addOption!(char[][])("sb", "shabang", "blow up", "IT");
: // make a group, options must have previously been added
: optionParser.makeGroup("string options", "bar", "sb");

Will make help:

: usage:  myapp [option [value]]
:
: options:
:   -h, --help            Show this help message and exit.
:   --version             Show program's version number and exit.
:   -v, --verbose
:
: number options:
:   -f, --foo
:   -x THING, --xeno=THING
:                         does this and that
:   -a, --apple           make applesauce
:   -l LONG, --long=LONG
:                         be longer
:   -d DOUBLE, --double=DOUBLE
:   -ui UINT,..., --uint=UINT,...
:
: string options:
:   --bar=BLOB            make it happen
:   -sb IT, --shabang=IT
:                         blow up

Help string formatting separates short-name from METAVAR by a space for easier reading.

Smarter use of templates to support more types.

Bug *un-enhanced* :) where "--option= --next-opt" would consume --next-opt as --option's value instead of causing error because --option has no value.

A few more unittest cases.

Question for potential users of optparse.d:
Would you rather have anal checking of all usage of the module or reduce the
object-file size from 55k to 35k? I tried to use "version" but it's too buggy (I
just wanted version'd else-if...)

--Derick


June 01, 2005
If it could be setup statically at compile-time and have the same conciseness, flexibility, and ease of checking for options and retrieving their values, that would be awesome, but I don't follow what you mean about box values and TypeList.  Could you elaborate?

The only way to parameterize something at compile-time is with templates, right? But they can only take integral values, not char[] for option names or arbitrary types for default values.  Statically-initialized structs could be used but then they still have to be given to an OptionParser and variables for them would also need to be declared.  I don't think it can be done and retain the same degree of simpleness of use.


In article <d7iifp$2jhh$1@digitaldaemon.com>, Andrew Fedoniouk says...
>
>Cool, Derick!
>
>What about using box values there?
>
>Having them and use TypeList instead of
>
>  optionParser = new OptionParser(__FILE__[0..$-2], "[option [value]]",
>"0.0");
>  optionParser.addOption!()("v","verbose");
>  optionParser.addOption!(float)("f","foo",null,null,null,true);
>  optionParser.addOption!(int)("x","xeno","does this and that","THING",123);
>
>will allow to build such declarations in compile time - statically.
>
>Just hypothesis....
>
>Andrew.


June 01, 2005
<derick_eddington@nospam.yashmoo.com> wrote in message news:d7jvl1$1420$1@digitaldaemon.com...
> If it could be setup statically at compile-time and have the same
> conciseness,
> flexibility, and ease of checking for options and retrieving their values,
> that
> would be awesome, but I don't follow what you mean about box values and
> TypeList.  Could you elaborate?
>
> The only way to parameterize something at compile-time is with templates,
> right?
> But they can only take integral values, not char[] for option names or
> arbitrary
> types for default values.  Statically-initialized structs could be used
> but then
> they still have to be given to an OptionParser and variables for them
> would also
> need to be declared.  I don't think it can be done and retain the same
> degree of
> simpleness of use.

Yep. You are right. I was thinking about simple
implementation of something close to boost::spirit
http://spirit.sourceforge.net/
but it seems like even simple implementation is an overkill for such task.

Andrew.


>
>
> In article <d7iifp$2jhh$1@digitaldaemon.com>, Andrew Fedoniouk says...
>>
>>Cool, Derick!
>>
>>What about using box values there?
>>
>>Having them and use TypeList instead of
>>
>>  optionParser = new OptionParser(__FILE__[0..$-2], "[option [value]]",
>>"0.0");
>>  optionParser.addOption!()("v","verbose");
>>  optionParser.addOption!(float)("f","foo",null,null,null,true);
>>  optionParser.addOption!(int)("x","xeno","does this and
>> that","THING",123);
>>
>>will allow to build such declarations in compile time - statically.
>>
>>Just hypothesis....



>>
>>Andrew.
>
>