Skip to content

Commit

Permalink
Adding example, better Val combs, and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Feb 19, 2019
1 parent 008a163 commit 5d4474d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 15 deletions.
2 changes: 1 addition & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
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 };
Expand All @@ -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
Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
44 changes: 44 additions & 0 deletions tests/SetTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"})});
Expand Down

0 comments on commit 5d4474d

Please sign in to comment.