mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 12:43:52 +00:00
Option delimiter (#240)
* move delimiter controls to Option vs in the App callbacks
This commit is contained in:
parent
7254ea7916
commit
9f81385bcd
@ -273,6 +273,7 @@ Before parsing, you can set the following options:
|
|||||||
- `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
|
- `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
|
||||||
- `->ignore_underscore()`: Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character
|
- `->ignore_underscore()`: Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character
|
||||||
- `->disable_flag_override()`: from the command line long form flag option can be assigned a value on the command line using the `=` notation `--flag=value`. If this behavior is not desired, the `disable_flag_override()` disables it and will generate an exception if it is done on the command line. The `=` does not work with short form flag options.
|
- `->disable_flag_override()`: from the command line long form flag option can be assigned a value on the command line using the `=` notation `--flag=value`. If this behavior is not desired, the `disable_flag_override()` disables it and will generate an exception if it is done on the command line. The `=` does not work with short form flag options.
|
||||||
|
- `->delimiter(char)`: allows specification of a custom delimiter for separating single arguments into vector arguments, for example specifying `->delimiter(',')` on an option would result in `--opt=1,2,3` producing 3 elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a vector value
|
||||||
- `->description(str)`: Set/change the description.
|
- `->description(str)`: Set/change the description.
|
||||||
- `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`, and `->join()`. This will only affect options expecting 1 argument or bool flags (which do not inherit their default but always start with a specific policy).
|
- `->multi_option_policy(CLI::MultiOptionPolicy::Throw)`: Set the multi-option policy. Shortcuts available: `->take_last()`, `->take_first()`, and `->join()`. This will only affect options expecting 1 argument or bool flags (which do not inherit their default but always start with a specific policy).
|
||||||
- `->check(CLI::IsMember(...))`: Require an option be a member of a given set. See below for options.
|
- `->check(CLI::IsMember(...))`: Require an option be a member of a given set. See below for options.
|
||||||
@ -338,9 +339,7 @@ In most cases the fastest and easiest way is to return the results through a cal
|
|||||||
|
|
||||||
- `results()`: retrieves a vector of strings with all the results in the order they were given.
|
- `results()`: retrieves a vector of strings with all the results in the order they were given.
|
||||||
- `results(variable_to_bind_to)`: gets the results according to the MultiOptionPolicy and converts them just like the `add_option_function` with a variable.
|
- `results(variable_to_bind_to)`: gets the results according to the MultiOptionPolicy and converts them just like the `add_option_function` with a variable.
|
||||||
- `results(vector_type_variable,delimiter)`: gets the results to a vector type and uses a delimiter to further split the values
|
- `Value=as<type>()`: returns the result or default value directly as the specified type if possible, can be vector to return all results, and a non-vector to get the result according to the MultiOptionPolicy in place.
|
||||||
- `Value=as<type>()`: returns the result or default value directly as the specified type if possible.
|
|
||||||
- `Vector_value=as<type>(delimiter): same the results function with the delimiter but returns the value directly.
|
|
||||||
|
|
||||||
### Subcommands
|
### Subcommands
|
||||||
|
|
||||||
@ -434,7 +433,7 @@ arguments, use `.config_to_str(default_also=false, prefix="", write_description=
|
|||||||
|
|
||||||
Many of the defaults for subcommands and even options are inherited from their creators. The inherited default values for subcommands are `allow_extras`, `prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`, `footer`, and maximum number of required subcommands. The help flag existence, name, and description are inherited, as well.
|
Many of the defaults for subcommands and even options are inherited from their creators. The inherited default values for subcommands are `allow_extras`, `prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`, `footer`, and maximum number of required subcommands. The help flag existence, name, and description are inherited, as well.
|
||||||
|
|
||||||
Options have defaults for `group`, `required`, `disable_flag_override`,`multi_option_policy`, `ignore_underscore`, and `ignore_case`. To set these defaults, you should set the `option_defaults()` object, for example:
|
Options have defaults for `group`, `required`, `disable_flag_override`,`multi_option_policy`, `ignore_underscore`,`delimiter`, and `ignore_case`. To set these defaults, you should set the `option_defaults()` object, for example:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
app.option_defaults()->required();
|
app.option_defaults()->required();
|
||||||
|
@ -435,29 +435,21 @@ class App {
|
|||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add option for vectors (no default)
|
/// Add option for vectors
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Option *add_option(std::string option_name,
|
Option *add_option(std::string option_name,
|
||||||
std::vector<T> &variable, ///< The variable vector to set
|
std::vector<T> &variable, ///< The variable vector to set
|
||||||
std::string option_description = "",
|
std::string option_description = "") {
|
||||||
char delimiter = '\0') {
|
|
||||||
|
|
||||||
CLI::callback_t fun = [&variable, delimiter](CLI::results_t res) {
|
CLI::callback_t fun = [&variable](CLI::results_t res) {
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
variable.clear();
|
variable.clear();
|
||||||
|
variable.reserve(res.size());
|
||||||
for(const auto &elem : res) {
|
for(const auto &elem : res) {
|
||||||
if((delimiter != '\0') && (elem.find_first_of(delimiter) != std::string::npos)) {
|
|
||||||
for(const auto &var : CLI::detail::split(elem, delimiter)) {
|
|
||||||
if(!var.empty()) {
|
|
||||||
variable.emplace_back();
|
|
||||||
retval &= detail::lexical_cast(var, variable.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
variable.emplace_back();
|
variable.emplace_back();
|
||||||
retval &= detail::lexical_cast(elem, variable.back());
|
retval &= detail::lexical_cast(elem, variable.back());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (!variable.empty()) && retval;
|
return (!variable.empty()) && retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -466,35 +458,28 @@ class App {
|
|||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add option for vectors
|
/// Add option for vectors with defaulted argument
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Option *add_option(std::string option_name,
|
Option *add_option(std::string option_name,
|
||||||
std::vector<T> &variable, ///< The variable vector to set
|
std::vector<T> &variable, ///< The variable vector to set
|
||||||
std::string option_description,
|
std::string option_description,
|
||||||
bool defaulted,
|
bool defaulted) {
|
||||||
char delimiter = '\0') {
|
|
||||||
|
|
||||||
CLI::callback_t fun = [&variable, delimiter](CLI::results_t res) {
|
CLI::callback_t fun = [&variable](CLI::results_t res) {
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
variable.clear();
|
variable.clear();
|
||||||
|
variable.reserve(res.size());
|
||||||
for(const auto &elem : res) {
|
for(const auto &elem : res) {
|
||||||
if((delimiter != '\0') && (elem.find_first_of(delimiter) != std::string::npos)) {
|
|
||||||
for(const auto &var : CLI::detail::split(elem, delimiter)) {
|
|
||||||
if(!var.empty()) {
|
|
||||||
variable.emplace_back();
|
|
||||||
retval &= detail::lexical_cast(var, variable.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
variable.emplace_back();
|
variable.emplace_back();
|
||||||
retval &= detail::lexical_cast(elem, variable.back());
|
retval &= detail::lexical_cast(elem, variable.back());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (!variable.empty()) && retval;
|
return (!variable.empty()) && retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
Option *opt = add_option(option_name, fun, option_description, defaulted);
|
Option *opt = add_option(option_name, fun, option_description, defaulted);
|
||||||
opt->type_name(detail::type_name<T>())->type_size(-1);
|
opt->type_name(detail::type_name<T>())->type_size(-1);
|
||||||
|
|
||||||
if(defaulted)
|
if(defaulted)
|
||||||
opt->default_str("[" + detail::join(variable) + "]");
|
opt->default_str("[" + detail::join(variable) + "]");
|
||||||
return opt;
|
return opt;
|
||||||
@ -504,26 +489,16 @@ class App {
|
|||||||
template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail::dummy>
|
template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail::dummy>
|
||||||
Option *add_option_function(std::string option_name,
|
Option *add_option_function(std::string option_name,
|
||||||
const std::function<bool(const T &)> &func, ///< the callback to execute
|
const std::function<bool(const T &)> &func, ///< the callback to execute
|
||||||
std::string option_description = "",
|
std::string option_description = "") {
|
||||||
char delimiter = '\0') {
|
|
||||||
|
|
||||||
CLI::callback_t fun = [func, delimiter](CLI::results_t res) {
|
CLI::callback_t fun = [func](CLI::results_t res) {
|
||||||
T values;
|
T values;
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
values.reserve(res.size());
|
values.reserve(res.size());
|
||||||
for(const auto &elem : res) {
|
for(const auto &elem : res) {
|
||||||
if((delimiter != '\0') && (elem.find_first_of(delimiter) != std::string::npos)) {
|
|
||||||
for(const auto &var : CLI::detail::split(elem, delimiter)) {
|
|
||||||
if(!var.empty()) {
|
|
||||||
values.emplace_back();
|
|
||||||
retval &= detail::lexical_cast(var, values.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
values.emplace_back();
|
values.emplace_back();
|
||||||
retval &= detail::lexical_cast(elem, values.back());
|
retval &= detail::lexical_cast(elem, values.back());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(retval) {
|
if(retval) {
|
||||||
return func(values);
|
return func(values);
|
||||||
}
|
}
|
||||||
@ -2032,6 +2007,7 @@ class App {
|
|||||||
// Make sure we always eat the minimum for unlimited vectors
|
// Make sure we always eat the minimum for unlimited vectors
|
||||||
int collected = 0;
|
int collected = 0;
|
||||||
// deal with flag like things
|
// deal with flag like things
|
||||||
|
int count = 0;
|
||||||
if(num == 0) {
|
if(num == 0) {
|
||||||
auto res = op->get_flag_value(arg_name, value);
|
auto res = op->get_flag_value(arg_name, value);
|
||||||
op->add_result(res);
|
op->add_result(res);
|
||||||
@ -2039,20 +2015,22 @@ class App {
|
|||||||
}
|
}
|
||||||
// --this=value
|
// --this=value
|
||||||
else if(!value.empty()) {
|
else if(!value.empty()) {
|
||||||
|
op->add_result(value, count);
|
||||||
|
parse_order_.push_back(op.get());
|
||||||
|
collected += count;
|
||||||
// If exact number expected
|
// If exact number expected
|
||||||
if(num > 0)
|
if(num > 0)
|
||||||
num--;
|
num = (num >= count) ? num - count : 0;
|
||||||
op->add_result(value);
|
|
||||||
parse_order_.push_back(op.get());
|
|
||||||
collected += 1;
|
|
||||||
// -Trest
|
// -Trest
|
||||||
} else if(!rest.empty()) {
|
} else if(!rest.empty()) {
|
||||||
if(num > 0)
|
op->add_result(rest, count);
|
||||||
num--;
|
|
||||||
op->add_result(rest);
|
|
||||||
parse_order_.push_back(op.get());
|
parse_order_.push_back(op.get());
|
||||||
rest = "";
|
rest = "";
|
||||||
collected += 1;
|
collected += count;
|
||||||
|
// If exact number expected
|
||||||
|
if(num > 0)
|
||||||
|
num = (num >= count) ? num - count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlimited vector parser
|
// Unlimited vector parser
|
||||||
@ -2065,10 +2043,10 @@ class App {
|
|||||||
if(_count_remaining_positionals() > 0)
|
if(_count_remaining_positionals() > 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
op->add_result(args.back());
|
op->add_result(args.back(), count);
|
||||||
parse_order_.push_back(op.get());
|
parse_order_.push_back(op.get());
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
collected++;
|
collected += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow -- to end an unlimited list and "eat" it
|
// Allow -- to end an unlimited list and "eat" it
|
||||||
@ -2077,11 +2055,11 @@ class App {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
while(num > 0 && !args.empty()) {
|
while(num > 0 && !args.empty()) {
|
||||||
num--;
|
|
||||||
std::string current_ = args.back();
|
std::string current_ = args.back();
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
op->add_result(current_);
|
op->add_result(current_, count);
|
||||||
parse_order_.push_back(op.get());
|
parse_order_.push_back(op.get());
|
||||||
|
num -= count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(num > 0) {
|
if(num > 0) {
|
||||||
|
@ -52,7 +52,8 @@ template <typename CRTP> class OptionBase {
|
|||||||
bool configurable_{true};
|
bool configurable_{true};
|
||||||
/// Disable overriding flag values with '=value'
|
/// Disable overriding flag values with '=value'
|
||||||
bool disable_flag_override_{false};
|
bool disable_flag_override_{false};
|
||||||
|
/// Specify a delimiter character for vector arguments
|
||||||
|
char delimiter_{'\0'};
|
||||||
/// Policy for multiple arguments when `expected_ == 1` (can be set on bool flags, too)
|
/// Policy for multiple arguments when `expected_ == 1` (can be set on bool flags, too)
|
||||||
MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
|
MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ template <typename CRTP> class OptionBase {
|
|||||||
other->ignore_underscore(ignore_underscore_);
|
other->ignore_underscore(ignore_underscore_);
|
||||||
other->configurable(configurable_);
|
other->configurable(configurable_);
|
||||||
other->disable_flag_override(disable_flag_override_);
|
other->disable_flag_override(disable_flag_override_);
|
||||||
|
other->delimiter(delimiter_);
|
||||||
other->multi_option_policy(multi_option_policy_);
|
other->multi_option_policy(multi_option_policy_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +108,7 @@ template <typename CRTP> class OptionBase {
|
|||||||
/// The status of configurable
|
/// The status of configurable
|
||||||
bool get_disable_flag_override() const { return disable_flag_override_; }
|
bool get_disable_flag_override() const { return disable_flag_override_; }
|
||||||
|
|
||||||
|
char get_delimiter() const { return delimiter_; }
|
||||||
/// The status of the multi option policy
|
/// The status of the multi option policy
|
||||||
MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
|
MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
|
||||||
|
|
||||||
@ -137,6 +140,12 @@ template <typename CRTP> class OptionBase {
|
|||||||
configurable_ = value;
|
configurable_ = value;
|
||||||
return static_cast<CRTP *>(this);
|
return static_cast<CRTP *>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allow in a configuration file
|
||||||
|
CRTP *delimiter(char value = '\0') {
|
||||||
|
delimiter_ = value;
|
||||||
|
return static_cast<CRTP *>(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is a version of OptionBase that only supports setting values,
|
/// This is a version of OptionBase that only supports setting values,
|
||||||
@ -165,11 +174,17 @@ class OptionDefaults : public OptionBase<OptionDefaults> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ignore underscores in the option name
|
/// Disable overriding flag values with an '=<value>' segment
|
||||||
OptionDefaults *disable_flag_override(bool value = true) {
|
OptionDefaults *disable_flag_override(bool value = true) {
|
||||||
disable_flag_override_ = value;
|
disable_flag_override_ = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set a delimiter character to split up single arguments to treat as multiple inputs
|
||||||
|
OptionDefaults *delimiter(char value = '\0') {
|
||||||
|
delimiter_ = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Option : public OptionBase<Option> {
|
class Option : public OptionBase<Option> {
|
||||||
@ -793,19 +808,23 @@ class Option : public OptionBase<Option> {
|
|||||||
|
|
||||||
/// Puts a result at the end
|
/// Puts a result at the end
|
||||||
Option *add_result(std::string s) {
|
Option *add_result(std::string s) {
|
||||||
results_.push_back(std::move(s));
|
_add_result(std::move(s));
|
||||||
|
callback_run_ = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Puts a result at the end and get a count of the number of arguments actually added
|
||||||
|
Option *add_result(std::string s, int &count) {
|
||||||
|
count = _add_result(std::move(s));
|
||||||
callback_run_ = false;
|
callback_run_ = false;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Puts a result at the end
|
/// Puts a result at the end
|
||||||
Option *add_result(std::vector<std::string> s) {
|
Option *add_result(std::vector<std::string> s) {
|
||||||
if(results_.empty()) {
|
for(auto &str : s) {
|
||||||
results_ = std::move(s);
|
_add_result(std::move(str));
|
||||||
} else {
|
|
||||||
results_.insert(results_.end(), s.begin(), s.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback_run_ = false;
|
callback_run_ = false;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -850,23 +869,14 @@ class Option : public OptionBase<Option> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// get the results as a vector of a particular type
|
/// get the results as a vector of a particular type
|
||||||
template <typename T> void results(std::vector<T> &output, char delim = '\0') const {
|
template <typename T> void results(std::vector<T> &output) const {
|
||||||
output.clear();
|
output.clear();
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
|
|
||||||
for(const auto &elem : results_) {
|
for(const auto &elem : results_) {
|
||||||
if(delim != '\0') {
|
|
||||||
for(const auto &var : CLI::detail::split(elem, delim)) {
|
|
||||||
if(!var.empty()) {
|
|
||||||
output.emplace_back();
|
|
||||||
retval &= detail::lexical_cast(var, output.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
output.emplace_back();
|
output.emplace_back();
|
||||||
retval &= detail::lexical_cast(elem, output.back());
|
retval &= detail::lexical_cast(elem, output.back());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!retval) {
|
if(!retval) {
|
||||||
throw ConversionError(get_name(), results_);
|
throw ConversionError(get_name(), results_);
|
||||||
@ -874,20 +884,12 @@ class Option : public OptionBase<Option> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return the results as a particular type
|
/// return the results as a particular type
|
||||||
template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> T as() const {
|
template <typename T> T as() const {
|
||||||
T output;
|
T output;
|
||||||
results(output);
|
results(output);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the results as a vector of a particular type
|
|
||||||
template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail::dummy>
|
|
||||||
T as(char delim = '\0') const {
|
|
||||||
T output;
|
|
||||||
results(output, delim);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See if the callback has been run already
|
/// See if the callback has been run already
|
||||||
bool get_callback_run() const { return callback_run_; }
|
bool get_callback_run() const { return callback_run_; }
|
||||||
|
|
||||||
@ -935,6 +937,28 @@ class Option : public OptionBase<Option> {
|
|||||||
|
|
||||||
/// Get the typename for this option
|
/// Get the typename for this option
|
||||||
std::string get_type_name() const { return type_name_(); }
|
std::string get_type_name() const { return type_name_(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _add_result(std::string &&result) {
|
||||||
|
int count = 0;
|
||||||
|
if(delimiter_ == '\0') {
|
||||||
|
results_.push_back(std::move(result));
|
||||||
|
++count;
|
||||||
|
} else {
|
||||||
|
if((result.find_first_of(delimiter_) != std::string::npos)) {
|
||||||
|
for(const auto &var : CLI::detail::split(result, delimiter_)) {
|
||||||
|
if(!var.empty()) {
|
||||||
|
results_.push_back(var);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results_.push_back(std::move(result));
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CLI
|
} // namespace CLI
|
||||||
|
@ -1956,17 +1956,17 @@ TEST_F(TApp, CustomUserSepParse) {
|
|||||||
|
|
||||||
std::vector<int> vals = {1, 2, 3};
|
std::vector<int> vals = {1, 2, 3};
|
||||||
args = {"--idx", "1,2,3"};
|
args = {"--idx", "1,2,3"};
|
||||||
auto opt = app.add_option("--idx", vals, "", ',');
|
auto opt = app.add_option("--idx", vals)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
||||||
std::vector<int> vals2;
|
std::vector<int> vals2;
|
||||||
// check that the results vector gets the results in the same way
|
// check that the results vector gets the results in the same way
|
||||||
opt->results(vals2, ',');
|
opt->results(vals2);
|
||||||
EXPECT_EQ(vals2, vals);
|
EXPECT_EQ(vals2, vals);
|
||||||
|
|
||||||
app.remove_option(opt);
|
app.remove_option(opt);
|
||||||
|
|
||||||
app.add_option("--idx", vals, "", true, ',');
|
app.add_option("--idx", vals, "", true)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
||||||
}
|
}
|
||||||
@ -1979,8 +1979,7 @@ TEST_F(TApp, DefaultUserSepParse) {
|
|||||||
auto opt = app.add_option("--idx", vals, "");
|
auto opt = app.add_option("--idx", vals, "");
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<std::string>({"1 2 3", "4 5 6"}));
|
EXPECT_EQ(vals, std::vector<std::string>({"1 2 3", "4 5 6"}));
|
||||||
app.remove_option(opt);
|
opt->delimiter(',');
|
||||||
app.add_option("--idx", vals, "", true);
|
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<std::string>({"1 2 3", "4 5 6"}));
|
EXPECT_EQ(vals, std::vector<std::string>({"1 2 3", "4 5 6"}));
|
||||||
}
|
}
|
||||||
@ -1989,7 +1988,7 @@ TEST_F(TApp, DefaultUserSepParse) {
|
|||||||
TEST_F(TApp, BadUserSepParse) {
|
TEST_F(TApp, BadUserSepParse) {
|
||||||
|
|
||||||
std::vector<int> vals;
|
std::vector<int> vals;
|
||||||
app.add_option("--idx", vals, "");
|
app.add_option("--idx", vals);
|
||||||
|
|
||||||
args = {"--idx", "1,2,3"};
|
args = {"--idx", "1,2,3"};
|
||||||
|
|
||||||
@ -2001,13 +2000,13 @@ TEST_F(TApp, CustomUserSepParse2) {
|
|||||||
|
|
||||||
std::vector<int> vals = {1, 2, 3};
|
std::vector<int> vals = {1, 2, 3};
|
||||||
args = {"--idx", "1,2,"};
|
args = {"--idx", "1,2,"};
|
||||||
auto opt = app.add_option("--idx", vals, "", ',');
|
auto opt = app.add_option("--idx", vals)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
|
|
||||||
app.remove_option(opt);
|
app.remove_option(opt);
|
||||||
|
|
||||||
app.add_option("--idx", vals, "", true, ',');
|
app.add_option("--idx", vals, "", true)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
}
|
}
|
||||||
@ -2020,13 +2019,28 @@ TEST_F(TApp, CustomUserSepParseFunction) {
|
|||||||
[&vals](std::vector<int> v) {
|
[&vals](std::vector<int> v) {
|
||||||
vals = std::move(v);
|
vals = std::move(v);
|
||||||
return true;
|
return true;
|
||||||
},
|
})
|
||||||
"",
|
->delimiter(',');
|
||||||
',');
|
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delimiter removal
|
||||||
|
TEST_F(TApp, CustomUserSepParseToggle) {
|
||||||
|
|
||||||
|
std::vector<std::string> vals;
|
||||||
|
args = {"--idx", "1,2,3"};
|
||||||
|
auto opt = app.add_option("--idx", vals)->delimiter(',');
|
||||||
|
run();
|
||||||
|
EXPECT_EQ(vals, std::vector<std::string>({"1", "2", "3"}));
|
||||||
|
opt->delimiter('\0');
|
||||||
|
run();
|
||||||
|
EXPECT_EQ(vals, std::vector<std::string>({"1,2,3"}));
|
||||||
|
opt->delimiter(',');
|
||||||
|
run();
|
||||||
|
EXPECT_EQ(vals, std::vector<std::string>({"1", "2", "3"}));
|
||||||
|
}
|
||||||
|
|
||||||
// #209
|
// #209
|
||||||
TEST_F(TApp, CustomUserSepParse3) {
|
TEST_F(TApp, CustomUserSepParse3) {
|
||||||
|
|
||||||
@ -2035,12 +2049,12 @@ TEST_F(TApp, CustomUserSepParse3) {
|
|||||||
"1",
|
"1",
|
||||||
","
|
","
|
||||||
"2"};
|
"2"};
|
||||||
auto opt = app.add_option("--idx", vals, "", ',');
|
auto opt = app.add_option("--idx", vals)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
app.remove_option(opt);
|
app.remove_option(opt);
|
||||||
|
|
||||||
app.add_option("--idx", vals, "", false, ',');
|
app.add_option("--idx", vals, "", false)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
}
|
}
|
||||||
@ -2050,13 +2064,13 @@ TEST_F(TApp, CustomUserSepParse4) {
|
|||||||
|
|
||||||
std::vector<int> vals;
|
std::vector<int> vals;
|
||||||
args = {"--idx", "1, 2"};
|
args = {"--idx", "1, 2"};
|
||||||
auto opt = app.add_option("--idx", vals, "", ',');
|
auto opt = app.add_option("--idx", vals)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
|
|
||||||
app.remove_option(opt);
|
app.remove_option(opt);
|
||||||
|
|
||||||
app.add_option("--idx", vals, "", true, ',');
|
app.add_option("--idx", vals, "", true)->delimiter(',');
|
||||||
run();
|
run();
|
||||||
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
EXPECT_EQ(vals, std::vector<int>({1, 2}));
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,38 @@ TEST_F(TApp, BuiltinComplex) {
|
|||||||
EXPECT_DOUBLE_EQ(3, comp.imag());
|
EXPECT_DOUBLE_EQ(3, comp.imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, BuiltinComplexWithDelimiter) {
|
||||||
|
cx comp{1, 2};
|
||||||
|
app.add_complex("-c,--complex", comp, "", true)->delimiter('+');
|
||||||
|
|
||||||
|
args = {"-c", "4+3i"};
|
||||||
|
|
||||||
|
std::string help = app.help();
|
||||||
|
EXPECT_THAT(help, HasSubstr("1"));
|
||||||
|
EXPECT_THAT(help, HasSubstr("2"));
|
||||||
|
EXPECT_THAT(help, HasSubstr("COMPLEX"));
|
||||||
|
|
||||||
|
EXPECT_DOUBLE_EQ(1, comp.real());
|
||||||
|
EXPECT_DOUBLE_EQ(2, comp.imag());
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_DOUBLE_EQ(4, comp.real());
|
||||||
|
EXPECT_DOUBLE_EQ(3, comp.imag());
|
||||||
|
|
||||||
|
args = {"-c", "5+-3i"};
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_DOUBLE_EQ(5, comp.real());
|
||||||
|
EXPECT_DOUBLE_EQ(-3, comp.imag());
|
||||||
|
|
||||||
|
args = {"-c", "6", "-4i"};
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_DOUBLE_EQ(6, comp.real());
|
||||||
|
EXPECT_DOUBLE_EQ(-4, comp.imag());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TApp, BuiltinComplexIgnoreI) {
|
TEST_F(TApp, BuiltinComplexIgnoreI) {
|
||||||
cx comp{1, 2};
|
cx comp{1, 2};
|
||||||
app.add_complex("-c,--complex", comp);
|
app.add_complex("-c,--complex", comp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user