1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-30 12:43:52 +00:00

Remove double vector parse

This commit is contained in:
Henry Fredrick Schreiner 2017-03-02 13:10:32 -05:00
parent e870e264c3
commit 84add337bb
4 changed files with 37 additions and 67 deletions

View File

@ -1,5 +1,6 @@
## Version 0.6
* Simplified parsing to use `vector<string>` only
* Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`.
* Added string versions of `->requires()` and `->excludes()` for consistency.
* Renamed protected members for internal consistency, grouped docs.

View File

@ -41,7 +41,6 @@ This library was built to supply the Application object for the GooFit CUDA/OMP
* Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system?
* Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
* Test "adding to cmake" method
* Maybe simplify the `vector<vector>` structure of options, it is more powerful but unlikely to be needed.
See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details.
@ -117,7 +116,6 @@ app.add_config(option_name,
required=false)
App* subcom = app.add_subcommand(name, discription);
```
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
@ -145,7 +143,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
* `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
* `->check(CLI::Range(min,max))`: Requires that the option be between min and max (make sure to use floating point if needed). Min defaults to 0.
These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`.
These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`. If you just want to see the unconverted values, use `.results()` to get the `std::vector<std::string>` of results.
On the command line, options can be given as:
@ -201,17 +199,16 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent
## How it works
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of vector of strings, so it knows how many times an option was passed, and how many arguments each passing received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it recieved (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
`false` if it failed.
### Example
~~~python
app.add_option("--fancy-count", [](std::vector<std::vector<std::string>> val){
```cpp
app.add_option("--fancy-count", [](std::vector<std::string> val){
std::cout << "This option was given " << val.size() << " times." << std::endl
<< "The first time, it received " << val.at(0).size() << " items" << std::endl;
});
~~~
```
## Contributing
@ -221,7 +218,7 @@ To contribute, open an [issue](https://github.com/henryiii/CLI11/issues) or [pul
If you use the [`rang`](https://github.com/agauniyal/rang/wiki) library to add color to your terminal in a safe, multi-platform way, you can combine it with CLI11 nicely:
```
```cpp
std::atexit([](){std::cout << rang::style::reset;});
try {
app.parse(argc, argv);

View File

@ -227,13 +227,9 @@ public:
CLI::callback_t fun = [&variable](CLI::results_t res){
if(res.size()!=1) {
if(res.size()!=1)
return false;
}
if(res[0].size()!=1) {
return false;
}
return detail::lexical_cast(res[0][0], variable);
return detail::lexical_cast(res[0], variable);
};
Option* opt = add_option(name, fun, description, defaulted);
@ -258,10 +254,9 @@ public:
CLI::callback_t fun = [&variable](CLI::results_t res){
bool retval = true;
variable.clear();
for(const auto &a : res)
for(const auto &b : a) {
for(const auto &a : res) {
variable.emplace_back();
retval &= detail::lexical_cast(b, variable.back());
retval &= detail::lexical_cast(a, variable.back());
}
return variable.size() > 0 && retval;
};
@ -291,7 +286,7 @@ public:
return opt;
}
/// Add option for flag
/// Add option for flag integer
template<typename T,
enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
Option* add_flag(
@ -350,10 +345,7 @@ public:
if(res.size()!=1) {
return false;
}
if(res[0].size()!=1) {
return false;
}
bool retval = detail::lexical_cast(res[0][0], member);
bool retval = detail::lexical_cast(res[0], member);
if(!retval)
return false;
return std::find(std::begin(options), std::end(options), member) != std::end(options);
@ -383,10 +375,7 @@ public:
if(res.size()!=1) {
return false;
}
if(res[0].size()!=1) {
return false;
}
member = detail::to_lower(res.at(0).at(0));
member = detail::to_lower(res[0]);
auto iter = std::find_if(std::begin(options), std::end(options),
[&member](std::string val){return detail::to_lower(val) == member;});
if(iter == std::end(options))
@ -558,7 +547,7 @@ public:
std::stringstream out;
for(const Option_p &opt : options_) {
if(opt->lnames_.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
out << opt->lnames_[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
out << opt->lnames_[0] << "=" << detail::join(opt->results()) << std::endl;
}
return out.str();
}
@ -763,8 +752,7 @@ protected:
if (opt->count() == 0 && opt->envname_ != "") {
char *ename = std::getenv(opt->envname_.c_str());
if(ename != nullptr) {
opt->get_new();
opt->add_result(0, std::string(ename));
opt->add_result(std::string(ename));
}
}
}
@ -851,8 +839,7 @@ protected:
&& opt->count() < opt->get_expected()
) {
opt->get_new();
opt->add_result(0, positional);
opt->add_result(positional);
args.pop_back();
return;
}
@ -915,29 +902,28 @@ protected:
// Get a reference to the pointer to make syntax bearable
Option_p& op = *op_ptr;
int vnum = op->get_new();
int num = op->get_expected();
if(num == 0)
op->add_result(vnum, "");
op->add_result("");
else if(rest!="") {
if (num > 0)
num--;
op->add_result(vnum, rest);
op->add_result(rest);
rest = "";
}
if(num == -1) {
while(args.size()>0 && _recognize(args.back()) == detail::Classifer::NONE) {
op->add_result(vnum, args.back());
op->add_result(args.back());
args.pop_back();
}
} else while(num>0 && args.size() > 0) {
num--;
std::string current_ = args.back();
args.pop_back();
op->add_result(vnum, current_);
op->add_result(current_);
}
if(rest != "") {
@ -980,25 +966,23 @@ protected:
if(!overwrite && op->count() > 0)
return;
int vnum = op->get_new();
int num = op->get_expected();
if(value != "") {
if(num!=-1) num--;
op->add_result(vnum, value);
op->add_result(value);
} else if (num == 0) {
op->add_result(vnum, "");
op->add_result("");
}
if(num == -1) {
while(args.size() > 0 && _recognize(args.back()) == detail::Classifer::NONE) {
op->add_result(vnum, args.back());
op->add_result(args.back());
args.pop_back();
}
} else while(num>0 && args.size()>0) {
num--;
op->add_result(vnum,args.back());
op->add_result(args.back());
args.pop_back();
}
return;

View File

@ -17,7 +17,7 @@
namespace CLI {
typedef std::vector<std::vector<std::string>> results_t;
typedef std::vector<std::string> results_t;
typedef std::function<bool(results_t)> callback_t;
class Option;
@ -121,16 +121,13 @@ public:
/// Count the total number of times an option was passed
int count() const {
int out = 0;
for(const std::vector<std::string>& vec : results_)
out += vec.size();
return out;
return results_.size();
}
/// This class is true if option is passed.
operator bool() const {
return results_.size() > 0;
return count() > 0;
}
/// Clear the parsed results (mostly for testing)
@ -372,9 +369,9 @@ public:
/// Process the callback
void run_callback() const {
if(!callback_(results_))
throw ConversionError(get_name() + "=" + detail::join(flatten_results()));
throw ConversionError(get_name() + "=" + detail::join(results_));
if(validators_.size()>0) {
for(const std::string & result : flatten_results())
for(const std::string & result : results_)
for(const std::function<bool(std::string)> &vali : validators_)
if(!vali(result))
throw ValidationError(get_name() + "=" + result);
@ -440,23 +437,14 @@ public:
/// Puts a result at position r
void add_result(int r, std::string s) {
results_.at(r).push_back(s);
}
/// Starts a new results vector (used for r in add_result)
int get_new() {
results_.emplace_back();
return results_.size() - 1;
void add_result(std::string s) {
results_.push_back(s);
}
/// Produce a flattened vector of results, vs. a vector of vectors.
std::vector<std::string> flatten_results() const {
std::vector<std::string> output;
for(const std::vector<std::string> result : results_)
output.insert(std::end(output), std::begin(result), std::end(result));
return output;
/// Get a copy of the results
std::vector<std::string> results() const {
return results_;
}
///@}