1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-29 12:13:52 +00:00

Rename requires to needs (#82)

* Adding fix for #75, rename requires to needs

* Removing check for install commands (should still be run in subproject)
This commit is contained in:
Henry Schreiner 2018-03-08 11:48:40 +01:00 committed by GitHub
parent d465414455
commit 5186158442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 102 additions and 34 deletions

View File

@ -1,5 +1,23 @@
## Version 1.4 (in progress)
* Added `get_parent()` to access the parent from a subcommand
* `app.allow_ini_extras()` added to allow extras in INI files [#70]
* Adding install support for CMake [#79]
* MakeSingleHeader now works if outside of git [#78]
* Double printing of error message fixed [#77]
* Descriptions can now be written with `config_to_str` [#66]
* Multiline INI comments now supported
* Added `ExistingPath` validator [#73]
* Renamed `requires` to `needs` to avoid C++20 keyword [#75], [#82]
[#70]: https://github.com/CLIUtils/CLI11/issues/70
[#75]: https://github.com/CLIUtils/CLI11/issues/75
[#82]: https://github.com/CLIUtils/CLI11/pull/82
[#79]: https://github.com/CLIUtils/CLI11/pull/79
[#78]: https://github.com/CLIUtils/CLI11/pull/78
[#77]: https://github.com/CLIUtils/CLI11/pull/77
[#73]: https://github.com/CLIUtils/CLI11/pull/73
[#66]: https://github.com/CLIUtils/CLI11/pull/66
## Version 1.3: Refactor

View File

@ -53,9 +53,7 @@ file(GLOB CLI_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*")
# To see in IDE, must be listed for target
add_library(CLI11 INTERFACE)
target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
if (CUR_PROJ)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include)
endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include)
# Single file test
find_package(PythonInterp)
@ -64,6 +62,7 @@ if(CUR_PROJ AND PYTHONINTERP_FOUND)
else()
set(CLI_SINGLE_FILE_DEFAULT OFF)
endif()
option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CLI_SINGLE_FILE_DEFAULT})
if(CLI_SINGLE_FILE)
find_package(PythonInterp REQUIRED)
@ -76,9 +75,7 @@ if(CLI_SINGLE_FILE)
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp")
set_target_properties(generate_cli_single_file
PROPERTIES FOLDER "Scripts")
if (CUR_PROJ)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp DESTINATION include)
endif()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp DESTINATION include)
add_library(CLI11_SINGLE INTERFACE)
target_link_libraries(CLI11_SINGLE INTERFACE CLI11)
add_dependencies(CLI11_SINGLE generate_cli_single_file)
@ -98,3 +95,4 @@ option(CLI_EXAMPLES "Build the examples" ${CUR_PROJ})
if(CLI_EXAMPLES)
add_subdirectory(examples)
endif()

View File

@ -171,7 +171,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
* `->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.
* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args. If negative, require at least `-N`.
* `->requires(opt)`: This option requires another option to also be present, opt is an `Option` pointer.
* `->needs(opt)`: This option requires another option to also be present, opt is an `Option` pointer.
* `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer.
* `->envname(name)`: Gets the value from the environment if present and not passed on the command line.
* `->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
```
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
arguments, use `.config_to_str(default_also=false)`, where `default_also` will also show any defaulted arguments.
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.
## Inheriting defaults

View File

@ -278,7 +278,7 @@ class Option : public OptionBase<Option> {
}
/// Sets required options
Option *requires(Option *opt) {
Option *needs(Option *opt) {
auto tup = requires_.insert(opt);
if(!tup.second)
throw OptionAlreadyAdded::Requires(get_name(), opt->get_name());
@ -286,19 +286,33 @@ class Option : public OptionBase<Option> {
}
/// Can find a string if needed
template <typename T = App> Option *requires(std::string opt_name) {
template <typename T = App> Option *needs(std::string opt_name) {
for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
if(opt.get() != this && opt->check_name(opt_name))
return requires(opt.get());
return needs(opt.get());
throw IncorrectConstruction::MissingOption(opt_name);
}
/// Any number supported, any mix of string and Opt
template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
requires(opt);
return requires(opt1, args...);
template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
needs(opt);
return needs(opt1, args...);
}
#if __cplusplus <= 201703L
/// Sets required options \deprecated
Option *requires(Option *opt) { return needs(opt); }
/// Can find a string if needed \deprecated
template <typename T = App> Option *requires(std::string opt_name) { return needs<T>(opt_name); }
/// Any number supported, any mix of string and Opt \deprecated
template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
needs(opt);
return needs(opt1, args...);
}
#endif
/// Sets excluded options
Option *excludes(Option *opt) {
auto tup = excludes_.insert(opt);
@ -314,6 +328,7 @@ class Option : public OptionBase<Option> {
return excludes(opt.get());
throw IncorrectConstruction::MissingOption(opt_name);
}
/// Any number supported, any mix of string and Opt
template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
excludes(opt);

View File

@ -982,9 +982,9 @@ TEST_F(TApp, OriginalOrder) {
EXPECT_EQ(app.parse_order(), std::vector<CLI::Option *>({op1, op2, op1, op1}));
}
TEST_F(TApp, RequiresFlags) {
TEST_F(TApp, NeedsFlags) {
CLI::Option *opt = app.add_flag("-s,--string");
app.add_flag("--both")->requires(opt);
app.add_flag("--both")->needs(opt);
run();
@ -1049,11 +1049,11 @@ TEST_F(TApp, ExcludesMixedFlags) {
EXPECT_THROW(run(), CLI::ExcludesError);
}
TEST_F(TApp, RequiresMultiFlags) {
TEST_F(TApp, NeedsMultiFlags) {
CLI::Option *opt1 = app.add_flag("--opt1");
CLI::Option *opt2 = app.add_flag("--opt2");
CLI::Option *opt3 = app.add_flag("--opt3");
app.add_flag("--optall")->requires(opt1, opt2, opt3);
app.add_flag("--optall")->needs(opt1, opt2, opt3);
run();
@ -1082,6 +1082,41 @@ TEST_F(TApp, RequiresMultiFlags) {
run();
}
TEST_F(TApp, NeedsMixedFlags) {
CLI::Option *opt1 = app.add_flag("--opt1");
app.add_flag("--opt2");
app.add_flag("--opt3");
app.add_flag("--optall")->needs(opt1, "--opt2", "--opt3");
run();
app.reset();
args = {"--opt1"};
run();
app.reset();
args = {"--opt2"};
run();
app.reset();
args = {"--optall"};
EXPECT_THROW(run(), CLI::RequiresError);
app.reset();
args = {"--optall", "--opt1"};
EXPECT_THROW(run(), CLI::RequiresError);
app.reset();
args = {"--optall", "--opt2", "--opt1"};
EXPECT_THROW(run(), CLI::RequiresError);
app.reset();
args = {"--optall", "--opt1", "--opt2", "--opt3"};
run();
}
#if __cplusplus <= 201703L
TEST_F(TApp, RequiresMixedFlags) {
CLI::Option *opt1 = app.add_flag("--opt1");
app.add_flag("--opt2");
@ -1115,10 +1150,12 @@ TEST_F(TApp, RequiresMixedFlags) {
run();
}
TEST_F(TApp, RequiresChainedFlags) {
#endif
TEST_F(TApp, NeedsChainedFlags) {
CLI::Option *opt1 = app.add_flag("--opt1");
CLI::Option *opt2 = app.add_flag("--opt2")->requires(opt1);
app.add_flag("--opt3")->requires(opt2);
CLI::Option *opt2 = app.add_flag("--opt2")->needs(opt1);
app.add_flag("--opt3")->needs(opt2);
run();

View File

@ -163,9 +163,9 @@ TEST_F(TApp, IncorrectConstructionTakeLastExpected) {
EXPECT_THROW(cat->expected(2), CLI::IncorrectConstruction);
}
TEST_F(TApp, IncorrectConstructionRequiresCannotFind) {
TEST_F(TApp, IncorrectConstructionNeedsCannotFind) {
auto cat = app.add_flag("--cat");
EXPECT_THROW(cat->requires("--nothing"), CLI::IncorrectConstruction);
EXPECT_THROW(cat->needs("--nothing"), CLI::IncorrectConstruction);
}
TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
@ -173,18 +173,18 @@ TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
EXPECT_THROW(cat->excludes("--nothing"), CLI::IncorrectConstruction);
}
TEST_F(TApp, IncorrectConstructionDuplicateRequires) {
TEST_F(TApp, IncorrectConstructionDuplicateNeeds) {
auto cat = app.add_flag("--cat");
auto other = app.add_flag("--other");
ASSERT_NO_THROW(cat->requires(other));
EXPECT_THROW(cat->requires(other), CLI::OptionAlreadyAdded);
ASSERT_NO_THROW(cat->needs(other));
EXPECT_THROW(cat->needs(other), CLI::OptionAlreadyAdded);
}
TEST_F(TApp, IncorrectConstructionDuplicateRequiresTxt) {
TEST_F(TApp, IncorrectConstructionDuplicateNeedsTxt) {
auto cat = app.add_flag("--cat");
app.add_flag("--other");
ASSERT_NO_THROW(cat->requires("--other"));
EXPECT_THROW(cat->requires("--other"), CLI::OptionAlreadyAdded);
ASSERT_NO_THROW(cat->needs("--other"));
EXPECT_THROW(cat->needs("--other"), CLI::OptionAlreadyAdded);
}
TEST_F(TApp, IncorrectConstructionDuplicateExcludes) {

View File

@ -153,24 +153,24 @@ TEST(THelp, EnvName) {
EXPECT_THAT(help, HasSubstr("SOME_ENV"));
}
TEST(THelp, Requires) {
TEST(THelp, Needs) {
CLI::App app{"My prog"};
CLI::Option *op1 = app.add_flag("--op1");
app.add_flag("--op2")->requires(op1);
app.add_flag("--op2")->needs(op1);
std::string help = app.help();
EXPECT_THAT(help, HasSubstr("Requires: --op1"));
}
TEST(THelp, RequiresPositional) {
TEST(THelp, NeedsPositional) {
CLI::App app{"My prog"};
int x, y;
CLI::Option *op1 = app.add_option("op1", x, "one");
app.add_option("op2", y, "two")->requires(op1);
app.add_option("op2", y, "two")->needs(op1);
std::string help = app.help();

View File

@ -248,7 +248,7 @@ TEST_F(TApp, IniGetNoRemaining) {
int two = 0;
app.add_option("--two", two);
EXPECT_NO_THROW(run());
EXPECT_EQ(app.remaining().size(), 0);
EXPECT_EQ(app.remaining().size(), (size_t)0);
}
TEST_F(TApp, IniNotRequiredNotDefault) {