Commit 0667d7a88e53248bb5d6b63ac306e24133b334c4

Authored by Henry Fredrick Schreiner
1 parent 47a7c3b8

test Value type

include/CLI.hpp
... ... @@ -160,6 +160,9 @@ struct HorribleError : public Error {
160 160 struct IncorrectConstruction : public Error {
161 161 IncorrectConstruction(std::string name) : Error("IncorrectConstruction", name, 8) {}
162 162 };
  163 +struct EmptyError : public Error {
  164 + EmptyError(std::string name) : Error("EmptyError", name, 9) {}
  165 +};
163 166  
164 167 const std::regex reg_split{R"regex((?:([a-zA-Z0-9]?)(?:,|$)|^)([a-zA-Z0-9][a-zA-Z0-9_\-]*)?)regex"};
165 168 const std::regex reg_short{R"regex(-([^-])(.*))regex"};
... ... @@ -372,8 +375,32 @@ bool lexical_cast(std::string input, T& output) {
372 375  
373 376 enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND};
374 377  
  378 +
375 379 class App;
376 380  
  381 +// Prototype return value test
  382 +template <typename T>
  383 +class Value {
  384 + friend App;
  385 +protected:
  386 + std::unique_ptr<std::unique_ptr<T>> value {new std::unique_ptr<T>()};
  387 + std::string name;
  388 +public:
  389 + Value(std::string name) : name(name) {}
  390 + operator bool() const {return (bool) *value;}
  391 + //explicit operator T () const {return **this;}
  392 + T operator *() const {
  393 + if(*value) {
  394 + //std::cout << "Succ" << std::endl;
  395 + return **value;
  396 + }
  397 + else {
  398 + //std::cout << "Throwing!!!" << std::endl;
  399 + throw EmptyError(name);
  400 + }
  401 + }
  402 +};
  403 +
377 404 /// Creates a command line program, with very few defaults.
378 405 /** To use, create a new Program() instance with argc, argv, and a help discription. The templated
379 406 * add_option methods make it easy to prepare options. Remember to call `.start` before starting your
... ... @@ -558,6 +585,30 @@ public:
558 585 return add_option(name, fun, discription, opts);
559 586 }
560 587  
  588 + /// Prototype for new output style
  589 + template<typename T = std::string>
  590 + Value<T> make_option(
  591 + std::string name, ///< The name, short,long
  592 + std::string discription="",
  593 + Combiner opts=VALIDATORS
  594 + ) {
  595 +
  596 + Value<T> out(name);
  597 + std::unique_ptr<T> *ptr = out.value.get();
  598 +
  599 + CLI::callback_t fun = [ptr](CLI::results_t res){
  600 + if(res.size()!=1) {
  601 + return false;
  602 + }
  603 + if(res[0].size()!=1) {
  604 + return false;
  605 + }
  606 + ptr->reset(new T());
  607 + return lexical_cast(res[0][0], **ptr);
  608 + };
  609 + add_option(name, fun, discription, opts);
  610 + return std::move(out);
  611 + }
561 612  
562 613  
563 614 /// Parses the command line - throws errors
... ...
tests/CLITest.cpp
... ... @@ -345,10 +345,31 @@ TEST_F(SubcommandProgram, SpareSub) {
345 345 EXPECT_THROW(run(), CLI::PositionalError);
346 346 }
347 347  
  348 +class TAppValue : public TApp {};
  349 +
  350 +TEST_F(TAppValue, OneString) {
  351 + auto str = app.make_option("s,string");
  352 + std::string v;
  353 + args = {"--string", "mystring"};
  354 + EXPECT_FALSE((bool) str);
  355 + EXPECT_THROW(v = *str, CLI::EmptyError);
  356 + //EXPECT_THROW(v = str, CLI::EmptyError);
  357 + EXPECT_FALSE((bool) str);
  358 + EXPECT_NO_THROW(run());
  359 + EXPECT_TRUE((bool) str);
  360 + EXPECT_NO_THROW(v = *str);
  361 + EXPECT_NO_THROW(v = str);
  362 +
  363 + EXPECT_EQ(1, app.count("s"));
  364 + EXPECT_EQ(1, app.count("string"));
  365 + EXPECT_EQ(*str, "mystring");
  366 +
  367 +}
  368 +
348 369 // TODO: Add vector arguments
349 370 // TODO: Maybe add function to call on subcommand parse? Stashed.
350 371 // TODO: Check help output
351 372 // TODO: Add default/type info to help
352 373 // TODO: Add set checking
353 374 // TODO: Try all of the options together
354   -// TODO: Add make_option alternative with type
  375 +// TODO: Add make_option alternative with type? Cancelled for now
... ...