Commit 0667d7a88e53248bb5d6b63ac306e24133b334c4
1 parent
47a7c3b8
test Value type
Showing
2 changed files
with
73 additions
and
1 deletions
include/CLI.hpp
| @@ -160,6 +160,9 @@ struct HorribleError : public Error { | @@ -160,6 +160,9 @@ struct HorribleError : public Error { | ||
| 160 | struct IncorrectConstruction : public Error { | 160 | struct IncorrectConstruction : public Error { |
| 161 | IncorrectConstruction(std::string name) : Error("IncorrectConstruction", name, 8) {} | 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 | const std::regex reg_split{R"regex((?:([a-zA-Z0-9]?)(?:,|$)|^)([a-zA-Z0-9][a-zA-Z0-9_\-]*)?)regex"}; | 167 | const std::regex reg_split{R"regex((?:([a-zA-Z0-9]?)(?:,|$)|^)([a-zA-Z0-9][a-zA-Z0-9_\-]*)?)regex"}; |
| 165 | const std::regex reg_short{R"regex(-([^-])(.*))regex"}; | 168 | const std::regex reg_short{R"regex(-([^-])(.*))regex"}; |
| @@ -372,8 +375,32 @@ bool lexical_cast(std::string input, T& output) { | @@ -372,8 +375,32 @@ bool lexical_cast(std::string input, T& output) { | ||
| 372 | 375 | ||
| 373 | enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND}; | 376 | enum class Classifer {NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND}; |
| 374 | 377 | ||
| 378 | + | ||
| 375 | class App; | 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 | /// Creates a command line program, with very few defaults. | 404 | /// Creates a command line program, with very few defaults. |
| 378 | /** To use, create a new Program() instance with argc, argv, and a help discription. The templated | 405 | /** To use, create a new Program() instance with argc, argv, and a help discription. The templated |
| 379 | * add_option methods make it easy to prepare options. Remember to call `.start` before starting your | 406 | * add_option methods make it easy to prepare options. Remember to call `.start` before starting your |
| @@ -558,6 +585,30 @@ public: | @@ -558,6 +585,30 @@ public: | ||
| 558 | return add_option(name, fun, discription, opts); | 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 | /// Parses the command line - throws errors | 614 | /// Parses the command line - throws errors |
tests/CLITest.cpp
| @@ -345,10 +345,31 @@ TEST_F(SubcommandProgram, SpareSub) { | @@ -345,10 +345,31 @@ TEST_F(SubcommandProgram, SpareSub) { | ||
| 345 | EXPECT_THROW(run(), CLI::PositionalError); | 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 | // TODO: Add vector arguments | 369 | // TODO: Add vector arguments |
| 349 | // TODO: Maybe add function to call on subcommand parse? Stashed. | 370 | // TODO: Maybe add function to call on subcommand parse? Stashed. |
| 350 | // TODO: Check help output | 371 | // TODO: Check help output |
| 351 | // TODO: Add default/type info to help | 372 | // TODO: Add default/type info to help |
| 352 | // TODO: Add set checking | 373 | // TODO: Add set checking |
| 353 | // TODO: Try all of the options together | 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 |