diff --git a/book/chapters/options.md b/book/chapters/options.md index 04bfd0bbd..22b6e94c6 100644 --- a/book/chapters/options.md +++ b/book/chapters/options.md @@ -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: diff --git a/examples/nested.cpp b/examples/nested.cpp index 23f428514..97f34290f 100644 --- a/examples/nested.cpp +++ b/examples/nested.cpp @@ -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"); diff --git a/examples/ranges.cpp b/examples/ranges.cpp index 085a7ad1b..37032e6e3 100644 --- a/examples/ranges.cpp +++ b/examples/ranges.cpp @@ -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); diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index edbe2b738..acae2a136 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -611,14 +611,13 @@ class App { enable_if_t::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(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(variable); }); opt->type_name(detail::type_name()); diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index 6c3e71ced..d5e6c38e9 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -2219,7 +2219,7 @@ TEST_CASE_METHOD(TApp, "CustomUserSepParse3", "[app]") { CHECK(std::vector({1, 2}) == vals); app.remove_option(opt); - app.add_option("--idx", vals, "", false)->delimiter(','); + app.add_option("--idx", vals)->delimiter(','); run(); CHECK(std::vector({1, 2}) == vals); } diff --git a/tests/ConfigFileTest.cpp b/tests/ConfigFileTest.cpp index 12fa88c10..afe170544 100644 --- a/tests/ConfigFileTest.cpp +++ b/tests/ConfigFileTest.cpp @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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()); run(); @@ -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()); run(); @@ -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()); run(); @@ -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()); run(); diff --git a/tests/CreationTest.cpp b/tests/CreationTest.cpp index 2a70f70d4..0e6e45d68 100644 --- a/tests/CreationTest.cpp +++ b/tests/CreationTest.cpp @@ -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 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(); diff --git a/tests/DeprecatedTest.cpp b/tests/DeprecatedTest.cpp index cf9987c6d..a25224ca6 100644 --- a/tests/DeprecatedTest.cpp +++ b/tests/DeprecatedTest.cpp @@ -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 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 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 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 strvec{"one"}; - std::vector 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 vals = {1, 2, 3}; - args = {"--idx", "1,2,3"}; - auto opt = app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2, 3}) == vals); - std::vector 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({1, 2, 3}) == vals); -} - -// #209 -TEST_CASE_METHOD(TApp, "CustomUserSepParse2", "[deprecated]") { - - std::vector vals = {1, 2, 3}; - args = {"--idx", "1,2,"}; - auto opt = app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); - - app.remove_option(opt); - - app.add_option("--idx", vals, "", true)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); -} -// -// #209 -TEST_CASE_METHOD(TApp, "CustomUserSepParse4", "[deprecated]") { - - std::vector vals; - args = {"--idx", "1, 2"}; - auto opt = app.add_option("--idx", vals, "", true)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); - - app.remove_option(opt); - - app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); -} - -// #218 -TEST_CASE_METHOD(TApp, "CustomUserSepParse5", "[deprecated]") { - - std::vector bar; - args = {"this", "is", "a", "test"}; - auto opt = app.add_option("bar", bar, "bar"); - run(); - CHECK(std::vector({"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({"this", "is", "a", "test"}) == bar); -} diff --git a/tests/NewParseTest.cpp b/tests/NewParseTest.cpp index d9d9dbf91..6e88fee23 100644 --- a/tests/NewParseTest.cpp +++ b/tests/NewParseTest.cpp @@ -35,7 +35,7 @@ TEST_CASE_METHOD(TApp, "Complex", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") { cx comp{1, 2}; - app.add_option("-c,--complex", comp, "", true); + app.add_option("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -55,7 +55,7 @@ TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexFloat", "[newparse]") { std::complex comp{1, 2}; - app.add_complex, float>("-c,--complex", comp, "", true); + app.add_complex, float>("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -75,7 +75,7 @@ TEST_CASE_METHOD(TApp, "ComplexFloat", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexFloatOption", "[newparse]") { std::complex comp{1, 2}; - app.add_option("-c,--complex", comp, "", true); + app.add_option("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -95,7 +95,7 @@ TEST_CASE_METHOD(TApp, "ComplexFloatOption", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexWithDelimiter", "[newparse]") { cx comp{1, 2}; - app.add_complex("-c,--complex", comp, "", true)->delimiter('+'); + app.add_complex("-c,--complex", comp)->capture_default_str()->delimiter('+'); args = {"-c", "4+3i"}; @@ -127,7 +127,7 @@ TEST_CASE_METHOD(TApp, "ComplexWithDelimiter", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexWithDelimiterOption", "[newparse]") { cx comp{1, 2}; - app.add_option("-c,--complex", comp, "", true)->delimiter('+'); + app.add_option("-c,--complex", comp)->capture_default_str()->delimiter('+'); args = {"-c", "4+3i"}; diff --git a/tests/OptionTypeTest.cpp b/tests/OptionTypeTest.cpp index a2f893bec..3204d5204 100644 --- a/tests/OptionTypeTest.cpp +++ b/tests/OptionTypeTest.cpp @@ -240,7 +240,7 @@ TEST_CASE_METHOD(TApp, "CharOption", "[optiontype]") { TEST_CASE_METHOD(TApp, "vectorDefaults", "[optiontype]") { std::vector vals{4, 5}; - auto opt = app.add_option("--long", vals, "", true); + auto opt = app.add_option("--long", vals)->capture_default_str(); args = {"--long", "[1,2,3]"}; diff --git a/tests/SetTest.cpp b/tests/SetTest.cpp index d34a67a64..bd817b752 100644 --- a/tests/SetTest.cpp +++ b/tests/SetTest.cpp @@ -373,7 +373,7 @@ TEST_CASE_METHOD(TApp, "NumericalSets", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaults", "[set]") { int someint{2}; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({1, 2, 3, 4})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4})); args = {"-a1", "-a2"}; @@ -382,7 +382,7 @@ TEST_CASE_METHOD(TApp, "SetWithDefaults", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaultsConversion", "[set]") { int someint{2}; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({1, 2, 3, 4})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4})); args = {"-a", "hi"}; @@ -391,7 +391,7 @@ TEST_CASE_METHOD(TApp, "SetWithDefaultsConversion", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaultsIC", "[set]") { std::string someint = "ho"; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({"Hi", "Ho"})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({"Hi", "Ho"})); args = {"-aHi", "-aHo"}; @@ -415,7 +415,7 @@ TEST_CASE_METHOD(TApp, "InSet", "[set]") { TEST_CASE_METHOD(TApp, "InSetWithDefault", "[set]") { std::string choice = "one"; - app.add_option("-q,--quick", choice, "", true)->check(CLI::IsMember({"one", "two", "three"})); + app.add_option("-q,--quick", choice)->capture_default_str()->check(CLI::IsMember({"one", "two", "three"})); run(); CHECK(choice == "one"); @@ -432,7 +432,9 @@ TEST_CASE_METHOD(TApp, "InSetWithDefault", "[set]") { TEST_CASE_METHOD(TApp, "InCaselessSetWithDefault", "[set]") { std::string choice = "one"; - app.add_option("-q,--quick", choice, "", true)->transform(CLI::IsMember({"one", "two", "three"}, CLI::ignore_case)); + app.add_option("-q,--quick", choice) + ->capture_default_str() + ->transform(CLI::IsMember({"one", "two", "three"}, CLI::ignore_case)); run(); CHECK(choice == "one"); @@ -494,7 +496,7 @@ TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") { int choice{0}; auto vals = std::shared_ptr>(new std::set({1, 2, 3})); app.add_option("-q,--quick", choice)->check(CLI::IsMember(vals)); - app.add_option("-s,--slow", choice, "", true)->check(CLI::IsMember(vals)); + app.add_option("-s,--slow", choice)->capture_default_str()->check(CLI::IsMember(vals)); args = {"--quick=hello"}; CHECK_THROWS_AS(run(), CLI::ValidationError); @@ -651,7 +653,7 @@ TEST_CASE_METHOD(TApp, "AddRemoveSetItems", "[set]") { std::string type1, type2; app.add_option("--type1", type1)->check(CLI::IsMember(&items)); - app.add_option("--type2", type2, "", true)->check(CLI::IsMember(&items)); + app.add_option("--type2", type2)->capture_default_str()->check(CLI::IsMember(&items)); args = {"--type1", "TYPE1", "--type2", "TYPE2"}; @@ -682,7 +684,7 @@ TEST_CASE_METHOD(TApp, "AddRemoveSetItemsNoCase", "[set]") { std::string type1, type2; app.add_option("--type1", type1)->transform(CLI::IsMember(&items, CLI::ignore_case)); - app.add_option("--type2", type2, "", true)->transform(CLI::IsMember(&items, CLI::ignore_case)); + app.add_option("--type2", type2)->capture_default_str()->transform(CLI::IsMember(&items, CLI::ignore_case)); args = {"--type1", "TYPe1", "--type2", "TyPE2"}; diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index eef67bca7..c17013bf4 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -109,7 +109,7 @@ TEST_CASE_METHOD(TApp, "CrazyNameSubcommand", "[subcom]") { TEST_CASE_METHOD(TApp, "RequiredAndSubcommands", "[subcom]") { std::string baz; - app.add_option("baz", baz, "Baz Description", true)->required(); + app.add_option("baz", baz, "Baz Description")->required()->capture_default_str(); auto foo = app.add_subcommand("foo"); auto bar = app.add_subcommand("bar");