argparse version 0.7.0 - a CLI parsing library

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Mar 17 19:07:28 UTC 2022


On Mon, Mar 14, 2022 at 03:06:44AM +0000, Andrey Zherikov via Digitalmars-d-announce wrote:
> Hi everyone,
> 
> I'd like to share that I've published a new version of
> [argparse](https://code.dlang.org/packages/argparse) library.  It's
> got some new features since my [first
> announcement](https://forum.dlang.org/post/zjljbdzfrtcxfiuzozty@forum.dlang.org)
> as well as some bug fixes:
> - Support of the usage without UDAs
> - Custom grouping of arguments on help screen
> - Mutually exclusive arguments
> - Mutually dependent arguments
> - Subcommands
[...]

Very comprehensive library!  Quite similar in concept to my own argument
parsing module that also uses a struct + UDAs for specifying options.
(Though your module is more advanced; mine doesn't handle things like
subcommands.)

I notice that some of your UDAs are pretty complicated, which makes me
wonder if you're aware that it's possible to attach multiple UDAs to a
single declaration.  For example, in my own argument parsing module, I
have a UDA @Alt for specifying an alternative name (usually a
single-character shorthand) to an option, as well as a UDA @Help for
attaching help text to an option.  Here's an example of both being used
for the same declaration:

	struct Options {
		@Alt("n") // accept `-n` in addition to `--name`
		@Help("Name of the object to generate")
		string name;
	}

Using independent, orthogonal UDAs may make option specification using
your module easier to read. For example, from your docs:

	struct T {
		@(NamedArgument
			.PreValidation!((string s) { return s.length > 1 && s[0] == '!'; })
			.Parse        !((string s) { return s[1]; })
			.Validation   !((char v) { return v >= '0' && v <= '9'; })
			.Action !((ref int a, char v) { a = v - '0'; })
		)
		int a;
	}

could be rewritten with multiple UDAs as:

	struct T {
		@NamedArgument
		@PreValidation!((string s) { return s.length > 1 && s[0] == '!'; })
		@Parse        !((string s) { return s[1]; })
		@Validation   !((char v) { return v >= '0' && v <= '9'; })
		@Action!((ref int a, char v) { a = v - '0'; })
		int a;
	}

It might also simplify your implementation by having more smaller,
independent pieces for each UDA instead of a single complex UDA that
handles everything.

Also, some of your function literals could use shorthand syntax, e.g.:

	.PreValidation!((string s) { return s.length > 1 && s[0] == '!'; })

could be written as:

	.PreValidation!(s => s.length > 1 && s[0] == '!')


T

-- 
Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin


More information about the Digitalmars-d-announce mailing list