Skip to content

Commit

Permalink
refactor!: drop defaulted from add_option
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Jun 15, 2021
1 parent ac74dac commit 3bd538d
Show file tree
Hide file tree
Showing 12 changed files with 38 additions and 246 deletions.
4 changes: 2 additions & 2 deletions book/chapters/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ int int_option{0};
app.add_option("-i", int_option, "Optional description");
```
This will bind the option `-i` to the integer `int_option`. On the command line, a single value that can be converted to an integer will be expected. Non-integer results will fail. If that option is not given, CLI11 will not touch the initial value. This allows you to set up defaults by simply setting your value beforehand. If you want CLI11 to display your default value, you can add the optional final argument `true` when you add the option.
This will bind the option `-i` to the integer `int_option`. On the command line, a single value that can be converted to an integer will be expected. Non-integer results will fail. If that option is not given, CLI11 will not touch the initial value. This allows you to set up defaults by simply setting your value beforehand. If you want CLI11 to display your default value, you can add `->capture_default_str()` after the option.
```cpp
int int_option{0};
app.add_option("-i", int_option, "Optional description", true);
app.add_option("-i", int_option, "Optional description")->capture_default_str();
```

You can use any C++ int-like type, not just `int`. CLI11 understands the following categories of types:
Expand Down
4 changes: 3 additions & 1 deletion examples/nested.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ int main(int argc, char **argv) {

std::string mvcamera_config_file = "mvcamera_config.json";
CLI::App *mvcameraApp = cameraApp->add_subcommand("mvcamera", "MatrixVision Camera Configuration");
mvcameraApp->add_option("-c,--config", mvcamera_config_file, "Config filename", true)->check(CLI::ExistingFile);
mvcameraApp->add_option("-c,--config", mvcamera_config_file, "Config filename")
->capture_default_str()
->check(CLI::ExistingFile);

std::string mock_camera_path;
CLI::App *mockcameraApp = cameraApp->add_subcommand("mock", "Mock Camera Configuration");
Expand Down
2 changes: 1 addition & 1 deletion examples/ranges.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int main(int argc, char **argv) {
int min{0}, max{0}, step{1};
ogroup->add_option("--min,-m", min, "The minimum")->required();
ogroup->add_option("--max,-M", max, "The maximum")->required();
ogroup->add_option("--step,-s", step, "The step", true);
ogroup->add_option("--step,-s", step, "The step")->capture_default_str();

app.require_option(1);

Expand Down
5 changes: 2 additions & 3 deletions include/CLI/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,14 +611,13 @@ class App {
enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
Option *add_option(std::string option_name,
AssignTo &variable, ///< The variable to set
std::string option_description = "",
bool defaulted = false) {
std::string option_description = "") {

auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
};

Option *opt = add_option(option_name, fun, option_description, defaulted, [&variable]() {
Option *opt = add_option(option_name, fun, option_description, false, [&variable]() {
return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
});
opt->type_name(detail::type_name<ConvertTo>());
Expand Down
2 changes: 1 addition & 1 deletion tests/AppTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2219,7 +2219,7 @@ TEST_CASE_METHOD(TApp, "CustomUserSepParse3", "[app]") {
CHECK(std::vector<int>({1, 2}) == vals);
app.remove_option(opt);

app.add_option("--idx", vals, "", false)->delimiter(',');
app.add_option("--idx", vals)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2}) == vals);
}
Expand Down
20 changes: 10 additions & 10 deletions tests/ConfigFileTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputHiddenOptions", "[config]") {
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
app.add_option("--dval", val, "", true)->group("");
app.add_option("--dval", val)->capture_default_str()->group("");

run();

Expand Down Expand Up @@ -1723,7 +1723,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputOptionGroup", "[config]") {
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
auto og = app.add_option_group("group3", "g3 desc");
og->add_option("--dval", val, "", true)->group("");
og->add_option("--dval", val)->capture_default_str()->group("");

run();

Expand Down Expand Up @@ -1809,7 +1809,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputSet", "[config]") {
TEST_CASE_METHOD(TApp, "TomlOutputDefault", "[config]") {

int v{7};
app.add_option("--simple", v, "", true);
app.add_option("--simple", v)->capture_default_str();

run();

Expand Down Expand Up @@ -1934,10 +1934,10 @@ TEST_CASE_METHOD(TApp, "TomlOutputQuoted", "[config]") {
TEST_CASE_METHOD(TApp, "DefaultsTomlOutputQuoted", "[config]") {

std::string val1{"I am a string"};
app.add_option("--val1", val1, "", true);
app.add_option("--val1", val1)->capture_default_str();

std::string val2{R"(I am a "confusing" string)"};
app.add_option("--val2", val2, "", true);
app.add_option("--val2", val2)->capture_default_str();

run();

Expand Down Expand Up @@ -2068,7 +2068,7 @@ TEST_CASE_METHOD(TApp, "IniOutputHiddenOptions", "[config]") {
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
app.add_option("--dval", val, "", true)->group("");
app.add_option("--dval", val)->capture_default_str()->group("");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();

Expand Down Expand Up @@ -2106,7 +2106,7 @@ TEST_CASE_METHOD(TApp, "IniOutputOptionGroup", "[config]") {
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
auto og = app.add_option_group("group3", "g3 desc");
og->add_option("--dval", val, "", true)->group("");
og->add_option("--dval", val)->capture_default_str()->group("");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();

Expand Down Expand Up @@ -2177,7 +2177,7 @@ TEST_CASE_METHOD(TApp, "IniOutputSet", "[config]") {
TEST_CASE_METHOD(TApp, "IniOutputDefault", "[config]") {

int v{7};
app.add_option("--simple", v, "", true);
app.add_option("--simple", v)->capture_default_str();
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();

Expand Down Expand Up @@ -2302,10 +2302,10 @@ TEST_CASE_METHOD(TApp, "IniOutputQuoted", "[config]") {
TEST_CASE_METHOD(TApp, "DefaultsIniOutputQuoted", "[config]") {

std::string val1{"I am a string"};
app.add_option("--val1", val1, "", true);
app.add_option("--val1", val1)->capture_default_str();

std::string val2{R"(I am a "confusing" string)"};
app.add_option("--val2", val2, "", true);
app.add_option("--val2", val2)->capture_default_str();
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();

Expand Down
4 changes: 2 additions & 2 deletions tests/CreationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,13 +739,13 @@ TEST_CASE_METHOD(TApp, "MakeUnstreamableOptions", "[creation]") {
app.add_option("--value", value);

// This used to fail to build, since it tries to stream from Unstreamable
app.add_option("--value2", value, "", false);
app.add_option("--value2", value);

std::vector<Unstreamable> values;
app.add_option("--values", values);

// This used to fail to build, since it tries to stream from Unstreamable
app.add_option("--values2", values, "", false);
app.add_option("--values2", values);

args = {"--value", "45"};
run();
Expand Down
211 changes: 0 additions & 211 deletions tests/DeprecatedTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,214 +12,3 @@ TEST_CASE("Deprecated: Empty", "[deprecated]") {
// No deprecated features at this time.
CHECK(true);
}

// Classic sets

TEST_CASE("THelp: Defaults", "[deprecated]") {
CLI::App app{"My prog"};

int one{1}, two{2};
app.add_option("--one", one, "Help for one", true);
app.add_option("--set", two, "Help for set", true)->check(CLI::IsMember({2, 3, 4}));

std::string help = app.help();

CHECK_THAT(help, Contains("--one"));
CHECK_THAT(help, Contains("--set"));
CHECK_THAT(help, Contains("1"));
CHECK_THAT(help, Contains("=2"));
CHECK_THAT(help, Contains("2,3,4"));
}

TEST_CASE("THelp: VectorOpts", "[deprecated]") {
CLI::App app{"My prog"};
std::vector<int> x = {1, 2};
app.add_option("-q,--quick", x, "", true);

std::string help = app.help();

CHECK_THAT(help, Contains("INT=[1,2] ..."));
}

TEST_CASE("THelp: SetLower", "[deprecated]") {
CLI::App app{"My prog"};

std::string def{"One"};
app.add_option("--set", def, "Help for set", true)->check(CLI::IsMember({"oNe", "twO", "THREE"}));

std::string help = app.help();

CHECK_THAT(help, Contains("--set"));
CHECK_THAT(help, Contains("=One"));
CHECK_THAT(help, Contains("oNe"));
CHECK_THAT(help, Contains("twO"));
CHECK_THAT(help, Contains("THREE"));
}

TEST_CASE("THelp: ChangingSetDefaulted", "[deprecated]") {
CLI::App app;

std::set<int> vals{1, 2, 3};
int val = 2;
app.add_option("--val", val, "", true)->check(CLI::IsMember(&vals));

std::string help = app.help();

CHECK_THAT(help, Contains("1"));
CHECK_THAT(help, !Contains("4"));

vals.insert(4);
vals.erase(1);

help = app.help();

CHECK_THAT(help, !Contains("1"));
CHECK_THAT(help, Contains("4"));
}

TEST_CASE("THelp: ChangingCaselessSetDefaulted", "[deprecated]") {
CLI::App app;

std::set<std::string> vals{"1", "2", "3"};
std::string val = "2";
app.add_option("--val", val, "", true)->check(CLI::IsMember(&vals, CLI::ignore_case));

std::string help = app.help();

CHECK_THAT(help, Contains("1"));
CHECK_THAT(help, !Contains("4"));

vals.insert("4");
vals.erase("1");

help = app.help();

CHECK_THAT(help, !Contains("1"));
CHECK_THAT(help, Contains("4"));
}

TEST_CASE_METHOD(TApp, "DefaultOpts", "[deprecated]") {

int i = 3;
std::string s = "HI";

app.add_option("-i,i", i, "", false);
app.add_option("-s,s", s, "", true);

args = {"-i2", "9"};

run();

CHECK(app.count("i") == 1u);
CHECK(app.count("-s") == 1u);
CHECK(i == 2);
CHECK(s == "9");
}

TEST_CASE_METHOD(TApp, "VectorDefaultedFixedString", "[deprecated]") {
std::vector<std::string> strvec{"one"};
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};

CLI::Option *opt = app.add_option("-s,--string", strvec, "", true)->expected(3);
CHECK(opt->get_expected() == 3);

args = {"--string", "mystring", "mystring2", "mystring3"};
run();
CHECK(app.count("--string") == 3u);
CHECK(strvec == answer);
}

TEST_CASE_METHOD(TApp, "DefaultedResult", "[deprecated]") {
std::string sval = "NA";
int ival;
auto opts = app.add_option("--string", sval, "", true);
auto optv = app.add_option("--val", ival);
args = {};
run();
CHECK("NA" == sval);
std::string nString;
opts->results(nString);
CHECK("NA" == nString);
int newIval;
// CHECK_THROWS_AS (optv->results(newIval), CLI::ConversionError);
optv->default_str("442");
optv->results(newIval);
CHECK(442 == newIval);
}

TEST_CASE_METHOD(TApp, "OptionWithDefaults", "[deprecated]") {
int someint = 2;
app.add_option("-a", someint, "", true);

args = {"-a1", "-a2"};

CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
}

// #209
TEST_CASE_METHOD(TApp, "CustomUserSepParse", "[deprecated]") {

std::vector<int> vals = {1, 2, 3};
args = {"--idx", "1,2,3"};
auto opt = app.add_option("--idx", vals)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2, 3}) == vals);
std::vector<int> vals2;
// check that the results vector gets the results in the same way
opt->results(vals2);
CHECK(vals == vals2);

app.remove_option(opt);

app.add_option("--idx", vals, "", true)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2, 3}) == vals);
}

// #209
TEST_CASE_METHOD(TApp, "CustomUserSepParse2", "[deprecated]") {

std::vector<int> vals = {1, 2, 3};
args = {"--idx", "1,2,"};
auto opt = app.add_option("--idx", vals)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2}) == vals);

app.remove_option(opt);

app.add_option("--idx", vals, "", true)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2}) == vals);
}
//
// #209
TEST_CASE_METHOD(TApp, "CustomUserSepParse4", "[deprecated]") {

std::vector<int> vals;
args = {"--idx", "1, 2"};
auto opt = app.add_option("--idx", vals, "", true)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2}) == vals);

app.remove_option(opt);

app.add_option("--idx", vals)->delimiter(',');
run();
CHECK(std::vector<int>({1, 2}) == vals);
}

// #218
TEST_CASE_METHOD(TApp, "CustomUserSepParse5", "[deprecated]") {

std::vector<std::string> bar;
args = {"this", "is", "a", "test"};
auto opt = app.add_option("bar", bar, "bar");
run();
CHECK(std::vector<std::string>({"this", "is", "a", "test"}) == bar);

app.remove_option(opt);
args = {"this", "is", "a", "test"};
app.add_option("bar", bar, "bar", true);
run();
CHECK(std::vector<std::string>({"this", "is", "a", "test"}) == bar);
}
Loading

0 comments on commit 3bd538d

Please sign in to comment.