Commit 518615844270bba877087501677e0534a559272d

Authored by Henry Schreiner
Committed by GitHub
1 parent d4654144

Rename requires to needs (#82)

* Adding fix for #75, rename requires to needs

* Removing check for install commands (should still be run in subproject)
CHANGELOG.md
1 ## Version 1.4 (in progress) 1 ## Version 1.4 (in progress)
2 * Added `get_parent()` to access the parent from a subcommand 2 * Added `get_parent()` to access the parent from a subcommand
  3 +* `app.allow_ini_extras()` added to allow extras in INI files [#70]
  4 +* Adding install support for CMake [#79]
  5 +* MakeSingleHeader now works if outside of git [#78]
  6 +* Double printing of error message fixed [#77]
  7 +* Descriptions can now be written with `config_to_str` [#66]
  8 +* Multiline INI comments now supported
  9 +* Added `ExistingPath` validator [#73]
  10 +* Renamed `requires` to `needs` to avoid C++20 keyword [#75], [#82]
  11 +
  12 +[#70]: https://github.com/CLIUtils/CLI11/issues/70
  13 +[#75]: https://github.com/CLIUtils/CLI11/issues/75
  14 +
  15 +[#82]: https://github.com/CLIUtils/CLI11/pull/82
  16 +[#79]: https://github.com/CLIUtils/CLI11/pull/79
  17 +[#78]: https://github.com/CLIUtils/CLI11/pull/78
  18 +[#77]: https://github.com/CLIUtils/CLI11/pull/77
  19 +[#73]: https://github.com/CLIUtils/CLI11/pull/73
  20 +[#66]: https://github.com/CLIUtils/CLI11/pull/66
3 21
4 ## Version 1.3: Refactor 22 ## Version 1.3: Refactor
5 23
CMakeLists.txt
@@ -53,9 +53,7 @@ file(GLOB CLI_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*") @@ -53,9 +53,7 @@ file(GLOB CLI_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*")
53 # To see in IDE, must be listed for target 53 # To see in IDE, must be listed for target
54 add_library(CLI11 INTERFACE) 54 add_library(CLI11 INTERFACE)
55 target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") 55 target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
56 -if (CUR_PROJ)  
57 - install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include)  
58 -endif() 56 +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include)
59 57
60 # Single file test 58 # Single file test
61 find_package(PythonInterp) 59 find_package(PythonInterp)
@@ -64,6 +62,7 @@ if(CUR_PROJ AND PYTHONINTERP_FOUND) @@ -64,6 +62,7 @@ if(CUR_PROJ AND PYTHONINTERP_FOUND)
64 else() 62 else()
65 set(CLI_SINGLE_FILE_DEFAULT OFF) 63 set(CLI_SINGLE_FILE_DEFAULT OFF)
66 endif() 64 endif()
  65 +
67 option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CLI_SINGLE_FILE_DEFAULT}) 66 option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CLI_SINGLE_FILE_DEFAULT})
68 if(CLI_SINGLE_FILE) 67 if(CLI_SINGLE_FILE)
69 find_package(PythonInterp REQUIRED) 68 find_package(PythonInterp REQUIRED)
@@ -76,9 +75,7 @@ if(CLI_SINGLE_FILE) @@ -76,9 +75,7 @@ if(CLI_SINGLE_FILE)
76 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp") 75 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp")
77 set_target_properties(generate_cli_single_file 76 set_target_properties(generate_cli_single_file
78 PROPERTIES FOLDER "Scripts") 77 PROPERTIES FOLDER "Scripts")
79 - if (CUR_PROJ)  
80 - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp DESTINATION include)  
81 - endif() 78 + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp DESTINATION include)
82 add_library(CLI11_SINGLE INTERFACE) 79 add_library(CLI11_SINGLE INTERFACE)
83 target_link_libraries(CLI11_SINGLE INTERFACE CLI11) 80 target_link_libraries(CLI11_SINGLE INTERFACE CLI11)
84 add_dependencies(CLI11_SINGLE generate_cli_single_file) 81 add_dependencies(CLI11_SINGLE generate_cli_single_file)
@@ -98,3 +95,4 @@ option(CLI_EXAMPLES "Build the examples" ${CUR_PROJ}) @@ -98,3 +95,4 @@ option(CLI_EXAMPLES "Build the examples" ${CUR_PROJ})
98 if(CLI_EXAMPLES) 95 if(CLI_EXAMPLES)
99 add_subdirectory(examples) 96 add_subdirectory(examples)
100 endif() 97 endif()
  98 +
README.md
@@ -171,7 +171,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t @@ -171,7 +171,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
171 171
172 * `->required()`: The program will quit if this option is not present. This is `mandatory` in Plumbum, but required options seems to be a more standard term. For compatibility, `->mandatory()` also works. 172 * `->required()`: The program will quit if this option is not present. This is `mandatory` in Plumbum, but required options seems to be a more standard term. For compatibility, `->mandatory()` also works.
173 * `->expected(N)`: Take `N` values instead of as many as possible, only for vector args. If negative, require at least `-N`. 173 * `->expected(N)`: Take `N` values instead of as many as possible, only for vector args. If negative, require at least `-N`.
174 -* `->requires(opt)`: This option requires another option to also be present, opt is an `Option` pointer. 174 +* `->needs(opt)`: This option requires another option to also be present, opt is an `Option` pointer.
175 * `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer. 175 * `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer.
176 * `->envname(name)`: Gets the value from the environment if present and not passed on the command line. 176 * `->envname(name)`: Gets the value from the environment if present and not passed on the command line.
177 * `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`. `""` will not show up in the help print (hidden). 177 * `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`. `""` will not show up in the help print (hidden).
@@ -272,7 +272,7 @@ sub.subcommand = true @@ -272,7 +272,7 @@ sub.subcommand = true
272 ``` 272 ```
273 273
274 Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`; or `false`, `off`, `0`, `no` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not mean that subcommand was passed, it just sets the "defaults". To print a configuration file from the passed 274 Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`; or `false`, `off`, `0`, `no` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not mean that subcommand was passed, it just sets the "defaults". To print a configuration file from the passed
275 -arguments, use `.config_to_str(default_also=false)`, where `default_also` will also show any defaulted arguments. 275 +arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions.
276 276
277 ## Inheriting defaults 277 ## Inheriting defaults
278 278
include/CLI/Option.hpp
@@ -278,7 +278,7 @@ class Option : public OptionBase<Option> { @@ -278,7 +278,7 @@ class Option : public OptionBase<Option> {
278 } 278 }
279 279
280 /// Sets required options 280 /// Sets required options
281 - Option *requires(Option *opt) { 281 + Option *needs(Option *opt) {
282 auto tup = requires_.insert(opt); 282 auto tup = requires_.insert(opt);
283 if(!tup.second) 283 if(!tup.second)
284 throw OptionAlreadyAdded::Requires(get_name(), opt->get_name()); 284 throw OptionAlreadyAdded::Requires(get_name(), opt->get_name());
@@ -286,18 +286,32 @@ class Option : public OptionBase<Option> { @@ -286,18 +286,32 @@ class Option : public OptionBase<Option> {
286 } 286 }
287 287
288 /// Can find a string if needed 288 /// Can find a string if needed
289 - template <typename T = App> Option *requires(std::string opt_name) { 289 + template <typename T = App> Option *needs(std::string opt_name) {
290 for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_) 290 for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
291 if(opt.get() != this && opt->check_name(opt_name)) 291 if(opt.get() != this && opt->check_name(opt_name))
292 - return requires(opt.get()); 292 + return needs(opt.get());
293 throw IncorrectConstruction::MissingOption(opt_name); 293 throw IncorrectConstruction::MissingOption(opt_name);
294 } 294 }
295 295
296 /// Any number supported, any mix of string and Opt 296 /// Any number supported, any mix of string and Opt
  297 + template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
  298 + needs(opt);
  299 + return needs(opt1, args...);
  300 + }
  301 +
  302 +#if __cplusplus <= 201703L
  303 + /// Sets required options \deprecated
  304 + Option *requires(Option *opt) { return needs(opt); }
  305 +
  306 + /// Can find a string if needed \deprecated
  307 + template <typename T = App> Option *requires(std::string opt_name) { return needs<T>(opt_name); }
  308 +
  309 + /// Any number supported, any mix of string and Opt \deprecated
297 template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) { 310 template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
298 - requires(opt);  
299 - return requires(opt1, args...); 311 + needs(opt);
  312 + return needs(opt1, args...);
300 } 313 }
  314 +#endif
301 315
302 /// Sets excluded options 316 /// Sets excluded options
303 Option *excludes(Option *opt) { 317 Option *excludes(Option *opt) {
@@ -314,6 +328,7 @@ class Option : public OptionBase&lt;Option&gt; { @@ -314,6 +328,7 @@ class Option : public OptionBase&lt;Option&gt; {
314 return excludes(opt.get()); 328 return excludes(opt.get());
315 throw IncorrectConstruction::MissingOption(opt_name); 329 throw IncorrectConstruction::MissingOption(opt_name);
316 } 330 }
  331 +
317 /// Any number supported, any mix of string and Opt 332 /// Any number supported, any mix of string and Opt
318 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) { 333 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
319 excludes(opt); 334 excludes(opt);
tests/AppTest.cpp
@@ -982,9 +982,9 @@ TEST_F(TApp, OriginalOrder) { @@ -982,9 +982,9 @@ TEST_F(TApp, OriginalOrder) {
982 EXPECT_EQ(app.parse_order(), std::vector<CLI::Option *>({op1, op2, op1, op1})); 982 EXPECT_EQ(app.parse_order(), std::vector<CLI::Option *>({op1, op2, op1, op1}));
983 } 983 }
984 984
985 -TEST_F(TApp, RequiresFlags) { 985 +TEST_F(TApp, NeedsFlags) {
986 CLI::Option *opt = app.add_flag("-s,--string"); 986 CLI::Option *opt = app.add_flag("-s,--string");
987 - app.add_flag("--both")->requires(opt); 987 + app.add_flag("--both")->needs(opt);
988 988
989 run(); 989 run();
990 990
@@ -1049,11 +1049,11 @@ TEST_F(TApp, ExcludesMixedFlags) { @@ -1049,11 +1049,11 @@ TEST_F(TApp, ExcludesMixedFlags) {
1049 EXPECT_THROW(run(), CLI::ExcludesError); 1049 EXPECT_THROW(run(), CLI::ExcludesError);
1050 } 1050 }
1051 1051
1052 -TEST_F(TApp, RequiresMultiFlags) { 1052 +TEST_F(TApp, NeedsMultiFlags) {
1053 CLI::Option *opt1 = app.add_flag("--opt1"); 1053 CLI::Option *opt1 = app.add_flag("--opt1");
1054 CLI::Option *opt2 = app.add_flag("--opt2"); 1054 CLI::Option *opt2 = app.add_flag("--opt2");
1055 CLI::Option *opt3 = app.add_flag("--opt3"); 1055 CLI::Option *opt3 = app.add_flag("--opt3");
1056 - app.add_flag("--optall")->requires(opt1, opt2, opt3); 1056 + app.add_flag("--optall")->needs(opt1, opt2, opt3);
1057 1057
1058 run(); 1058 run();
1059 1059
@@ -1082,6 +1082,41 @@ TEST_F(TApp, RequiresMultiFlags) { @@ -1082,6 +1082,41 @@ TEST_F(TApp, RequiresMultiFlags) {
1082 run(); 1082 run();
1083 } 1083 }
1084 1084
  1085 +TEST_F(TApp, NeedsMixedFlags) {
  1086 + CLI::Option *opt1 = app.add_flag("--opt1");
  1087 + app.add_flag("--opt2");
  1088 + app.add_flag("--opt3");
  1089 + app.add_flag("--optall")->needs(opt1, "--opt2", "--opt3");
  1090 +
  1091 + run();
  1092 +
  1093 + app.reset();
  1094 + args = {"--opt1"};
  1095 + run();
  1096 +
  1097 + app.reset();
  1098 + args = {"--opt2"};
  1099 + run();
  1100 +
  1101 + app.reset();
  1102 + args = {"--optall"};
  1103 + EXPECT_THROW(run(), CLI::RequiresError);
  1104 +
  1105 + app.reset();
  1106 + args = {"--optall", "--opt1"};
  1107 + EXPECT_THROW(run(), CLI::RequiresError);
  1108 +
  1109 + app.reset();
  1110 + args = {"--optall", "--opt2", "--opt1"};
  1111 + EXPECT_THROW(run(), CLI::RequiresError);
  1112 +
  1113 + app.reset();
  1114 + args = {"--optall", "--opt1", "--opt2", "--opt3"};
  1115 + run();
  1116 +}
  1117 +
  1118 +#if __cplusplus <= 201703L
  1119 +
1085 TEST_F(TApp, RequiresMixedFlags) { 1120 TEST_F(TApp, RequiresMixedFlags) {
1086 CLI::Option *opt1 = app.add_flag("--opt1"); 1121 CLI::Option *opt1 = app.add_flag("--opt1");
1087 app.add_flag("--opt2"); 1122 app.add_flag("--opt2");
@@ -1115,10 +1150,12 @@ TEST_F(TApp, RequiresMixedFlags) { @@ -1115,10 +1150,12 @@ TEST_F(TApp, RequiresMixedFlags) {
1115 run(); 1150 run();
1116 } 1151 }
1117 1152
1118 -TEST_F(TApp, RequiresChainedFlags) { 1153 +#endif
  1154 +
  1155 +TEST_F(TApp, NeedsChainedFlags) {
1119 CLI::Option *opt1 = app.add_flag("--opt1"); 1156 CLI::Option *opt1 = app.add_flag("--opt1");
1120 - CLI::Option *opt2 = app.add_flag("--opt2")->requires(opt1);  
1121 - app.add_flag("--opt3")->requires(opt2); 1157 + CLI::Option *opt2 = app.add_flag("--opt2")->needs(opt1);
  1158 + app.add_flag("--opt3")->needs(opt2);
1122 1159
1123 run(); 1160 run();
1124 1161
tests/CreationTest.cpp
@@ -163,9 +163,9 @@ TEST_F(TApp, IncorrectConstructionTakeLastExpected) { @@ -163,9 +163,9 @@ TEST_F(TApp, IncorrectConstructionTakeLastExpected) {
163 EXPECT_THROW(cat->expected(2), CLI::IncorrectConstruction); 163 EXPECT_THROW(cat->expected(2), CLI::IncorrectConstruction);
164 } 164 }
165 165
166 -TEST_F(TApp, IncorrectConstructionRequiresCannotFind) { 166 +TEST_F(TApp, IncorrectConstructionNeedsCannotFind) {
167 auto cat = app.add_flag("--cat"); 167 auto cat = app.add_flag("--cat");
168 - EXPECT_THROW(cat->requires("--nothing"), CLI::IncorrectConstruction); 168 + EXPECT_THROW(cat->needs("--nothing"), CLI::IncorrectConstruction);
169 } 169 }
170 170
171 TEST_F(TApp, IncorrectConstructionExcludesCannotFind) { 171 TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
@@ -173,18 +173,18 @@ TEST_F(TApp, IncorrectConstructionExcludesCannotFind) { @@ -173,18 +173,18 @@ TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
173 EXPECT_THROW(cat->excludes("--nothing"), CLI::IncorrectConstruction); 173 EXPECT_THROW(cat->excludes("--nothing"), CLI::IncorrectConstruction);
174 } 174 }
175 175
176 -TEST_F(TApp, IncorrectConstructionDuplicateRequires) { 176 +TEST_F(TApp, IncorrectConstructionDuplicateNeeds) {
177 auto cat = app.add_flag("--cat"); 177 auto cat = app.add_flag("--cat");
178 auto other = app.add_flag("--other"); 178 auto other = app.add_flag("--other");
179 - ASSERT_NO_THROW(cat->requires(other));  
180 - EXPECT_THROW(cat->requires(other), CLI::OptionAlreadyAdded); 179 + ASSERT_NO_THROW(cat->needs(other));
  180 + EXPECT_THROW(cat->needs(other), CLI::OptionAlreadyAdded);
181 } 181 }
182 182
183 -TEST_F(TApp, IncorrectConstructionDuplicateRequiresTxt) { 183 +TEST_F(TApp, IncorrectConstructionDuplicateNeedsTxt) {
184 auto cat = app.add_flag("--cat"); 184 auto cat = app.add_flag("--cat");
185 app.add_flag("--other"); 185 app.add_flag("--other");
186 - ASSERT_NO_THROW(cat->requires("--other"));  
187 - EXPECT_THROW(cat->requires("--other"), CLI::OptionAlreadyAdded); 186 + ASSERT_NO_THROW(cat->needs("--other"));
  187 + EXPECT_THROW(cat->needs("--other"), CLI::OptionAlreadyAdded);
188 } 188 }
189 189
190 TEST_F(TApp, IncorrectConstructionDuplicateExcludes) { 190 TEST_F(TApp, IncorrectConstructionDuplicateExcludes) {
tests/HelpTest.cpp
@@ -153,24 +153,24 @@ TEST(THelp, EnvName) { @@ -153,24 +153,24 @@ TEST(THelp, EnvName) {
153 EXPECT_THAT(help, HasSubstr("SOME_ENV")); 153 EXPECT_THAT(help, HasSubstr("SOME_ENV"));
154 } 154 }
155 155
156 -TEST(THelp, Requires) { 156 +TEST(THelp, Needs) {
157 CLI::App app{"My prog"}; 157 CLI::App app{"My prog"};
158 158
159 CLI::Option *op1 = app.add_flag("--op1"); 159 CLI::Option *op1 = app.add_flag("--op1");
160 - app.add_flag("--op2")->requires(op1); 160 + app.add_flag("--op2")->needs(op1);
161 161
162 std::string help = app.help(); 162 std::string help = app.help();
163 163
164 EXPECT_THAT(help, HasSubstr("Requires: --op1")); 164 EXPECT_THAT(help, HasSubstr("Requires: --op1"));
165 } 165 }
166 166
167 -TEST(THelp, RequiresPositional) { 167 +TEST(THelp, NeedsPositional) {
168 CLI::App app{"My prog"}; 168 CLI::App app{"My prog"};
169 169
170 int x, y; 170 int x, y;
171 171
172 CLI::Option *op1 = app.add_option("op1", x, "one"); 172 CLI::Option *op1 = app.add_option("op1", x, "one");
173 - app.add_option("op2", y, "two")->requires(op1); 173 + app.add_option("op2", y, "two")->needs(op1);
174 174
175 std::string help = app.help(); 175 std::string help = app.help();
176 176
tests/IniTest.cpp
@@ -248,7 +248,7 @@ TEST_F(TApp, IniGetNoRemaining) { @@ -248,7 +248,7 @@ TEST_F(TApp, IniGetNoRemaining) {
248 int two = 0; 248 int two = 0;
249 app.add_option("--two", two); 249 app.add_option("--two", two);
250 EXPECT_NO_THROW(run()); 250 EXPECT_NO_THROW(run());
251 - EXPECT_EQ(app.remaining().size(), 0); 251 + EXPECT_EQ(app.remaining().size(), (size_t)0);
252 } 252 }
253 253
254 TEST_F(TApp, IniNotRequiredNotDefault) { 254 TEST_F(TApp, IniNotRequiredNotDefault) {