Skip to content

Commit a78f5bc

Browse files
authored
Dropping links if option removed (#179)
1 parent b683f4e commit a78f5bc

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

include/CLI/App.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,12 @@ class App {
781781

782782
/// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
783783
bool remove_option(Option *opt) {
784+
// Make sure no links exist
785+
for(Option_p &op : options_) {
786+
op->remove_needs(opt);
787+
op->remove_excludes(opt);
788+
}
789+
784790
auto iterator =
785791
std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
786792
if(iterator != std::end(options_)) {
@@ -1356,7 +1362,7 @@ class App {
13561362
throw RequiredError(opt->get_name());
13571363
}
13581364
// Requires
1359-
for(const Option *opt_req : opt->requires_)
1365+
for(const Option *opt_req : opt->needs_)
13601366
if(opt->count() > 0 && opt_req->count() == 0)
13611367
throw RequiresError(opt->get_name(), opt_req->get_name());
13621368
// Excludes

include/CLI/Option.hpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class Option : public OptionBase<Option> {
200200
std::vector<std::function<std::string(std::string &)>> validators_;
201201

202202
/// A list of options that are required with this option
203-
std::set<Option *> requires_;
203+
std::set<Option *> needs_;
204204

205205
/// A list of options that are excluded with this option
206206
std::set<Option *> excludes_;
@@ -322,7 +322,7 @@ class Option : public OptionBase<Option> {
322322

323323
/// Sets required options
324324
Option *needs(Option *opt) {
325-
auto tup = requires_.insert(opt);
325+
auto tup = needs_.insert(opt);
326326
if(!tup.second)
327327
throw OptionAlreadyAdded::Requires(get_name(), opt->get_name());
328328
return this;
@@ -342,6 +342,18 @@ class Option : public OptionBase<Option> {
342342
return needs(opt1, args...);
343343
}
344344

345+
/// Remove needs link from an option. Returns true if the option really was in the needs list.
346+
bool remove_needs(Option *opt) {
347+
auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
348+
349+
if(iterator != std::end(needs_)) {
350+
needs_.erase(iterator);
351+
return true;
352+
} else {
353+
return false;
354+
}
355+
}
356+
345357
/// Sets excluded options
346358
Option *excludes(Option *opt) {
347359
excludes_.insert(opt);
@@ -369,6 +381,18 @@ class Option : public OptionBase<Option> {
369381
return excludes(opt1, args...);
370382
}
371383

384+
/// Remove needs link from an option. Returns true if the option really was in the needs list.
385+
bool remove_excludes(Option *opt) {
386+
auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
387+
388+
if(iterator != std::end(excludes_)) {
389+
excludes_.erase(iterator);
390+
return true;
391+
} else {
392+
return false;
393+
}
394+
}
395+
372396
/// Sets environment variable to read if no option given
373397
Option *envname(std::string name) {
374398
envname_ = name;
@@ -418,7 +442,7 @@ class Option : public OptionBase<Option> {
418442
std::string get_envname() const { return envname_; }
419443

420444
/// The set of options needed
421-
std::set<Option *> get_needs() const { return requires_; }
445+
std::set<Option *> get_needs() const { return needs_; }
422446

423447
/// The set of options excluded
424448
std::set<Option *> get_excludes() const { return excludes_; }

tests/AppTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,34 @@ TEST_F(TApp, RemoveOption) {
816816
EXPECT_THROW(run(), CLI::ExtrasError);
817817
}
818818

819+
TEST_F(TApp, RemoveNeedsLinks) {
820+
auto one = app.add_flag("--one");
821+
auto two = app.add_flag("--two");
822+
823+
two->needs(one);
824+
one->needs(two);
825+
826+
EXPECT_TRUE(app.remove_option(one));
827+
828+
args = {"--two"};
829+
830+
run();
831+
}
832+
833+
TEST_F(TApp, RemoveExcludesLinks) {
834+
auto one = app.add_flag("--one");
835+
auto two = app.add_flag("--two");
836+
837+
two->excludes(one);
838+
one->excludes(two);
839+
840+
EXPECT_TRUE(app.remove_option(one));
841+
842+
args = {"--two"};
843+
844+
run(); // Mostly hoping it does not crash
845+
}
846+
819847
TEST_F(TApp, FileNotExists) {
820848
std::string myfile{"TestNonFileNotUsed.txt"};
821849
ASSERT_NO_THROW(CLI::NonexistentPath(myfile));

0 commit comments

Comments
 (0)