Skip to content

Commit

Permalink
Refactor error processing
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-zherikov committed Jun 8, 2022
1 parent 1a0f11c commit 1ef6dbd
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 64 deletions.
54 changes: 30 additions & 24 deletions source/argparse/internal.d
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,9 @@ package struct Restrictions
{
return partiallyApply!((size_t index, in Config config, in bool[size_t] cliArgs, in ArgumentInfo[] allArgs)
{
if(index in cliArgs)
return Result.Success;

config.onError("The following argument is required: ", info.getArgumentName(config));
return Result.Failure;
return (index in cliArgs) ?
Result.Success :
Result.Error("The following argument is required: ", info.getArgumentName(config));
})(index);
}

Expand All @@ -181,11 +179,8 @@ package struct Restrictions
missedIndex = index;

if(foundIndex != size_t.max && missedIndex != size_t.max)
{
config.onError("Missed argument '", allArgs[missedIndex].getArgumentName(config),
"' - it is required by argument '", allArgs[foundIndex].getArgumentName(config),"'");
return Result.Failure;
}
return Result.Error("Missed argument '", allArgs[missedIndex].getArgumentName(config),
"' - it is required by argument '", allArgs[foundIndex].getArgumentName(config),"'");
}

return Result.Success;
Expand All @@ -204,12 +199,8 @@ package struct Restrictions
if(foundIndex == size_t.max)
foundIndex = index;
else
{
config.onError("Argument '", allArgs[foundIndex].getArgumentName(config),
"' is not allowed with argument '", allArgs[index].getArgumentName(config),"'");
return Result.Failure;
}

return Result.Error("Argument '", allArgs[foundIndex].getArgumentName(config),
"' is not allowed with argument '", allArgs[index].getArgumentName(config),"'");
}

return Result.Success;
Expand All @@ -227,9 +218,7 @@ package struct Restrictions
if(index in cliArgs)
return Result.Success;

config.onError("One of the following arguments is required: '", restrictionArgs.map!(_ => allArgs[_].getArgumentName(config)).join("', '"), "'");

return Result.Failure;
return Result.Error("One of the following arguments is required: '", restrictionArgs.map!(_ => allArgs[_].getArgumentName(config)).join("', '"), "'");
}
}

Expand Down Expand Up @@ -569,10 +558,7 @@ package alias ParsingArgument(alias symbol, alias uda, ArgumentInfo info, RECEIV

auto res = info.checkValuesCount(argName, rawValues.length);
if(!res)
{
config.onError(res.errorMsg);
return res;
}

auto param = RawParam(config, argName, rawValues);

Expand All @@ -585,8 +571,7 @@ package alias ParsingArgument(alias symbol, alias uda, ArgumentInfo info, RECEIV
}
catch(Exception e)
{
config.onError(argName, ": ", e.msg);
return Result.Failure;
return Result.Error(argName, ": ", e.msg);
}
}
};
Expand Down Expand Up @@ -2225,3 +2210,24 @@ unittest
}

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

package static Result callParser(Config config, COMMAND)(ref COMMAND receiver, string[] args, out string[] unrecognizedArgs)
{
auto parser = Parser(config, args);

auto command = CommandArguments!COMMAND(config);
auto res = parser.parseAll!false(command, receiver);
if(!res)
{
if(res.errorMsg.length > 0)
config.onError(res.errorMsg);

return res;
}

unrecognizedArgs = parser.unrecognizedArgs;

return Result.Success;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
85 changes: 45 additions & 40 deletions source/argparse/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import argparse.internal;

import std.typecons: Nullable;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Public API
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct Config
Expand Down Expand Up @@ -136,13 +138,22 @@ struct Result
return status == Status.success;
}

package static auto Error(A...)(A args) nothrow
package static auto Error(A...)(A args)
{
import std.conv: text;
import std.stdio: stderr, writeln;

return Result(1, Status.failure, text!A(args));
}

version(unittest)
{
package bool isError(string text)
{
import std.algorithm: canFind;
return (!cast(bool) this) && errorMsg.canFind(text);
}
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -210,32 +221,37 @@ package struct ArgumentInfo

unittest
{
ArgumentInfo info;
info.allowBooleanNegation = false;
info.minValuesCount = 2;
info.maxValuesCount = 4;
auto info(int min, int max)
{
ArgumentInfo info;
info.allowBooleanNegation = false;
info.minValuesCount = min;
info.maxValuesCount = max;
return info;
}

alias isError = (Result res) => !res && res.errorMsg.length > 0;
assert(info(2,4).checkValuesCount("", 1).isError("expected at least 2 values"));
assert(info(2,4).checkValuesCount("", 2));
assert(info(2,4).checkValuesCount("", 3));
assert(info(2,4).checkValuesCount("", 4));
assert(info(2,4).checkValuesCount("", 5).isError("expected at most 4 values"));

assert( isError(info.checkValuesCount("", 1)));
assert(!isError(info.checkValuesCount("", 2)));
assert(!isError(info.checkValuesCount("", 3)));
assert(!isError(info.checkValuesCount("", 4)));
assert( isError(info.checkValuesCount("", 5)));
}
assert(info(2,2).checkValuesCount("", 1).isError("expected 2 values"));
assert(info(2,2).checkValuesCount("", 2));
assert(info(2,2).checkValuesCount("", 3).isError("expected 2 values"));

unittest
{
ArgumentInfo info;
info.allowBooleanNegation = false;
info.minValuesCount = 2;
info.maxValuesCount = 2;
assert(info(1,1).checkValuesCount("", 0).isError("expected 1 value"));
assert(info(1,1).checkValuesCount("", 1));
assert(info(1,1).checkValuesCount("", 2).isError("expected 1 value"));

alias isError = (Result res) => !res && res.errorMsg.length > 0;
assert(info(0,1).checkValuesCount("", 0));
assert(info(0,1).checkValuesCount("", 1));
assert(info(0,1).checkValuesCount("", 2).isError("expected at most 1 value"));

assert( isError(info.checkValuesCount("", 1)));
assert(!isError(info.checkValuesCount("", 2)));
assert( isError(info.checkValuesCount("", 3)));
assert(info(1,2).checkValuesCount("", 0).isError("expected at least 1 value"));
assert(info(1,2).checkValuesCount("", 1));
assert(info(1,2).checkValuesCount("", 2));
assert(info(1,2).checkValuesCount("", 3).isError("expected at most 2 values"));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -876,16 +892,7 @@ template CLI(Config config, COMMAND)
{
static Result parseKnownArgs(ref COMMAND receiver, string[] args, out string[] unrecognizedArgs)
{
auto parser = Parser(config, args);

auto command = CommandArguments!COMMAND(config);
auto res = parser.parseAll!false(command, receiver);
if(!res)
return res;

unrecognizedArgs = parser.unrecognizedArgs;

return Result.Success;
return callParser!config(receiver, args, unrecognizedArgs);
}

static Result parseKnownArgs(ref COMMAND receiver, ref string[] args)
Expand All @@ -904,8 +911,8 @@ template CLI(Config config, COMMAND)
auto res = parseKnownArgs(receiver, args);
if(res && args.length > 0)
{
config.onError("Unrecognized arguments: ", args);
return Result.Failure;
res = Result.Error("Unrecognized arguments: ", args);
config.onError(res.errorMsg);
}

return res;
Expand Down Expand Up @@ -972,17 +979,15 @@ template CLI(Config config, COMMAND)
// if we call anything from CLI!(config, Complete!COMMAND) so we have to directly call parser here

Complete!COMMAND receiver;
string[] unrecognizedArgs;

auto parser = Parser(config, args);

auto command = CommandArguments!(Complete!COMMAND)(config);
auto res = parser.parseAll!false(command, receiver);
auto res = callParser!config(receiver, args, unrecognizedArgs);
if(!res)
return 1;

if(res && parser.unrecognizedArgs.length > 0)
if(res && unrecognizedArgs.length > 0)
{
config.onError("Unrecognized arguments: ", parser.unrecognizedArgs);
config.onError("Unrecognized arguments: ", unrecognizedArgs);
return 1;
}

Expand Down

0 comments on commit 1ef6dbd

Please sign in to comment.