diff --git a/include/CLI.hpp b/include/CLI.hpp index 1faf942..2245c66 100644 --- a/include/CLI.hpp +++ b/include/CLI.hpp @@ -160,6 +160,9 @@ struct HorribleError : public Error { struct IncorrectConstruction : public Error { IncorrectConstruction(std::string name) : Error("IncorrectConstruction", name, 8) {} }; +struct EmptyError : public Error { + EmptyError(std::string name) : Error("EmptyError", name, 9) {} +}; const std::regex reg_split{R"regex((?:([a-zA-Z0-9]?)(?:,|$)|^)([a-zA-Z0-9][a-zA-Z0-9_\-]*)?)regex"}; const std::regex reg_short{R"regex(-([^-])(.*))regex"}; @@ -372,8 +375,32 @@ bool lexical_cast(std::string input, T& output) { enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND}; + class App; +// Prototype return value test +template +class Value { + friend App; +protected: + std::unique_ptr> value {new std::unique_ptr()}; + std::string name; +public: + Value(std::string name) : name(name) {} + operator bool() const {return (bool) *value;} + //explicit operator T () const {return **this;} + T operator *() const { + if(*value) { + //std::cout << "Succ" << std::endl; + return **value; + } + else { + //std::cout << "Throwing!!!" << std::endl; + throw EmptyError(name); + } + } +}; + /// Creates a command line program, with very few defaults. /** To use, create a new Program() instance with argc, argv, and a help discription. The templated * add_option methods make it easy to prepare options. Remember to call `.start` before starting your @@ -558,6 +585,30 @@ public: return add_option(name, fun, discription, opts); } + /// Prototype for new output style + template + Value make_option( + std::string name, ///< The name, short,long + std::string discription="", + Combiner opts=VALIDATORS + ) { + + Value out(name); + std::unique_ptr *ptr = out.value.get(); + + 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()); + return lexical_cast(res[0][0], **ptr); + }; + add_option(name, fun, discription, opts); + return std::move(out); + } /// Parses the command line - throws errors diff --git a/tests/CLITest.cpp b/tests/CLITest.cpp index 694420d..52f9949 100644 --- a/tests/CLITest.cpp +++ b/tests/CLITest.cpp @@ -345,10 +345,31 @@ TEST_F(SubcommandProgram, SpareSub) { EXPECT_THROW(run(), CLI::PositionalError); } +class TAppValue : public TApp {}; + +TEST_F(TAppValue, OneString) { + auto str = app.make_option("s,string"); + std::string v; + args = {"--string", "mystring"}; + EXPECT_FALSE((bool) str); + EXPECT_THROW(v = *str, CLI::EmptyError); + //EXPECT_THROW(v = str, CLI::EmptyError); + EXPECT_FALSE((bool) str); + EXPECT_NO_THROW(run()); + EXPECT_TRUE((bool) str); + EXPECT_NO_THROW(v = *str); + EXPECT_NO_THROW(v = str); + + EXPECT_EQ(1, app.count("s")); + EXPECT_EQ(1, app.count("string")); + EXPECT_EQ(*str, "mystring"); + +} + // 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 // TODO: Add set checking // TODO: Try all of the options together -// TODO: Add make_option alternative with type +// TODO: Add make_option alternative with type? Cancelled for now