Skip to content

Commit

Permalink
Support main callback with ref parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-zherikov committed Oct 23, 2024
1 parent 08e5ea0 commit f195278
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 6 deletions.
67 changes: 62 additions & 5 deletions source/argparse/api/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ template CLI(Config config, COMMAND)
return res;
}

static int parseArgs(alias newMain)(string[] args, COMMAND initialValue = COMMAND.init)
if(__traits(compiles, { newMain(COMMAND.init); }))
static int parseArgs(alias newMain)(string[] args, auto ref COMMAND initialValue = COMMAND.init)
if(__traits(compiles, { newMain(initialValue); }))
{
alias value = initialValue;

Expand All @@ -80,8 +80,8 @@ template CLI(Config config, COMMAND)
}
}

static int parseArgs(alias newMain)(string[] args, COMMAND initialValue = COMMAND.init)
if(__traits(compiles, { newMain(COMMAND.init, string[].init); }))
static int parseArgs(alias newMain)(string[] args, auto ref COMMAND initialValue = COMMAND.init)
if(__traits(compiles, { newMain(initialValue, string[].init); }))
{
alias value = initialValue;

Expand Down Expand Up @@ -153,4 +153,61 @@ template CLI(Config config, COMMAND)
}
}

alias CLI(COMMANDS...) = CLI!(Config.init, COMMANDS);
alias CLI(COMMANDS...) = CLI!(Config.init, COMMANDS);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

unittest
{
static struct Args {}

Args initValue;

enum cfg = Config.init;

assert(CLI!(cfg, Args).parseArgs!((_ ){})([]) == 0);
assert(CLI!(cfg, Args).parseArgs!((_, string[] unknown){})([]) == 0);
assert(CLI!(cfg, Args).parseArgs!((_ ){ return 123; })([]) == 123);
assert(CLI!(cfg, Args).parseArgs!((_, string[] unknown){ return 123; })([]) == 123);

assert(CLI!(cfg, Args).parseArgs!((_ ){})([], initValue) == 0);
assert(CLI!(cfg, Args).parseArgs!((_, string[] unknown){})([], initValue) == 0);
assert(CLI!(cfg, Args).parseArgs!((_ ){ return 123; })([], initValue) == 123);
assert(CLI!(cfg, Args).parseArgs!((_, string[] unknown){ return 123; })([], initValue) == 123);

// Ensure that CLI.main is compilable
{ mixin CLI!(cfg, Args).main!((_ ){}); }
{ mixin CLI!(cfg, Args).main!((_, string[] unknown){}); }
{ mixin CLI!(cfg, Args).main!((_ ){ return 123; }); }
{ mixin CLI!(cfg, Args).main!((_, string[] unknown){ return 123; }); }
}

// Ensure that CLI works with non-copyable structs
unittest
{
static struct Args {
@disable this(ref Args);
this(int) {}
}

//Args initValue;
auto initValue = Args(0);

enum cfg = Config.init;

assert(CLI!(cfg, Args).parseArgs!((ref _ ){})([]) == 0);
assert(CLI!(cfg, Args).parseArgs!((ref _, string[] unknown){})([]) == 0);
assert(CLI!(cfg, Args).parseArgs!((ref _ ){ return 123; })([]) == 123);
assert(CLI!(cfg, Args).parseArgs!((ref _, string[] unknown){ return 123; })([]) == 123);

assert(CLI!(cfg, Args).parseArgs!((ref _ ){})([], initValue) == 0);
assert(CLI!(cfg, Args).parseArgs!((ref _, string[] unknown){})([], initValue) == 0);
assert(CLI!(cfg, Args).parseArgs!((ref _ ){ return 123; })([], initValue) == 123);
assert(CLI!(cfg, Args).parseArgs!((ref _, string[] unknown){ return 123; })([], initValue) == 123);

// Ensure that CLI.main is compilable
{ mixin CLI!(cfg, Args).main!((ref _ ){}); }
{ mixin CLI!(cfg, Args).main!((ref _, string[] unknown){}); }
{ mixin CLI!(cfg, Args).main!((ref _ ){ return 123; }); }
{ mixin CLI!(cfg, Args).main!((ref _, string[] unknown){ return 123; }); }
}
3 changes: 2 additions & 1 deletion source/argparse/internal/command.d
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ private enum hasNoMembersWithUDA(COMMAND) = getSymbolsByUDA!(COMMAND, ArgumentUD
getSymbolsByUDA!(COMMAND, SubCommands ).length == 0;

private enum isOpFunction(alias mem) = is(typeof(mem) == function) && __traits(identifier, mem).length > 2 && __traits(identifier, mem)[0..2] == "op";
private enum isConstructor(alias mem) = is(typeof(mem) == function) && __traits(identifier, mem) == "__ctor";

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand All @@ -122,7 +123,7 @@ private template iterateArguments(TYPE)
enum filter = !is(mem) && (
hasUDA!(mem, ArgumentUDA) ||
hasUDA!(mem, NamedArgument) ||
hasNoMembersWithUDA!TYPE && !isOpFunction!mem && !isSumType!(typeof(mem)));
hasNoMembersWithUDA!TYPE && !isOpFunction!mem && !isConstructor!mem && !isSumType!(typeof(mem)));
}

alias iterateArguments = Filter!(filter, __traits(allMembers, TYPE));
Expand Down

0 comments on commit f195278

Please sign in to comment.