diff --git a/README.md b/README.md index db61f643b..16e959d56 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ Before parsing, you can set the following options: - `->description(str)`: Set/change the description. - `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`, and `->join()`. This will only affect options expecting 1 argument or bool flags (which do not inherit their default but always start with a specific policy). - `->check(CLI::IsMember(...))`: Require an option be a member of a given set. See below for options. +- `->transform(CLI::IsMember(...))`: Require an option be a member of a given set or map. Can change the parse. See below for options. - `->check(CLI::ExistingFile)`: Requires that the file exists if given. - `->check(CLI::ExistingDirectory)`: Requires that the directory exists. - `->check(CLI::ExistingPath)`: Requires that the path (file or directory) exists. @@ -283,7 +284,9 @@ of `IsMember`: - `CLI::IsMember({"choice1", "choice2"})`: Select from exact match to choices. - `CLI::IsMember({"choice1", "choice2"}, CLI::ignore_case, CLI::ignore_underscore)`: Match things like `Choice_1`, too. - `CLI::IsMember(std::set({2,3,4}))`: Most containers and types work; you just need `std::begin`, `std::end`, and `::value_type`. +- `CLI::IsMember(std::map({{"one", 1}, {"two", 2}}))`: You can use maps; in `->transform()` these replace the matched value with the key. - `auto p = std::make_shared>(std::initializer_list("one", "two")); CLI::IsMember(p)`: You can modify `p` later. +- Note that you can combine validators with `|`, and only the matched validation will modify the output in transform. The first `IsMember` is the only one that will print in help, though the error message will include all Validators. On the command line, options can be given as: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ba303b241..01590c319 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -130,7 +130,7 @@ add_cli_exe(enum enum.cpp) add_test(NAME enum_pass COMMAND enum -l 1) add_test(NAME enum_fail COMMAND enum -l 4) set_property(TEST enum_fail PROPERTY PASS_REGULAR_EXPRESSION - "--level: 4 not in {0,1,2}") + "--level: 4 not in {High,Medium,Low} | 4 not in {0,1,2}") add_cli_exe(modhelp modhelp.cpp) add_test(NAME modhelp COMMAND modhelp -a test -h) diff --git a/examples/enum.cpp b/examples/enum.cpp index 68c78f63c..19b92fbde 100644 --- a/examples/enum.cpp +++ b/examples/enum.cpp @@ -1,26 +1,25 @@ #include +#include #include enum class Level : int { High, Medium, Low }; -std::istream &operator>>(std::istream &in, Level &level) { - int i; - in >> i; - level = static_cast(i); - return in; -} - -std::ostream &operator<<(std::ostream &in, const Level &level) { return in << static_cast(level); } - int main(int argc, char **argv) { CLI::App app; + std::map map = {{"High", Level::High}, {"Medium", Level::Medium}, {"Low", Level::Low}}; + Level level; + app.add_option("-l,--level", level, "Level settings") - ->check(CLI::IsMember({Level::High, Level::Medium, Level::Low})) - ->type_name("enum/Level in {High=0, Medium=1, Low=2}"); + ->required() + ->transform(CLI::IsMember(map, CLI::ignore_case) | CLI::IsMember({Level::High, Level::Medium, Level::Low})); CLI11_PARSE(app, argc, argv); + // CLI11's built in enum streaming can be used outside CLI11 like this: + using namespace CLI::enums; + std::cout << "Enum received: " << level << std::endl; + return 0; } diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 6ab804e89..d1aee0e98 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -695,32 +695,32 @@ class App { } /// Add set of options, string only, ignore case (no default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_case)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_case)) instead") Option *add_set_ignore_case(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{options, CLI::ignore_case}); + opt->transform(IsMember{options, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore case (no default, set can be changed afterwards - do not destroy the /// set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_case)) with a (shared) pointer instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_case)) with a (shared) pointer instead") Option *add_mutable_set_ignore_case(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{&options, CLI::ignore_case}); + opt->transform(IsMember{&options, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore case (default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_case)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_case)) instead") Option *add_set_ignore_case(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities @@ -728,13 +728,13 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{options, CLI::ignore_case}); + opt->transform(IsMember{options, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore case (default, set can be changed afterwards - do not destroy the set) /// DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(...)) with a (shared) pointer instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(...)) with a (shared) pointer instead") Option *add_mutable_set_ignore_case(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities @@ -742,37 +742,37 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{&options, CLI::ignore_case}); + opt->transform(IsMember{&options, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore underscore (no default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_underscore)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_underscore)) instead") Option *add_set_ignore_underscore(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{options, CLI::ignore_underscore}); + opt->transform(IsMember{options, CLI::ignore_underscore}); return opt; } /// Add set of options, string only, ignore underscore (no default, set can be changed afterwards - do not destroy /// the set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_underscore)) with a (shared) pointer instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_underscore)) with a (shared) pointer instead") Option *add_mutable_set_ignore_underscore(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{options, CLI::ignore_underscore}); + opt->transform(IsMember{options, CLI::ignore_underscore}); return opt; } /// Add set of options, string only, ignore underscore (default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_underscore)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_underscore)) instead") Option *add_set_ignore_underscore(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities @@ -780,13 +780,13 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{options, CLI::ignore_underscore}); + opt->transform(IsMember{options, CLI::ignore_underscore}); return opt; } /// Add set of options, string only, ignore underscore (default, set can be changed afterwards - do not destroy the /// set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_underscore)) with a (shared) pointer instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_underscore)) with a (shared) pointer instead") Option *add_mutable_set_ignore_underscore(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities @@ -794,38 +794,38 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{&options, CLI::ignore_underscore}); + opt->transform(IsMember{&options, CLI::ignore_underscore}); return opt; } /// Add set of options, string only, ignore underscore and case (no default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) instead") Option *add_set_ignore_case_underscore(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{options, CLI::ignore_underscore, CLI::ignore_case}); + opt->transform(IsMember{options, CLI::ignore_underscore, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore underscore and case (no default, set can be changed afterwards - do not /// destroy the set) DEPRECATED CLI11_DEPRECATED( - "Use ->check(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) with a (shared) pointer instead") + "Use ->transform(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) with a (shared) pointer instead") Option *add_mutable_set_ignore_case_underscore(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities std::string description = "") { Option *opt = add_option(option_name, member, std::move(description)); - opt->check(IsMember{&options, CLI::ignore_underscore, CLI::ignore_case}); + opt->transform(IsMember{&options, CLI::ignore_underscore, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore underscore and case (default, static set) DEPRECATED - CLI11_DEPRECATED("Use ->check(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) instead") + CLI11_DEPRECATED("Use ->transform(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) instead") Option *add_set_ignore_case_underscore(std::string option_name, std::string &member, ///< The selected member of the set std::set options, ///< The set of possibilities @@ -833,14 +833,14 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{options, CLI::ignore_underscore, CLI::ignore_case}); + opt->transform(IsMember{options, CLI::ignore_underscore, CLI::ignore_case}); return opt; } /// Add set of options, string only, ignore underscore and case (default, set can be changed afterwards - do not /// destroy the set) DEPRECATED CLI11_DEPRECATED( - "Use ->check(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) with a (shared) pointer instead") + "Use ->transform(CLI::IsMember(..., CLI::ignore_case, CLI::ignore_underscore)) with a (shared) pointer instead") Option *add_mutable_set_ignore_case_underscore(std::string option_name, std::string &member, ///< The selected member of the set const std::set &options, ///< The set of possibilities @@ -848,7 +848,7 @@ class App { bool defaulted) { Option *opt = add_option(option_name, member, std::move(description), defaulted); - opt->check(IsMember{&options, CLI::ignore_underscore, CLI::ignore_case}); + opt->transform(IsMember{&options, CLI::ignore_underscore, CLI::ignore_case}); return opt; } diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 4c57af83b..9a0a9f865 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -303,7 +303,12 @@ class Option : public OptionBase