Skip to content

Commit

Permalink
Add support of custom types (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-zherikov authored Sep 16, 2022
1 parent 3bfd461 commit 51dd8de
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 8 deletions.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ considered arguments with the same name as the name of member:
```d
import argparse;
static struct Basic
struct Basic
{
// Basic data types are supported:
// --name argument
Expand Down Expand Up @@ -127,7 +127,7 @@ Optional arguments:
For more sophisticated CLI usage, `argparse` provides few UDAs:

```d
static struct Advanced
struct Advanced
{
// Positional arguments are required by default
@PositionalArgument(0)
Expand Down Expand Up @@ -1081,7 +1081,7 @@ If you want to determine whether `--color` argument was specified in command lin
data member:

```d
static struct Arguments
struct Arguments
{
static auto color = ansiStylingArgument;
}
Expand Down Expand Up @@ -1323,7 +1323,7 @@ An argument can be bound to a function with one of the following signatures
command line and the set of values specified in command line is provided into parameter.

```d
static struct T
struct T
{
int a;
Expand All @@ -1333,6 +1333,25 @@ static struct T
assert(CLI!T.parseArgs!((T t) { assert(t == T(4)); })(["-a","-a","-a","-a"]) == 0);
```

### Custom types

Any arbitrary type can be used to receive command line argument values. `argparse` supports this use case - you just need
to provide parsing function:

```d
struct Value
{
string a;
}
struct T
{
@(NamedArgument.Parse!((string s) { return Value(s); }))
Value s;
}
assert(CLI!T.parseArgs!((T t) { assert(t == T(Value("foo"))); return 12345; })(["-s","foo"]) == 12345);
```

## Argument parsing customization

Some time the functionality provided out of the box is not enough and it needs to be tuned.
Expand Down
9 changes: 8 additions & 1 deletion examples/getting_started/advanced/app.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import argparse;
import argparse.ansi;

static struct Advanced
struct Advanced
{
// Positional arguments are required by default
@PositionalArgument(0)
Expand All @@ -22,6 +22,13 @@ static struct Advanced
@NamedArgument(["b","banana","ban"])
int banana;

// Custom types can also be used with custon parsing function
struct CustomType {
double d;
}
@(NamedArgument.Parse!((string value) { import std.conv: to; return CustomType(value.to!double); }))
CustomType custom;

@(NamedArgument.Description(green.bold.underline("Colorize")~" the output. If value is omitted then '"~red("always")~"' is used."))
static auto color = ansiStylingArgument;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/getting_started/basic/app.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import argparse;

// If struct has no UDA then all members are named arguments
static struct Basic
struct Basic
{
// Basic data types are supported:
// --name argument
Expand Down
11 changes: 10 additions & 1 deletion source/argparse/internal.d
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,16 @@ if(!is(T == void))
);
}
else
static assert(false, "Type is not supported: " ~ T.stringof);
{
alias DefaultValueParseFunctions = ValueParseFunctions!(
void, // pre process
void, // pre validate
void, // parse
void, // validate
void, // action
void // no-value action
);
}
}

unittest
Expand Down
42 changes: 41 additions & 1 deletion source/argparse/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,17 @@ public auto PreValidation(alias func, T)(auto ref ArgumentUDA!T uda)

public auto Parse(alias func, T)(auto ref ArgumentUDA!T uda)
{
return ArgumentUDA!(uda.parsingFunc.changeParse!func)(uda.tupleof);
auto desc = ArgumentUDA!(uda.parsingFunc.changeParse!func)(uda.tupleof);

static if(__traits(compiles, { func(string.init); }))
desc.info.minValuesCount = desc.info.maxValuesCount = 1;
else
{
desc.info.minValuesCount = 0;
desc.info.maxValuesCount = ulong.max;
}

return desc;
}

public auto Validation(alias func, T)(auto ref ArgumentUDA!T uda)
Expand Down Expand Up @@ -1286,6 +1296,24 @@ unittest
assert(!is(FUNC == void));
}

unittest
{
auto uda = NamedArgument().Parse!((string _) => _);
assert(is(typeof(uda) : ArgumentUDA!(ValueParseFunctions!(void, void, FUNC, void, void, void)), alias FUNC));
assert(!is(FUNC == void));
assert(uda.info.minValuesCount == 1);
assert(uda.info.maxValuesCount == 1);
}

unittest
{
auto uda = NamedArgument().Parse!((string[] _) => _);
assert(is(typeof(uda) : ArgumentUDA!(ValueParseFunctions!(void, void, FUNC, void, void, void)), alias FUNC));
assert(!is(FUNC == void));
assert(uda.info.minValuesCount == 0);
assert(uda.info.maxValuesCount == ulong.max);
}

unittest
{
auto uda = NamedArgument().Validation!({});
Expand Down Expand Up @@ -1577,6 +1605,18 @@ unittest
assert(CLI!T.parseArgs!((T t) { assert(t == T(4)); return 12345; })(["-a","-a","-a","-a"]) == 12345);
}

unittest
{
struct Value { string a; }
struct T
{
@(NamedArgument.Parse!((string s) { return Value(s); }))
Value s;
}

assert(CLI!T.parseArgs!((T t) { assert(t == T(Value("foo"))); return 12345; })(["-s","foo"]) == 12345);
}


auto Command(string[] name...)
{
Expand Down

0 comments on commit 51dd8de

Please sign in to comment.