mirror of https://github.com/jarro2783/cxxopts.git
feat: Allow implicit values with disabled arguments
This commit is contained in:
parent
370de72bfe
commit
a7affdf6d6
10
README.md
10
README.md
|
|
@ -194,6 +194,16 @@ though it was given on the command line.
|
|||
|
||||
Default values are not counted by `Options::count`.
|
||||
|
||||
### Implicit values with disabled arguments
|
||||
|
||||
You can specify an option for which an argument cannot be specified using below syntax.
|
||||
|
||||
```cpp
|
||||
cxxopts::value<bool>()->implicit_value("true", true)
|
||||
```
|
||||
|
||||
In this case specifying option as `--option=<value>` is disallowed and will throw `specified_disabled_args` exception. Note that `--option value` is not supported for implicit values. It is treated as positional/unmatched.
|
||||
|
||||
## Boolean values
|
||||
|
||||
Boolean options have a default implicit value of `"true"`, which can be
|
||||
|
|
|
|||
|
|
@ -394,6 +394,9 @@ class Value : public std::enable_shared_from_this<Value>
|
|||
virtual bool
|
||||
has_implicit() const = 0;
|
||||
|
||||
virtual bool
|
||||
has_disabled_args() const = 0;
|
||||
|
||||
virtual std::string
|
||||
get_default_value() const = 0;
|
||||
|
||||
|
|
@ -404,7 +407,7 @@ class Value : public std::enable_shared_from_this<Value>
|
|||
default_value(const std::string& value) = 0;
|
||||
|
||||
virtual std::shared_ptr<Value>
|
||||
implicit_value(const std::string& value) = 0;
|
||||
implicit_value(const std::string& value, bool disabled_args = false) = 0;
|
||||
|
||||
virtual std::shared_ptr<Value>
|
||||
no_implicit_value() = 0;
|
||||
|
|
@ -482,6 +485,15 @@ class invalid_option_syntax : public parsing {
|
|||
}
|
||||
};
|
||||
|
||||
class specified_disabled_args : public parsing {
|
||||
public:
|
||||
explicit specified_disabled_args(const std::string& text)
|
||||
: parsing("Option " + LQUOTE + text + RQUOTE +
|
||||
" has disabled_args but argument was specified")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class no_such_option : public parsing
|
||||
{
|
||||
public:
|
||||
|
|
@ -1271,6 +1283,12 @@ class abstract_value : public Value
|
|||
return m_implicit;
|
||||
}
|
||||
|
||||
bool
|
||||
has_disabled_args() const override
|
||||
{
|
||||
return m_disabled_args;
|
||||
}
|
||||
|
||||
std::shared_ptr<Value>
|
||||
default_value(const std::string& value) override
|
||||
{
|
||||
|
|
@ -1280,10 +1298,11 @@ class abstract_value : public Value
|
|||
}
|
||||
|
||||
std::shared_ptr<Value>
|
||||
implicit_value(const std::string& value) override
|
||||
implicit_value(const std::string& value, bool disabled_args = false) override
|
||||
{
|
||||
m_implicit = true;
|
||||
m_implicit_value = value;
|
||||
m_disabled_args = disabled_args;
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
|
|
@ -1328,6 +1347,7 @@ class abstract_value : public Value
|
|||
|
||||
bool m_default = false;
|
||||
bool m_implicit = false;
|
||||
bool m_disabled_args = false;
|
||||
|
||||
std::string m_default_value{};
|
||||
std::string m_implicit_value{};
|
||||
|
|
@ -2634,6 +2654,9 @@ OptionParser::parse(int argc, const char* const* argv)
|
|||
{
|
||||
//it must be the last argument
|
||||
if (argu_desc.set_value) {
|
||||
if(value->value().has_disabled_args()){
|
||||
throw_or_mimic<exceptions::specified_disabled_args>(name);
|
||||
}
|
||||
parse_option(value, name, argu_desc.value);
|
||||
}
|
||||
else{
|
||||
|
|
@ -2681,6 +2704,9 @@ OptionParser::parse(int argc, const char* const* argv)
|
|||
//equals provided for long option?
|
||||
if (argu_desc.set_value)
|
||||
{
|
||||
if(opt->value().has_disabled_args()){
|
||||
throw_or_mimic<exceptions::specified_disabled_args>(name);
|
||||
}
|
||||
//parse the option given
|
||||
|
||||
parse_option(opt, name, argu_desc.value);
|
||||
|
|
|
|||
|
|
@ -638,6 +638,66 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Implicit value with disabled_args", "[no_value]")
|
||||
{
|
||||
const char prog_name[] = "disabled_args";
|
||||
cxxopts::Options options(prog_name, "Implicit value with disabled args");
|
||||
options.add_options()
|
||||
("b,bool", "description", cxxopts::value<bool>()->implicit_value("true", true))
|
||||
("s,string", "description", cxxopts::value<std::string>()->implicit_value("value", true));
|
||||
struct testcase{
|
||||
std::string name;
|
||||
Argv argv;
|
||||
} tests_eq[] = {
|
||||
{
|
||||
"exception due to value passed in long arg",
|
||||
Argv{prog_name, "--bool=true"},
|
||||
},
|
||||
{
|
||||
"exception due to value passed in short arg",
|
||||
Argv{prog_name, "-b=true"},
|
||||
},
|
||||
{
|
||||
"exception due to string value",
|
||||
Argv{prog_name, "-b", "--string=something_else"},
|
||||
}
|
||||
};
|
||||
|
||||
for(const auto& tc : tests_eq) {
|
||||
SECTION(tc.name){
|
||||
CHECK_THROWS_AS(options.parse(tc.argv.argc(), tc.argv.argv()),
|
||||
cxxopts::exceptions::specified_disabled_args);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("unmatched string value without ="){
|
||||
Argv argv{prog_name, "--string", "new_value"};
|
||||
auto result = options.parse(argv.argc(), argv.argv());
|
||||
CHECK(result.unmatched().size() == 1);
|
||||
CHECK(result.unmatched()[0] == "new_value");
|
||||
CHECK(result["string"].as<std::string>() == "value");
|
||||
}
|
||||
SECTION("unmatched short value without ="){
|
||||
Argv argv{prog_name, "-s", "new_value"};
|
||||
auto result = options.parse(argv.argc(), argv.argv());
|
||||
CHECK(result.unmatched().size() == 1);
|
||||
CHECK(result.unmatched()[0] == "new_value");
|
||||
CHECK(result["string"].as<std::string>() == "value");
|
||||
}
|
||||
SECTION("exception due to short value grouped"){
|
||||
Argv argv{prog_name, "-snew_value"};
|
||||
// it will be considered as -s -n -e ... because -s has implicit value
|
||||
CHECK_THROWS_AS(options.parse(argv.argc(), argv.argv()),
|
||||
cxxopts::exceptions::no_such_option);
|
||||
}
|
||||
SECTION("No exception"){
|
||||
Argv argv{prog_name, "--string", "-b"};
|
||||
auto result = options.parse(argv.argc(), argv.argv());
|
||||
CHECK(result["bool"].as<bool>() == true);
|
||||
CHECK(result["string"].as<std::string>() == "value");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Default values", "[default]")
|
||||
{
|
||||
cxxopts::Options options("defaults", "has defaults");
|
||||
|
|
|
|||
Loading…
Reference in New Issue