Commit 34bd80971bbb35770909ecfa26acc7f146646c09

Authored by Philip Top
Committed by GitHub
1 parent 73e94b22

allow the use of `allow_extra_args(false)` to specify only a single argument at …

…a time with a container output. (#484)
README.md
@@ -322,6 +322,7 @@ Before parsing, you can set the following options: @@ -322,6 +322,7 @@ Before parsing, you can set the following options:
322 - `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments). 322 - `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
323 - `->ignore_underscore()`: Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character 323 - `->ignore_underscore()`: Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character
324 - `->disable_flag_override()`: From the command line long form flag options can be assigned a value on the command line using the `=` notation `--flag=value`. If this behavior is not desired, the `disable_flag_override()` disables it and will generate an exception if it is done on the command line. The `=` does not work with short form flag options. 324 - `->disable_flag_override()`: From the command line long form flag options can be assigned a value on the command line using the `=` notation `--flag=value`. If this behavior is not desired, the `disable_flag_override()` disables it and will generate an exception if it is done on the command line. The `=` does not work with short form flag options.
  325 +- `->allow_extra_args(true/false)`: 🚧 If set to true the option will take an unlimited number of arguments like a vector, if false it will limit the number of arguments to the size of the type used in the option. Default value depends on the nature of the type use, containers default to true, others default to false.
325 - `->delimiter(char)`: Allows specification of a custom delimiter for separating single arguments into vector arguments, for example specifying `->delimiter(',')` on an option would result in `--opt=1,2,3` producing 3 elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a vector value. 326 - `->delimiter(char)`: Allows specification of a custom delimiter for separating single arguments into vector arguments, for example specifying `->delimiter(',')` on an option would result in `--opt=1,2,3` producing 3 elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a vector value.
326 - `->description(str)`: Set/change the description. 327 - `->description(str)`: Set/change the description.
327 - `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`,`->take_all()`, 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). 328 - `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`,`->take_all()`, 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).
include/CLI/App.hpp
@@ -2761,7 +2761,12 @@ class App { @@ -2761,7 +2761,12 @@ class App {
2761 } 2761 }
2762 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min()); 2762 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
2763 int max_num = op->get_items_expected_max(); 2763 int max_num = op->get_items_expected_max();
2764 - 2764 + // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
  2765 + // set. 16 is somewhat arbitrary (needs to be at least 4)
  2766 + if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
  2767 + auto tmax = op->get_type_size_max();
  2768 + max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
  2769 + }
2765 // Make sure we always eat the minimum for unlimited vectors 2770 // Make sure we always eat the minimum for unlimited vectors
2766 int collected = 0; // total number of arguments collected 2771 int collected = 0; // total number of arguments collected
2767 int result_count = 0; // local variable for number of results in a single arg string 2772 int result_count = 0; // local variable for number of results in a single arg string
tests/OptionTypeTest.cpp
@@ -838,3 +838,29 @@ TEST_F(TApp, tupleTwoVectors) { @@ -838,3 +838,29 @@ TEST_F(TApp, tupleTwoVectors) {
838 EXPECT_EQ(std::get<0>(cv).size(), 2U); 838 EXPECT_EQ(std::get<0>(cv).size(), 2U);
839 EXPECT_EQ(std::get<1>(cv).size(), 3U); 839 EXPECT_EQ(std::get<1>(cv).size(), 3U);
840 } 840 }
  841 +
  842 +TEST_F(TApp, vectorSingleArg) {
  843 +
  844 + std::vector<int> cv;
  845 + app.add_option("-c", cv)->allow_extra_args(false);
  846 + std::string extra;
  847 + app.add_option("args", extra);
  848 + args = {"-c", "1", "-c", "2", "4"};
  849 +
  850 + run();
  851 + EXPECT_EQ(cv.size(), 2U);
  852 + EXPECT_EQ(extra, "4");
  853 +}
  854 +
  855 +TEST_F(TApp, vectorDoubleArg) {
  856 +
  857 + std::vector<std::pair<int, std::string>> cv;
  858 + app.add_option("-c", cv)->allow_extra_args(false);
  859 + std::vector<std::string> extras;
  860 + app.add_option("args", extras);
  861 + args = {"-c", "1", "bob", "-c", "2", "apple", "4", "key"};
  862 +
  863 + run();
  864 + EXPECT_EQ(cv.size(), 2U);
  865 + EXPECT_EQ(extras.size(), 2U);
  866 +}