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

Adding make_* options

This commit is contained in:
Henry Fredrick Schreiner 2017-01-31 09:18:56 -05:00
parent 074d0339a4
commit 324a9c738d
2 changed files with 140 additions and 5 deletions

View File

@ -11,7 +11,7 @@
#include <algorithm>
#include <sstream>
#include <type_traits>
#include <unordered_set>
#include <set>
#include <iomanip>
#include <numeric>
@ -450,6 +450,10 @@ public:
logit(subcommands.back()->name);
return subcommands.back().get();
}
//------------ ADD STYLE ---------//
/// Add an option, will automatically understand the type for common types.
/** To use, create a variable with the expected type, and pass it in after the name.
* After start is called, you can use count to see if the value was passed, and
@ -563,7 +567,7 @@ public:
Option* add_set(
std::string name, ///< The name, short,long
T &member, ///< The selected member of the set
std::unordered_set<T> options, ///< The set of posibilities
std::set<T> options, ///< The set of posibilities
std::string discription="", ///< Discription string
Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS())
) {
@ -581,14 +585,20 @@ public:
bool retval = lexical_cast(res[0][0], member);
if(!retval)
return false;
return std::find(std::begin(options), std::end(options), retval) != std::end(options);
return std::find(std::begin(options), std::end(options), member) != std::end(options);
};
return add_option(name, fun, discription, opts);
}
//------------ MAKE STYLE ---------//
/// Prototype for new output style
template<typename T = std::string>
template<typename T = std::string,
enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
Value<T> make_option(
std::string name, ///< The name, short,long
std::string discription="",
@ -611,7 +621,117 @@ public:
add_option(name, fun, discription, opts);
return out;
}
/// Prototype for new output style with default
template<typename T = std::string,
enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
Value<T> make_option(
std::string name, ///< The name, short,long
const T& default_value,
std::string discription="",
Combiner opts=VALIDATORS
) {
Value<T> out(name);
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
ptr->reset(new T(default_value)); // resets the internal ptr
CLI::callback_t fun = [ptr](CLI::results_t res){
if(res.size()!=1) {
return false;
}
if(res[0].size()!=1) {
return false;
}
ptr->reset(new T()); // resets the internal ptr
return lexical_cast(res[0][0], **ptr);
};
add_option(name, fun, discription, opts);
return out;
}
/// Prototype for new output style
template<typename T>
Value<std::vector<T>> make_option(
std::string name, ///< The name, short,long
std::string discription="",
Combiner opts=VALIDATORS
) {
if(opts.num==0)
throw IncorrectConstruction("Must have ARGS or be a vector.");
Value<std::vector<T>> out(name);
std::shared_ptr<std::unique_ptr<std::vector<T> >> ptr = out.value;
CLI::callback_t fun = [ptr](CLI::results_t res){
ptr->reset(new std::vector<T>()); // resets the internal ptr
bool retval = true;
for(const auto &a : res)
for(const auto &b : a) {
(*ptr)->emplace_back();
retval &= lexical_cast(b, (*ptr)->back());
}
return (*ptr)->size() > 0 && retval;
};
add_option(name, fun, discription, opts);
return out;
}
/// Prototype for new output style: flag
Value<int> make_flag(
std::string name, ///< The name, short,long
std::string discription=""
) {
Value<int> out(name);
std::shared_ptr<std::unique_ptr<int>> ptr = out.value;
ptr->reset(new int()); // resets the internal ptr
**ptr = 0;
CLI::callback_t fun = [ptr](CLI::results_t res){
**ptr = (int) res.size();
return true;
};
add_option(name, fun, discription, NOTHING);
return out;
}
/// Add set of options
template<typename T>
Value<T> make_set(
std::string name, ///< The name, short,long
std::set<T> options, ///< The set of posibilities
std::string discription="", ///< Discription string
Combiner opts=VALIDATORS ///< The options (REQUIRED, DEFAULT, POSITIONAL, ARGS())
) {
Value<T> out(name);
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
if(opts.num!=1)
throw IncorrectConstruction("Must have ARGS(1).");
CLI::callback_t fun = [ptr, options](CLI::results_t res){
if(res.size()!=1) {
return false;
}
if(res[0].size()!=1) {
return false;
}
ptr->reset(new T());
bool retval = lexical_cast(res[0][0], **ptr);
if(!retval)
return false;
return std::find(std::begin(options), std::end(options), **ptr) != std::end(options);
};
add_option(name, fun, discription, opts);
return out;
}
/// Parses the command line - throws errors
void parse(int argc, char **argv) {

View File

@ -249,6 +249,22 @@ TEST_F(TApp, FileExists) {
EXPECT_FALSE(CLI::_ExistingFile(myfile));
}
TEST_F(TApp, InSet) {
std::string choice;
app.add_set("q,quick", choice, {"one", "two", "three"});
args = {"--quick", "two"};
EXPECT_NO_THROW(run());
EXPECT_EQ("two", choice);
app.reset();
args = {"--quick", "four"};
EXPECT_THROW(run(), CLI::ParseError);
}
TEST_F(TApp, VectorFixedString) {
std::vector<std::string> strvec;
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
@ -366,7 +382,6 @@ TEST_F(TAppValue, OneString) {
}
// TODO: Add vector arguments
// TODO: Maybe add function to call on subcommand parse? Stashed.
// TODO: Check help output
// TODO: Add default/type info to help