Browse Source

feat: pass through rest() to an argument handler.

Sam Jaffe 3 years ago
parent
commit
399c4424d4

+ 6 - 0
include/program_args/arguments.h

@@ -36,6 +36,11 @@ protected:
   auto action(LongArg name, std::string const &description = "");
   auto argument(size_t index, LongArg name,
                 std::string const & description = "");
+  std::vector<std::string> rest(LongArg name = "args") {
+    rest_name_ = name;
+    size_t const i = std::min(arguments.size(), argument_names.size());
+    return {arguments.begin() + i, arguments.end()};
+  }
   auto flag(LongArg name, std::string const & description = "");
   auto flag(LongArg name, char abbrev, std::string const & description = "");
   auto flag(char abbrev, std::string const & description = "");
@@ -65,6 +70,7 @@ private:
   using make_hook_t = std::function<main_callback_t(size_t, char const * const *)>;
   // Metadata variables
   bool primed_{false};
+  std::string rest_name_;
   std::map<option_id, std::string> argument_descriptions;
   std::map<size_t, option_id> argument_names;
   std::map<option_id, std::string> option_descriptions;

+ 3 - 0
include/program_args/arguments_impl.hpp

@@ -213,6 +213,9 @@ template <typename Impl> void Arguments<Impl>::usage() const {
   for (auto & [index, name] : argument_names) {
     std::cout << " " << (index == optional_from ? "[" : "") << name;
   }
+  if (rest_name_.size()) {
+    std::cout << " [" << rest_name_ << "...]";
+  }
   if (optional_from != no_optional_args) { std::cout << "]"; }
   std::cout << "\nArgument Arguments:\n";
   for (auto & [name, desc] : argument_descriptions) {

+ 20 - 0
test/argument_test.cpp

@@ -11,6 +11,7 @@
 
 using testing::ElementsAre;
 using testing::Eq;
+using testing::IsEmpty;
 
 template <typename T, size_t N> static T parse(char const * const (&argv)[N]) {
   return T(N, argv);
@@ -93,3 +94,22 @@ struct OOOArgumentTest : program::Arguments<OOOArgumentTest> {
 TEST(OOOArgumentTest, ThrowsOnConstruction) {
   EXPECT_THROW(OOOArgumentTest(), program::ArgumentStructureError);
 }
+
+struct RestArgsTest : program::Arguments<RestArgsTest> {
+  using Arguments::Arguments;
+  
+  std::string arg0 = argument(0, "arg0") = "";
+  std::vector<std::string> args = rest();
+};
+
+TEST(RestArgsTest, SetsOptionalArgFirst) {
+  auto const options = parse<RestArgsTest>({"", "A"});
+  EXPECT_THAT(options.arg0, "A");
+  EXPECT_THAT(options.args, IsEmpty());
+}
+
+TEST(RestArgsTest, ForwardsOverflowIntoRest) {
+  auto const options = parse<RestArgsTest>({"", "A", "B", "C"});
+  EXPECT_THAT(options.arg0, "A");
+  EXPECT_THAT(options.args, ElementsAre("B", "C"));
+}