Allow actions that return void

closes: p-ranav/argparse#39
This commit is contained in:
Zhihao Yuan 2019-11-13 12:54:07 -06:00
parent bda0866320
commit dc227448f6
No known key found for this signature in database
GPG Key ID: 0BC0BC626A0C5A8E
2 changed files with 53 additions and 7 deletions

View File

@ -41,6 +41,7 @@ SOFTWARE.
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <variant>
#include <vector> #include <vector>
namespace argparse { namespace argparse {
@ -114,8 +115,14 @@ public:
return *this; return *this;
} }
Argument &action(std::function<std::any(const std::string &)> aAction) { template <class F>
mAction = std::move(aAction); auto action(F &&aAction)
-> std::enable_if_t<std::is_invocable_v<F, std::string const>,
Argument &> {
if constexpr (std::is_void_v<std::invoke_result_t<F, std::string const>>)
mAction.emplace<void_action>(std::forward<F>(aAction));
else
mAction.emplace<valued_action>(std::forward<F>(aAction));
return *this; return *this;
} }
@ -139,7 +146,21 @@ public:
if (std::any_of(start, end, Argument::is_optional)) { if (std::any_of(start, end, Argument::is_optional)) {
throw std::runtime_error("optional argument in parameter sequence"); throw std::runtime_error("optional argument in parameter sequence");
} }
std::transform(start, end, std::back_inserter(mValues), mAction); struct action_apply {
void operator()(valued_action &f) {
std::transform(start, end, std::back_inserter(self.mValues), f);
}
void operator()(void_action &f) {
std::for_each(start, end, f);
if (!self.mDefaultValue.has_value())
self.mValues.resize(self.mNumArgs);
}
Iterator start, end;
Argument &self;
};
std::visit(action_apply{start, end, *this}, mAction);
return end; return end;
} else if (mDefaultValue.has_value()) { } else if (mDefaultValue.has_value()) {
return start; return start;
@ -306,8 +327,11 @@ private:
std::string mHelp; std::string mHelp;
std::any mDefaultValue; std::any mDefaultValue;
std::any mImplicitValue; std::any mImplicitValue;
std::function<std::any(const std::string &)> mAction = using valued_action = std::function<std::any(const std::string &)>;
[](const std::string &aValue) { return aValue; }; using void_action = std::function<void(const std::string &)>;
std::variant<valued_action, void_action> mAction{
std::in_place_type<valued_action>,
[](const std::string &aValue) { return aValue; }};
std::vector<std::any> mValues; std::vector<std::any> mValues;
std::vector<std::string> mRawValues; std::vector<std::string> mRawValues;
size_t mNumArgs = 1; size_t mNumArgs = 1;

View File

@ -2,7 +2,7 @@
#include <catch.hpp> #include <catch.hpp>
#include <argparse.hpp> #include <argparse.hpp>
TEST_CASE("Users can use defaul value inside actions", "[actions]") { TEST_CASE("Users can use default value inside actions", "[actions]") {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input") program.add_argument("input")
.default_value("bar") .default_value("bar")
@ -17,3 +17,25 @@ TEST_CASE("Users can use defaul value inside actions", "[actions]") {
program.parse_args({ "test", "fez" }); program.parse_args({ "test", "fez" });
REQUIRE(program.get("input") == "bar"); REQUIRE(program.get("input") == "bar");
} }
TEST_CASE("Users can add actions that return nothing", "[actions]") {
argparse::ArgumentParser program("test");
bool pressed = false;
auto &arg = program.add_argument("button").action(
[&](const std::string &) mutable { pressed = true; });
REQUIRE_FALSE(pressed);
SECTION("action performed") {
program.parse_args({"test", "ignored"});
REQUIRE(pressed);
}
SECTION("action performed and nothing overrides the default value") {
arg.default_value(42);
program.parse_args({"test", "ignored"});
REQUIRE(pressed);
REQUIRE(program.get<int>("button") == 42);
}
}