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/[email protected])
> 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

Reply via email to