Commit 324a9c738decace7446bbae52c46a25d7a8c689a

Authored by Henry Fredrick Schreiner
1 parent 074d0339

Adding make_* options

include/CLI.hpp
... ... @@ -11,7 +11,7 @@
11 11 #include <algorithm>
12 12 #include <sstream>
13 13 #include <type_traits>
14   -#include <unordered_set>
  14 +#include <set>
15 15 #include <iomanip>
16 16 #include <numeric>
17 17  
... ... @@ -450,6 +450,10 @@ public:
450 450 logit(subcommands.back()->name);
451 451 return subcommands.back().get();
452 452 }
  453 +
  454 +
  455 + //------------ ADD STYLE ---------//
  456 +
453 457 /// Add an option, will automatically understand the type for common types.
454 458 /** To use, create a variable with the expected type, and pass it in after the name.
455 459 * After start is called, you can use count to see if the value was passed, and
... ... @@ -563,7 +567,7 @@ public:
563 567 Option* add_set(
564 568 std::string name, ///< The name, short,long
565 569 T &member, ///< The selected member of the set
566   - std::unordered_set<T> options, ///< The set of posibilities
  570 + std::set<T> options, ///< The set of posibilities
567 571 std::string discription="", ///< Discription string
568 572 Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS())
569 573 ) {
... ... @@ -581,14 +585,20 @@ public:
581 585 bool retval = lexical_cast(res[0][0], member);
582 586 if(!retval)
583 587 return false;
584   - return std::find(std::begin(options), std::end(options), retval) != std::end(options);
  588 + return std::find(std::begin(options), std::end(options), member) != std::end(options);
585 589 };
586 590  
587 591 return add_option(name, fun, discription, opts);
588 592 }
589 593  
  594 +
  595 +
  596 +
  597 + //------------ MAKE STYLE ---------//
  598 +
590 599 /// Prototype for new output style
591   - template<typename T = std::string>
  600 + template<typename T = std::string,
  601 + enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
592 602 Value<T> make_option(
593 603 std::string name, ///< The name, short,long
594 604 std::string discription="",
... ... @@ -611,7 +621,117 @@ public:
611 621 add_option(name, fun, discription, opts);
612 622 return out;
613 623 }
  624 +
  625 + /// Prototype for new output style with default
  626 + template<typename T = std::string,
  627 + enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
  628 + Value<T> make_option(
  629 + std::string name, ///< The name, short,long
  630 + const T& default_value,
  631 + std::string discription="",
  632 + Combiner opts=VALIDATORS
  633 + ) {
  634 +
  635 + Value<T> out(name);
  636 + std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
  637 + ptr->reset(new T(default_value)); // resets the internal ptr
  638 +
  639 + CLI::callback_t fun = [ptr](CLI::results_t res){
  640 + if(res.size()!=1) {
  641 + return false;
  642 + }
  643 + if(res[0].size()!=1) {
  644 + return false;
  645 + }
  646 + ptr->reset(new T()); // resets the internal ptr
  647 + return lexical_cast(res[0][0], **ptr);
  648 + };
  649 + add_option(name, fun, discription, opts);
  650 + return out;
  651 + }
614 652  
  653 + /// Prototype for new output style
  654 + template<typename T>
  655 + Value<std::vector<T>> make_option(
  656 + std::string name, ///< The name, short,long
  657 + std::string discription="",
  658 + Combiner opts=VALIDATORS
  659 + ) {
  660 +
  661 + if(opts.num==0)
  662 + throw IncorrectConstruction("Must have ARGS or be a vector.");
  663 +
  664 + Value<std::vector<T>> out(name);
  665 + std::shared_ptr<std::unique_ptr<std::vector<T> >> ptr = out.value;
  666 +
  667 + CLI::callback_t fun = [ptr](CLI::results_t res){
  668 + ptr->reset(new std::vector<T>()); // resets the internal ptr
  669 + bool retval = true;
  670 + for(const auto &a : res)
  671 + for(const auto &b : a) {
  672 + (*ptr)->emplace_back();
  673 + retval &= lexical_cast(b, (*ptr)->back());
  674 + }
  675 + return (*ptr)->size() > 0 && retval;
  676 + };
  677 + add_option(name, fun, discription, opts);
  678 + return out;
  679 + }
  680 +
  681 +
  682 + /// Prototype for new output style: flag
  683 + Value<int> make_flag(
  684 + std::string name, ///< The name, short,long
  685 + std::string discription=""
  686 + ) {
  687 +
  688 + Value<int> out(name);
  689 + std::shared_ptr<std::unique_ptr<int>> ptr = out.value;
  690 + ptr->reset(new int()); // resets the internal ptr
  691 + **ptr = 0;
  692 +
  693 + CLI::callback_t fun = [ptr](CLI::results_t res){
  694 + **ptr = (int) res.size();
  695 + return true;
  696 + };
  697 + add_option(name, fun, discription, NOTHING);
  698 + return out;
  699 + }
  700 +
  701 + /// Add set of options
  702 + template<typename T>
  703 + Value<T> make_set(
  704 + std::string name, ///< The name, short,long
  705 + std::set<T> options, ///< The set of posibilities
  706 + std::string discription="", ///< Discription string
  707 + Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS())
  708 + ) {
  709 +
  710 + Value<T> out(name);
  711 + std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
  712 +
  713 + if(opts.num!=1)
  714 + throw IncorrectConstruction("Must have ARGS(1).");
  715 +
  716 + CLI::callback_t fun = [ptr, options](CLI::results_t res){
  717 + if(res.size()!=1) {
  718 + return false;
  719 + }
  720 + if(res[0].size()!=1) {
  721 + return false;
  722 + }
  723 + ptr->reset(new T());
  724 + bool retval = lexical_cast(res[0][0], **ptr);
  725 + if(!retval)
  726 + return false;
  727 + return std::find(std::begin(options), std::end(options), **ptr) != std::end(options);
  728 + };
  729 +
  730 + add_option(name, fun, discription, opts);
  731 + return out;
  732 + }
  733 +
  734 +
615 735  
616 736 /// Parses the command line - throws errors
617 737 void parse(int argc, char **argv) {
... ...
tests/CLITest.cpp
... ... @@ -249,6 +249,22 @@ TEST_F(TApp, FileExists) {
249 249 EXPECT_FALSE(CLI::_ExistingFile(myfile));
250 250 }
251 251  
  252 +TEST_F(TApp, InSet) {
  253 +
  254 + std::string choice;
  255 + app.add_set("q,quick", choice, {"one", "two", "three"});
  256 +
  257 + args = {"--quick", "two"};
  258 +
  259 + EXPECT_NO_THROW(run());
  260 + EXPECT_EQ("two", choice);
  261 +
  262 + app.reset();
  263 +
  264 + args = {"--quick", "four"};
  265 + EXPECT_THROW(run(), CLI::ParseError);
  266 +}
  267 +
252 268 TEST_F(TApp, VectorFixedString) {
253 269 std::vector<std::string> strvec;
254 270 std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
... ... @@ -366,7 +382,6 @@ TEST_F(TAppValue, OneString) {
366 382  
367 383 }
368 384  
369   -// TODO: Add vector arguments
370 385 // TODO: Maybe add function to call on subcommand parse? Stashed.
371 386 // TODO: Check help output
372 387 // TODO: Add default/type info to help
... ...