Skip to content

Commit

Permalink
Smarter shortcut syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Feb 16, 2019
1 parent 7981f7a commit 2f1925b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 20 deletions.
46 changes: 39 additions & 7 deletions include/CLI/Option.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,19 +330,51 @@ class Option : public OptionBase<Option> {
return this;
}

/// Allow a set to be quickly created
template <typename... Args> Option *set(Args &&... args) {
check(IsMember(std::forward<Args>(args)...));
/// Allow a set to be quickly created, strings followed optionally by functions.
///
/// Start: Will always have std::string
template <typename... Args> Option *choices(std::string value, Args &&... args) {
std::vector<std::string> values = {value};
return choices(values, std::forward<Args>(args)...);
}

private:
/// Final function called - no function
Option *choices(std::vector<std::string> values) {
check(IsMember(values));
return this;
}

/// Allow a set to be quickly created
template <typename... Args> Option *set(std::initializer_list<std::string> tmpset, Args &&... args) {
std::vector<std::string> myset(tmpset);
check(IsMember(myset, std::forward<Args>(args)...));
/// Final function called - function present
template <typename T,
enable_if_t<std::is_assignable<std::function<std::string(std::string)>, T>::value &&
!(std::is_same<T, const char *>::value || std::is_same<T, char *>::value),
detail::enabler> = detail::dummy>
Option *choices(std::vector<std::string> values, T fn) {
check(IsMember(values, fn));
return this;
}

/// Append a string
template <typename T,
typename... Args,
enable_if_t<std::is_assignable<std::string, T>::value, detail::enabler> = detail::dummy>
Option *choices(std::vector<std::string> values, T value, Args &&... args) {
values.push_back(std::move(value));
return choices(values, std::forward<Args>(args)...);
}

/// Combine functions
template <typename... Args>
Option *choices(std::vector<std::string> values,
std::function<std::string(std::string)> fn1,
std::function<std::string(std::string)> fn2,
Args &&... args) {
std::function<std::string(std::string)> fn = [fn1, fn2](std::string val) { return fn1(fn2(val)); };
return choices(values, fn, std::forward<Args>(args)...);
}

public:
/// Adds a user supplied function to run on each item passed in (communicate though lambda capture)
Option *each(std::function<void(std::string)> func) {
validators_.emplace_back([func](std::string &inout) {
Expand Down
14 changes: 4 additions & 10 deletions include/CLI/Validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,12 @@ class IsMember : public Validator {
explicit IsMember(std::initializer_list<std::string> values, Args &&... args)
: IsMember(std::vector<std::string>(values), std::forward<Args>(args)...) {}

/// This checks to see if an item is in a set: shared_pointer version. (Empty function)
template <typename T>
explicit IsMember(std::shared_ptr<T> set)
: IsMember(set, std::function<typename T::value_type(typename T::value_type)>{}) {}

/// This checks to see if an item is in a set: pointer version. (Empty function)
template <typename T, enable_if_t<std::is_pointer<T>::value, detail::enabler> = detail::dummy>
template <typename T, enable_if_t<is_copyable_ptr<T>::value, detail::enabler> = detail::dummy>
explicit IsMember(T set)
: IsMember(set,
std::function<typename std::remove_pointer<T>::type::value_type(
typename std::remove_pointer<T>::type::value_type)>{}) {}
std::function<typename std::pointer_traits<T>::element_type::value_type(
typename std::pointer_traits<T>::element_type::value_type)>{}) {}

/// This checks to see if an item is in a set: copy version. (Empty function)
template <typename T, enable_if_t<!is_copyable_ptr<T>::value, detail::enabler> = detail::dummy>
Expand All @@ -293,8 +288,7 @@ class IsMember : public Validator {
/// This checks to see if an item is in a set: pointer version.
template <typename T, typename F, enable_if_t<is_copyable_ptr<T>::value, detail::enabler> = detail::dummy>
explicit IsMember(T set, F filter_function) {
using set_t = typename std::pointer_traits<T>::element_type;
using item_t = typename set_t::value_type;
using item_t = typename std::pointer_traits<T>::element_type::value_type;

std::function<item_t(item_t)> filter_fn = filter_function;

Expand Down
35 changes: 32 additions & 3 deletions tests/SetTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,51 @@ TEST_F(TApp, SimiShortcutSets) {
EXPECT_EQ(value2, "One");
}

TEST_F(TApp, ShortcutSets) {
/*
//template <typename T, enable_if_t<std::is_assignable<std::function<std::string(std::string)>, T>::value &&
!(std::is_same<T, const char *>::value || std::is_same<T, char *>::value), detail::enabler> = detail::dummy>
//int check_compile(T fn) const {return 2;}
//template <typename T, enable_if_t<std::is_assignable<std::string, T>::value, detail::enabler> = detail::dummy>
//int check_compile(T str) const {return 3;}
std::string value;
int a = app.add_option("--set", value)->check_compile("this");
int b = app.add_option("--set2", value)->check_compile(CLI::ignore_case);
EXPECT_EQ(a, 3);
EXPECT_EQ(b, 2);
*/

TEST_F(TApp, ShortCutSets) {

std::string value;
auto opt = app.add_option("--set", value)->set({"one", "two", "three"});
auto opt = app.add_option("--set", value)->choices("one", "two", "three");
args = {"--set", "one"};
run();
EXPECT_EQ(1u, app.count("--set"));
EXPECT_EQ(1u, opt->count());
EXPECT_EQ(value, "one");

std::string value2;
auto opt2 = app.add_option("--set2", value2)->set({"One", "two", "three"}, CLI::ignore_case);
auto opt2 = app.add_option("--set2", value2)->choices("One", "two", "three", CLI::ignore_case);
args = {"--set2", "onE"};
run();
EXPECT_EQ(1u, app.count("--set2"));
EXPECT_EQ(1u, opt2->count());
EXPECT_EQ(value2, "One");

std::string value3;
auto opt3 =
app.add_option("--set3", value3)->choices("O_ne", "two", "three", CLI::ignore_case, CLI::ignore_underscore);
args = {"--set3", "onE"};
run();
EXPECT_EQ(1u, app.count("--set3"));
EXPECT_EQ(1u, opt3->count());
EXPECT_EQ(value3, "O_ne");
}

TEST_F(TApp, NumericalSets) {
Expand Down

0 comments on commit 2f1925b

Please sign in to comment.