From 324a9c738decace7446bbae52c46a25d7a8c689a Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Tue, 31 Jan 2017 09:18:56 -0500 Subject: [PATCH] Adding make_* options --- include/CLI.hpp | 128 ++++++++++++++++++++++++++++++++++++++++++++-- tests/CLITest.cpp | 17 +++++- 2 files changed, 140 insertions(+), 5 deletions(-) diff --git a/include/CLI.hpp b/include/CLI.hpp index c9e9ae45..8469e9f9 100644 --- a/include/CLI.hpp +++ b/include/CLI.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -450,6 +450,10 @@ public: logit(subcommands.back()->name); return subcommands.back().get(); } + + + //------------ ADD STYLE ---------// + /// Add an option, will automatically understand the type for common types. /** To use, create a variable with the expected type, and pass it in after the name. * After start is called, you can use count to see if the value was passed, and @@ -563,7 +567,7 @@ public: Option* add_set( std::string name, ///< The name, short,long T &member, ///< The selected member of the set - std::unordered_set options, ///< The set of posibilities + std::set options, ///< The set of posibilities std::string discription="", ///< Discription string Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) ) { @@ -581,14 +585,20 @@ public: bool retval = lexical_cast(res[0][0], member); if(!retval) return false; - return std::find(std::begin(options), std::end(options), retval) != std::end(options); + return std::find(std::begin(options), std::end(options), member) != std::end(options); }; return add_option(name, fun, discription, opts); } + + + + //------------ MAKE STYLE ---------// + /// Prototype for new output style - template + template::value, detail::enabler> = dummy> Value make_option( std::string name, ///< The name, short,long std::string discription="", @@ -611,7 +621,117 @@ public: add_option(name, fun, discription, opts); return out; } + + /// Prototype for new output style with default + template::value, detail::enabler> = dummy> + Value make_option( + std::string name, ///< The name, short,long + const T& default_value, + std::string discription="", + Combiner opts=VALIDATORS + ) { + + Value out(name); + std::shared_ptr> ptr = out.value; + ptr->reset(new T(default_value)); // resets the internal ptr + + CLI::callback_t fun = [ptr](CLI::results_t res){ + if(res.size()!=1) { + return false; + } + if(res[0].size()!=1) { + return false; + } + ptr->reset(new T()); // resets the internal ptr + return lexical_cast(res[0][0], **ptr); + }; + add_option(name, fun, discription, opts); + return out; + } + /// Prototype for new output style + template + Value> make_option( + std::string name, ///< The name, short,long + std::string discription="", + Combiner opts=VALIDATORS + ) { + + if(opts.num==0) + throw IncorrectConstruction("Must have ARGS or be a vector."); + + Value> out(name); + std::shared_ptr >> ptr = out.value; + + CLI::callback_t fun = [ptr](CLI::results_t res){ + ptr->reset(new std::vector()); // resets the internal ptr + bool retval = true; + for(const auto &a : res) + for(const auto &b : a) { + (*ptr)->emplace_back(); + retval &= lexical_cast(b, (*ptr)->back()); + } + return (*ptr)->size() > 0 && retval; + }; + add_option(name, fun, discription, opts); + return out; + } + + + /// Prototype for new output style: flag + Value make_flag( + std::string name, ///< The name, short,long + std::string discription="" + ) { + + Value out(name); + std::shared_ptr> ptr = out.value; + ptr->reset(new int()); // resets the internal ptr + **ptr = 0; + + CLI::callback_t fun = [ptr](CLI::results_t res){ + **ptr = (int) res.size(); + return true; + }; + add_option(name, fun, discription, NOTHING); + return out; + } + + /// Add set of options + template + Value make_set( + std::string name, ///< The name, short,long + std::set options, ///< The set of posibilities + std::string discription="", ///< Discription string + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS()) + ) { + + Value out(name); + std::shared_ptr> ptr = out.value; + + if(opts.num!=1) + throw IncorrectConstruction("Must have ARGS(1)."); + + CLI::callback_t fun = [ptr, options](CLI::results_t res){ + if(res.size()!=1) { + return false; + } + if(res[0].size()!=1) { + return false; + } + ptr->reset(new T()); + bool retval = lexical_cast(res[0][0], **ptr); + if(!retval) + return false; + return std::find(std::begin(options), std::end(options), **ptr) != std::end(options); + }; + + add_option(name, fun, discription, opts); + return out; + } + + /// Parses the command line - throws errors void parse(int argc, char **argv) { diff --git a/tests/CLITest.cpp b/tests/CLITest.cpp index 52f9949a..308b8087 100644 --- a/tests/CLITest.cpp +++ b/tests/CLITest.cpp @@ -249,6 +249,22 @@ TEST_F(TApp, FileExists) { EXPECT_FALSE(CLI::_ExistingFile(myfile)); } +TEST_F(TApp, InSet) { + + std::string choice; + app.add_set("q,quick", choice, {"one", "two", "three"}); + + args = {"--quick", "two"}; + + EXPECT_NO_THROW(run()); + EXPECT_EQ("two", choice); + + app.reset(); + + args = {"--quick", "four"}; + EXPECT_THROW(run(), CLI::ParseError); +} + TEST_F(TApp, VectorFixedString) { std::vector strvec; std::vector answer{"mystring", "mystring2", "mystring3"}; @@ -366,7 +382,6 @@ TEST_F(TAppValue, OneString) { } -// TODO: Add vector arguments // TODO: Maybe add function to call on subcommand parse? Stashed. // TODO: Check help output // TODO: Add default/type info to help