mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 07:04:39 +00:00
commit
5d1e80a7d0
@ -91,9 +91,11 @@ PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
RawStringFormats:
|
||||
- Delimiter: pb
|
||||
Language: TextProto
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- 'pb'
|
||||
- 'proto'
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
|
@ -40,6 +40,7 @@ SOFTWARE.
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
@ -73,7 +74,23 @@ using enable_if_container = std::enable_if_t<is_container_v<T>, T>;
|
||||
|
||||
template <typename T>
|
||||
using enable_if_not_container = std::enable_if_t<!is_container_v<T>, T>;
|
||||
} // namespace
|
||||
|
||||
template <class F, class Tuple, class Extra, size_t... I>
|
||||
constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,
|
||||
std::index_sequence<I...>) {
|
||||
return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...,
|
||||
std::forward<Extra>(x));
|
||||
}
|
||||
|
||||
template <class F, class Tuple, class Extra>
|
||||
constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) {
|
||||
return details::apply_plus_one_impl(
|
||||
std::forward<F>(f), std::forward<Tuple>(t), std::forward<Extra>(x),
|
||||
std::make_index_sequence<
|
||||
std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
class ArgumentParser;
|
||||
|
||||
@ -115,14 +132,22 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto action(F &&aAction)
|
||||
-> std::enable_if_t<std::is_invocable_v<F, std::string const>,
|
||||
template <class F, class... Args>
|
||||
auto action(F &&aAction, Args &&... aBound)
|
||||
-> std::enable_if_t<std::is_invocable_v<F, Args..., 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));
|
||||
using action_type = std::conditional_t<
|
||||
std::is_void_v<std::invoke_result_t<F, Args..., std::string const>>,
|
||||
void_action, valued_action>;
|
||||
if constexpr (sizeof...(Args) == 0)
|
||||
mAction.emplace<action_type>(std::forward<F>(aAction));
|
||||
else
|
||||
mAction.emplace<valued_action>(std::forward<F>(aAction));
|
||||
mAction.emplace<action_type>(
|
||||
[f = std::forward<F>(aAction),
|
||||
tup = std::make_tuple(std::forward<Args>(aBound)...)](
|
||||
std::string const &opt) mutable {
|
||||
return details::apply_plus_one(f, tup, opt);
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <catch.hpp>
|
||||
#include <argparse.hpp>
|
||||
#include <string_view>
|
||||
|
||||
TEST_CASE("Users can use default value inside actions", "[actions]") {
|
||||
argparse::ArgumentParser program("test");
|
||||
@ -39,3 +40,82 @@ TEST_CASE("Users can add actions that return nothing", "[actions]") {
|
||||
REQUIRE(program.get<int>("button") == 42);
|
||||
}
|
||||
}
|
||||
|
||||
class Image {
|
||||
public:
|
||||
int w = 0, h = 0;
|
||||
|
||||
void resize(std::string_view geometry) {
|
||||
std::stringstream s;
|
||||
s << geometry;
|
||||
s >> w;
|
||||
s.ignore();
|
||||
s >> h;
|
||||
}
|
||||
|
||||
static auto create(int w, int h, std::string_view format) -> Image {
|
||||
auto factor = [=] {
|
||||
if (format == "720p")
|
||||
return std::min(1280. / w, 720. / h);
|
||||
else if (format == "1080p")
|
||||
return std::min(1920. / w, 1080. / h);
|
||||
else
|
||||
return 1.;
|
||||
}();
|
||||
|
||||
return {static_cast<int>(w * factor), static_cast<int>(h * factor)};
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Users can bind arguments to actions", "[actions]") {
|
||||
argparse::ArgumentParser program("test");
|
||||
|
||||
GIVEN("an default initialized object bounded by reference") {
|
||||
Image img;
|
||||
program.add_argument("--size").action(&Image::resize, std::ref(img));
|
||||
|
||||
WHEN("provided no command-line arguments") {
|
||||
program.parse_args({"test"});
|
||||
|
||||
THEN("the object is not updated") {
|
||||
REQUIRE(img.w == 0);
|
||||
REQUIRE(img.h == 0);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("provided command-line arguments") {
|
||||
program.parse_args({"test", "--size", "320x98"});
|
||||
|
||||
THEN("the object is updated accordingly") {
|
||||
REQUIRE(img.w == 320);
|
||||
REQUIRE(img.h == 98);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("a command-line option waiting for the last argument in its action") {
|
||||
program.add_argument("format").action(Image::create, 400, 300);
|
||||
|
||||
WHEN("provided such an argument") {
|
||||
program.parse_args({"test", "720p"});
|
||||
|
||||
THEN("the option object is created as if providing all arguments") {
|
||||
auto img = program.get<Image>("format");
|
||||
|
||||
REQUIRE(img.w == 960);
|
||||
REQUIRE(img.h == 720);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("provided a different argument") {
|
||||
program.parse_args({"test", "1080p"});
|
||||
|
||||
THEN("a different option object is created") {
|
||||
auto img = program.get<Image>("format");
|
||||
|
||||
REQUIRE(img.w == 1440);
|
||||
REQUIRE(img.h == 1080);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user