Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding map support to IsMember #228

Merged
merged 6 commits into from
Feb 20, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adding example, better Val combs, and cleanup
henryiii committed Feb 20, 2019
commit ded999bf9c91a63a0e9f899a6bba9dc4fcd5b6a8
2 changes: 1 addition & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ add_cli_exe(enum enum.cpp)
add_test(NAME enum_pass COMMAND enum -l 1)
add_test(NAME enum_fail COMMAND enum -l 4)
set_property(TEST enum_fail PROPERTY PASS_REGULAR_EXPRESSION
"--level: 4 not in {0,1,2}")
"--level: 4 not in {High,Medium,Low} | 4 not in {0,1,2}")

add_cli_exe(modhelp modhelp.cpp)
add_test(NAME modhelp COMMAND modhelp -a test -h)
10 changes: 8 additions & 2 deletions examples/enum.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <CLI/CLI.hpp>
#include <map>
#include <sstream>

enum class Level : int { High, Medium, Low };
@@ -15,12 +16,17 @@ std::ostream &operator<<(std::ostream &in, const Level &level) { return in << st
int main(int argc, char **argv) {
CLI::App app;

std::map<Level, std::string> map = {{Level::High, "High"}, {Level::Medium, "Medium"}, {Level::Low, "Low"}};

Level level;

app.add_option("-l,--level", level, "Level settings")
->check(CLI::IsMember({Level::High, Level::Medium, Level::Low}))
->type_name("enum/Level in {High=0, Medium=1, Low=2}");
->required()
->check(CLI::IsMember(map, CLI::ignore_case) | CLI::IsMember({Level::High, Level::Medium, Level::Low}));

CLI11_PARSE(app, argc, argv);

std::cout << "Enum received: " << level << std::endl;

return 0;
}
28 changes: 16 additions & 12 deletions include/CLI/Validators.hpp
Original file line number Diff line number Diff line change
@@ -57,18 +57,20 @@ class Validator {
return func(value);
};

/// Combining validators is a new validator
/// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the
/// same.
Validator operator&(const Validator &other) const {
Validator newval;
newval.tname = (tname == other.tname ? tname : "");
newval.tname_function = tname_function;

// Give references (will make a copy in lambda function)
const std::function<std::string(std::string & filename)> &f1 = func;
const std::function<std::string(std::string & filename)> &f2 = other.func;

newval.func = [f1, f2](std::string &filename) {
std::string s1 = f1(filename);
std::string s2 = f2(filename);
newval.func = [f1, f2](std::string &input) {
std::string s1 = f1(input);
std::string s2 = f2(input);
if(!s1.empty() && !s2.empty())
return s1 + " & " + s2;
else
@@ -77,22 +79,24 @@ class Validator {
return newval;
}

/// Combining validators is a new validator
/// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the
/// same.
Validator operator|(const Validator &other) const {
Validator newval;
newval.tname = (tname == other.tname ? tname : "");
newval.tname_function = tname_function;

// Give references (will make a copy in lambda function)
const std::function<std::string(std::string & filename)> &f1 = func;
const std::function<std::string(std::string & filename)> &f2 = other.func;
const std::function<std::string(std::string &)> &f1 = func;
const std::function<std::string(std::string &)> &f2 = other.func;

newval.func = [f1, f2](std::string &filename) {
std::string s1 = f1(filename);
std::string s2 = f2(filename);
newval.func = [f1, f2](std::string &input) {
std::string s1 = f1(input);
std::string s2 = f2(input);
if(s1.empty() || s2.empty())
return std::string();
else
return s1 + " & " + s2;
return s1 + " | " + s2;
};
return newval;
}
@@ -308,7 +312,7 @@ class IsMember : public Validator {
// This is the type name for help, it will take the current version of the set contents
tname_function = [set]() {
std::stringstream out;
out << detail::type_name<item_t>() << " in {";
out << "{";
int i = 0; // I don't like counters like this
for(const auto &v : detail::smart_deref(set))
out << (i++ == 0 ? "" : ",") << detail::key_map_adaptor<element_t>::second(v);
44 changes: 44 additions & 0 deletions tests/SetTest.cpp
Original file line number Diff line number Diff line change
@@ -25,6 +25,50 @@ TEST_F(TApp, SimpleMaps) {
EXPECT_EQ(value, 1);
}

enum SimpleEnum { SE_one = 1, SE_two = 2 };

std::istream &operator>>(std::istream &in, SimpleEnum &e) {
int i;
in >> i;
e = static_cast<SimpleEnum>(i);
return in;
}

TEST_F(TApp, EnumMap) {
SimpleEnum value;
std::map<SimpleEnum, std::string> map = {{SE_one, "one"}, {SE_two, "two"}};
auto opt = app.add_option("-s,--set", value)->check(CLI::IsMember(map));
args = {"-s", "one"};
run();
EXPECT_EQ(1u, app.count("-s"));
EXPECT_EQ(1u, app.count("--set"));
EXPECT_EQ(1u, opt->count());
EXPECT_EQ(value, SE_one);
}

enum class SimpleEnumC { one = 1, two = 2 };

std::istream &operator>>(std::istream &in, SimpleEnumC &e) {
int i;
in >> i;
e = static_cast<SimpleEnumC>(i);
return in;
}

std::ostream &operator<<(std::ostream &in, const SimpleEnumC &e) { return in << static_cast<int>(e); }

TEST_F(TApp, EnumCMap) {
SimpleEnumC value;
std::map<SimpleEnumC, std::string> map = {{SimpleEnumC::one, "one"}, {SimpleEnumC::two, "two"}};
auto opt = app.add_option("-s,--set", value)->check(CLI::IsMember(map));
args = {"-s", "one"};
run();
EXPECT_EQ(1u, app.count("-s"));
EXPECT_EQ(1u, app.count("--set"));
EXPECT_EQ(1u, opt->count());
EXPECT_EQ(value, SimpleEnumC::one);
}

TEST_F(TApp, SimpleSets) {
std::string value;
auto opt = app.add_option("-s,--set", value)->check(CLI::IsMember{std::set<std::string>({"one", "two", "three"})});