aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md26
-rw-r--r--args.hxx108
-rw-r--r--test.cxx68
3 files changed, 144 insertions, 58 deletions
diff --git a/README.md b/README.md
index da4b9d7..1246367 100644
--- a/README.md
+++ b/README.md
@@ -176,9 +176,9 @@ int main()
args::ArgFlagList<char> characters(parser, "characters", "The character flag", args::Matcher{'c', "char"});
args::PosArgList<double> numbers(parser, "numbers", "The numbers position list");
parser.ParseArgs(arguments);
- const int i = integer.value;
- const std::vector<char> c(characters.values);
- const std::vector<double> n(numbers.values);
+ const int i = args::get(integer);
+ const std::vector<char> c(args::get(characters));
+ const std::vector<double> n(args::get(numbers));
assert(i == 7);
assert(c[0] == 'a');
assert(c[1] == 'b');
@@ -432,10 +432,10 @@ int main(int argc, char **argv)
std::cerr << parser;
return 1;
}
- if (integer) { std::cout << "i: " << integer.value << std::endl; }
- if (characters) { for (const auto ch: characters.values) { std::cout << "c: " << ch << std::endl; } }
- if (foo) { std::cout << "f: " << foo.value << std::endl; }
- if (numbers) { for (const auto nm: numbers.values) { std::cout << "n: " << nm << std::endl; } }
+ if (integer) { std::cout << "i: " << args::get(integer) << std::endl; }
+ if (characters) { for (const auto ch: args::get(characters)) { std::cout << "c: " << ch << std::endl; } }
+ if (foo) { std::cout << "f: " << args::get(foo) << std::endl; }
+ if (numbers) { for (const auto nm: args::get(numbers)) { std::cout << "n: " << nm << std::endl; } }
return 0;
}
```
@@ -528,11 +528,11 @@ int main(int argc, char **argv)
}
if (ints)
{
- std::cout << "ints found: " << std::get<0>(ints.value) << " and " << std::get<1>(ints.value) << std::endl;
+ std::cout << "ints found: " << std::get<0>(args::get(ints)) << " and " << std::get<1>(args::get(ints)) << std::endl;
}
if (doubles)
{
- std::cout << "doubles found: " << std::get<0>(doubles.value) << " and " << std::get<1>(doubles.value) << std::endl;
+ std::cout << "doubles found: " << std::get<0>(args::get(doubles)) << " and " << std::get<1>(args::get(doubles)) << std::endl;
}
return 0;
}
@@ -720,10 +720,10 @@ int main(int argc, char **argv)
std::cerr << parser;
return 1;
}
- std::cout << "bs = " << bs.value << std::endl;
- std::cout << "skip = " << skip.value << std::endl;
- if (input) { std::cout << "if = " << input.value << std::endl; }
- if (output) { std::cout << "of = " << output.value << std::endl; }
+ std::cout << "bs = " << args::get(bs) << std::endl;
+ std::cout << "skip = " << args::get(skip) << std::endl;
+ if (input) { std::cout << "if = " << args::get(input) << std::endl; }
+ if (output) { std::cout << "of = " << args::get(output) << std::endl; }
return 0;
}
```
diff --git a/args.hxx b/args.hxx
index 5aee038..22f1170 100644
--- a/args.hxx
+++ b/args.hxx
@@ -27,9 +27,18 @@
#include <tuple>
#include <vector>
#include <unordered_set>
+#include <type_traits>
namespace args
{
+ /** Getter to grab the value reference
+ */
+ template <typename Arg>
+ auto get(Arg &arg) -> decltype(arg.Get())
+ {
+ return arg.Get();
+ }
+
/** (INTERNAL) Count UTF-8 glyphs
*
* This is not reliable, and will fail for combinatory glyphs, but it's
@@ -613,6 +622,13 @@ namespace args
return validator(*this);
}
+ /** Get validation
+ */
+ bool Get() const
+ {
+ return Matched();
+ }
+
/** Get all the child descriptions for help generation
*/
std::vector<std::tuple<std::string, std::string, unsigned int>> GetChildDescriptions(const std::string &shortPrefix, const std::string &longPrefix, const std::string &shortSeparator, const std::string &longSeparator, unsigned int indent = 0) const
@@ -1199,6 +1215,13 @@ namespace args
}
virtual ~Flag() {}
+
+ /** Get whether this was matched
+ */
+ bool Get() const
+ {
+ return Matched();
+ }
};
/** Help flag class
@@ -1229,17 +1252,25 @@ namespace args
}
return nullptr;
}
+
+ /** Get whether this was matched
+ */
+ bool Get() const noexcept
+ {
+ return Matched();
+ }
};
/** A flag class that simply counts the number of times it's matched
*/
class Counter : public Flag
{
- public:
- /** The public count variable. Can be changed at will, but probably shouldn't be.
- */
+ friend int get(Counter &);
+
+ private:
int count;
+ public:
Counter(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const int startcount = 0): Flag(group, name, help, std::move(matcher)), count(startcount) {}
virtual ~Counter() {}
@@ -1263,6 +1294,13 @@ namespace args
}
return me;
}
+
+ /** Get the count
+ */
+ int &Get() noexcept
+ {
+ return count;
+ }
};
/** A default Reader function for argument classes
@@ -1303,13 +1341,13 @@ namespace args
template <typename T, void (*Reader)(const std::string &, const std::string &, T&) = ArgReader<T>>
class ArgFlag : public ArgFlagBase
{
- public:
- /** The publicly accessible value member
- *
- * You can change this, but you probably shouldn't.
- */
+ friend T &get(ArgFlag &);
+
+ private:
T value;
+ public:
+
ArgFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const T &defaultValue = T()): ArgFlagBase(name, help, std::move(matcher)), value(defaultValue)
{
group.Add(*this);
@@ -1321,6 +1359,13 @@ namespace args
{
Reader(name, value, this->value);
}
+
+ /** Get the value
+ */
+ T &Get() noexcept
+ {
+ return value;
+ }
};
/** An argument-accepting flag class that pushes the found values into a list
@@ -1335,13 +1380,12 @@ namespace args
void (*Reader)(const std::string &, const std::string &, T&) = ArgReader<T>>
class ArgFlagList : public ArgFlagBase
{
- public:
- /** The publicly accessible value member list
- *
- * You can change this, but you probably shouldn't.
- */
+ friend List &get(ArgFlagList &);
+ private:
List values;
+ public:
+
ArgFlagList(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const List &defaultValues = List()): ArgFlagBase(name, help, std::move(matcher)), values(defaultValues)
{
group.Add(*this);
@@ -1354,6 +1398,13 @@ namespace args
values.emplace_back();
Reader(name, value, values.back());
}
+
+ /** Get the values
+ */
+ List &Get() noexcept
+ {
+ return values;
+ }
};
/** A positional argument class
@@ -1364,13 +1415,10 @@ namespace args
template <typename T, void (*Reader)(const std::string &, const std::string &, T&) = ArgReader<T>>
class PosArg : public PosBase
{
- public:
- /** The publicly accessible value member
- *
- * You can change this, but you probably shouldn't.
- */
+ friend T &get(PosArg &);
+ private:
T value;
-
+ public:
PosArg(Group &group, const std::string &name, const std::string &help, const T &defaultValue = T()): PosBase(name, help), value(defaultValue)
{
group.Add(*this);
@@ -1384,6 +1432,13 @@ namespace args
ready = false;
matched = true;
}
+
+ /** Get the value
+ */
+ T &Get() noexcept
+ {
+ return value;
+ }
};
/** A positional argument class that pushes the found values into a list
@@ -1398,13 +1453,11 @@ namespace args
void (*Reader)(const std::string &, const std::string &, T&) = ArgReader<T>>
class PosArgList : public PosBase
{
- public:
- /** The publicly accessible value member list
- *
- * You can change this, but you probably shouldn't.
- */
+ friend List &get(PosArgList &);
+ private:
List values;
+ public:
PosArgList(Group &group, const std::string &name, const std::string &help, const List &defaultValues = List()): PosBase(name, help), values(defaultValues)
{
group.Add(*this);
@@ -1423,5 +1476,12 @@ namespace args
{
return name + std::string("...");
}
+
+ /** Get the values
+ */
+ List &Get() noexcept
+ {
+ return values;
+ }
};
}
diff --git a/test.cxx b/test.cxx
index 4816691..c5ab1b3 100644
--- a/test.cxx
+++ b/test.cxx
@@ -49,6 +49,21 @@ TEST_CASE("Boolean flags work as expected, with clustering", "[args]")
REQUIRE_FALSE(bix);
}
+TEST_CASE("Count flag works as expected", "[args]")
+{
+ args::ArgumentParser parser("This is a test program.", "This goes after the options.");
+ args::Counter foo(parser, "FOO", "test flag", args::Matcher{'f', "foo"});
+ args::Counter bar(parser, "BAR", "test flag", args::Matcher{'b', "bar"}, 7);
+ args::Counter baz(parser, "BAZ", "test flag", args::Matcher{'z', "baz"}, 7);
+ parser.ParseArgs(std::vector<std::string>{"--foo", "-fb", "--bar", "-b", "-f", "--foo"});
+ REQUIRE(foo);
+ REQUIRE(bar);
+ REQUIRE_FALSE(baz);
+ REQUIRE(args::get(foo) == 4);
+ REQUIRE(args::get(bar) == 10);
+ REQUIRE(args::get(baz) == 7);
+}
+
TEST_CASE("Argument flags work as expected, with clustering", "[args]")
{
args::ArgumentParser parser("This is a test program.", "This goes after the options.");
@@ -59,12 +74,12 @@ TEST_CASE("Argument flags work as expected, with clustering", "[args]")
args::Flag bix(parser, "BAZ", "test flag", args::Matcher{'x', "bix"});
parser.ParseArgs(std::vector<std::string>{"-bftest", "--baz=7.555e2", "--bim", "c"});
REQUIRE(foo);
- REQUIRE(foo.value == "test");
+ REQUIRE(args::get(foo) == "test");
REQUIRE(bar);
REQUIRE(baz);
- REQUIRE((baz.value > 755.49 && baz.value < 755.51));
+ REQUIRE((args::get(baz) > 755.49 && args::get(baz) < 755.51));
REQUIRE(bim);
- REQUIRE(bim.value == 'c');
+ REQUIRE(args::get(bim) == 'c');
REQUIRE_FALSE(bix);
}
@@ -85,15 +100,26 @@ TEST_CASE("Unified argument lists for match work", "[args]")
args::Flag bix(parser, "BAZ", "test flag", args::Matcher{"bix"});
parser.ParseArgs(std::vector<std::string>{"-bftest", "--baz=7.555e2", "--bim", "c"});
REQUIRE(foo);
- REQUIRE(foo.value == "test");
+ REQUIRE(args::get(foo) == "test");
REQUIRE(bar);
REQUIRE(baz);
- REQUIRE((baz.value > 755.49 && baz.value < 755.51));
+ REQUIRE((args::get(baz) > 755.49 && args::get(baz) < 755.51));
REQUIRE(bim);
- REQUIRE(bim.value == 'c');
+ REQUIRE(args::get(bim) == 'c');
REQUIRE_FALSE(bix);
}
+TEST_CASE("Get can be assigned to for non-reference types", "[args]")
+{
+ args::ArgumentParser parser("This is a test program.", "This goes after the options.");
+ args::ArgFlag<std::string> foo(parser, "FOO", "test flag", args::Matcher{'f', "foo"});
+ parser.ParseArgs(std::vector<std::string>{"--foo=test"});
+ REQUIRE(foo);
+ REQUIRE(args::get(foo) == "test");
+ args::get(foo) = "bar";
+ REQUIRE(args::get(foo) == "bar");
+}
+
TEST_CASE("Invalid argument parsing throws parsing exceptions", "[args]")
{
args::ArgumentParser parser("This is a test program.", "This goes after the options.");
@@ -108,7 +134,7 @@ TEST_CASE("Argument flag lists work as expected", "[args]")
args::ArgumentParser parser("This is a test program.", "This goes after the options.");
args::ArgFlagList<int> foo(parser, "FOO", "test flag", args::Matcher{'f', "foo"});
parser.ParseArgs(std::vector<std::string>{"--foo=7", "-f2", "-f", "9", "--foo", "42"});
- REQUIRE((foo.values == std::vector<int>{7, 2, 9, 42}));
+ REQUIRE((args::get(foo) == std::vector<int>{7, 2, 9, 42}));
}
TEST_CASE("Positional arguments and positional argument lists work as expected", "[args]")
@@ -119,11 +145,11 @@ TEST_CASE("Positional arguments and positional argument lists work as expected",
args::PosArgList<char> baz(parser, "BAZ", "test flag");
parser.ParseArgs(std::vector<std::string>{"this is a test flag", "0", "a", "b", "c", "x", "y", "z"});
REQUIRE(foo);
- REQUIRE((foo.value == "this is a test flag"));
+ REQUIRE((args::get(foo) == "this is a test flag"));
REQUIRE(bar);
- REQUIRE(!bar.value);
+ REQUIRE(!args::get(bar));
REQUIRE(baz);
- REQUIRE((baz.values == std::vector<char>{'a', 'b', 'c', 'x', 'y', 'z'}));
+ REQUIRE((args::get(baz) == std::vector<char>{'a', 'b', 'c', 'x', 'y', 'z'}));
}
TEST_CASE("Positionals that are unspecified evaluate false", "[args]")
@@ -134,7 +160,7 @@ TEST_CASE("Positionals that are unspecified evaluate false", "[args]")
args::PosArgList<char> baz(parser, "BAZ", "test flag");
parser.ParseArgs(std::vector<std::string>{"this is a test flag again"});
REQUIRE(foo);
- REQUIRE((foo.value == "this is a test flag again"));
+ REQUIRE((args::get(foo) == "this is a test flag again"));
REQUIRE_FALSE(bar);
REQUIRE_FALSE(baz);
}
@@ -225,10 +251,10 @@ TEST_CASE("Custom types work", "[args]")
args::PosArg<std::tuple<int, int>> ints(parser, "INTS", "This takes a pair of integers.");
args::PosArg<std::tuple<double, double>, DoublesReader> doubles(parser, "DOUBLES", "This takes a pair of doubles.");
parser.ParseArgs(std::vector<std::string>{"1,2", "3.8,4"});
- REQUIRE(std::get<0>(ints.value) == 1);
- REQUIRE(std::get<1>(ints.value) == 2);
- REQUIRE((std::get<0>(doubles.value) > 3.79 && std::get<0>(doubles.value) < 3.81));
- REQUIRE((std::get<1>(doubles.value) > 3.99 && std::get<1>(doubles.value) < 4.01));
+ REQUIRE(std::get<0>(args::get(ints)) == 1);
+ REQUIRE(std::get<1>(args::get(ints)) == 2);
+ REQUIRE((std::get<0>(args::get(doubles)) > 3.79 && std::get<0>(args::get(doubles)) < 3.81));
+ REQUIRE((std::get<1>(args::get(doubles)) > 3.99 && std::get<1>(args::get(doubles)) < 4.01));
}
TEST_CASE("Custom parser prefixes (dd-style)", "[args]")
@@ -243,11 +269,11 @@ TEST_CASE("Custom parser prefixes (dd-style)", "[args]")
args::ArgFlag<std::string> output(parser, "BLOCK SIZE", "Block size", args::Matcher({"of"}));
parser.ParseArgs(std::vector<std::string>{"skip=8", "if=/dev/null"});
REQUIRE_FALSE(bs);
- REQUIRE(bs.value == 512);
+ REQUIRE(args::get(bs) == 512);
REQUIRE(skip);
- REQUIRE(skip.value == 8);
+ REQUIRE(args::get(skip) == 8);
REQUIRE(input);
- REQUIRE(input.value == "/dev/null");
+ REQUIRE(args::get(input) == "/dev/null");
REQUIRE_FALSE(output);
}
@@ -263,11 +289,11 @@ TEST_CASE("Custom parser prefixes (Some Windows styles)", "[args]")
args::ArgFlag<std::string> output(parser, "BLOCK SIZE", "Block size", args::Matcher({"of"}));
parser.ParseArgs(std::vector<std::string>{"/skip:8", "/if:/dev/null"});
REQUIRE_FALSE(bs);
- REQUIRE(bs.value == 512);
+ REQUIRE(args::get(bs) == 512);
REQUIRE(skip);
- REQUIRE(skip.value == 8);
+ REQUIRE(args::get(skip) == 8);
REQUIRE(input);
- REQUIRE(input.value == "/dev/null");
+ REQUIRE(args::get(input) == "/dev/null");
REQUIRE_FALSE(output);
}