Skip to content

Commit

Permalink
Adding fix for #75, rename requires to needs
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Mar 2, 2018
1 parent d465414 commit 3092816
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 27 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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

Expand Down
25 changes: 20 additions & 5 deletions include/CLI/Option.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,26 +278,40 @@ 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());
return this;
}

/// 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 *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) {
requires(opt);
return requires(opt1, args...);
needs(opt);
return needs(opt1, args...);
}
#endif

/// Sets excluded options
Option *excludes(Option *opt) {
Expand All @@ -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);
Expand Down
51 changes: 44 additions & 7 deletions tests/AppTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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();

Expand Down
16 changes: 8 additions & 8 deletions tests/CreationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,28 +163,28 @@ 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) {
auto cat = app.add_flag("--cat");
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) {
Expand Down
8 changes: 4 additions & 4 deletions tests/HelpTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion tests/IniTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 3092816

Please sign in to comment.