mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-03 14:44:40 +00:00
Merge pull request #254 from skrobinson/fix-maintenance
Various maintenance tasks
This commit is contained in:
commit
e516556733
@ -7,9 +7,8 @@ project(argparse
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
option(ARGPARSE_INSTALL ON)
|
||||
option(ARGPARSE_BUILD_TESTS OFF)
|
||||
option(ARGPARSE_LONG_VERSION_ARG_ONLY OFF)
|
||||
option(ARGPARSE_INSTALL "Include an install target" ON)
|
||||
option(ARGPARSE_BUILD_TESTS "Build tests" OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
@ -17,11 +16,6 @@ include(CMakePackageConfigHelpers)
|
||||
add_library(argparse INTERFACE)
|
||||
add_library(argparse::argparse ALIAS argparse)
|
||||
|
||||
|
||||
if (ARGPARSE_LONG_VERSION_ARG_ONLY)
|
||||
target_compile_definitions(argparse INTERFACE ARGPARSE_LONG_VERSION_ARG_ONLY=true)
|
||||
endif ()
|
||||
|
||||
target_compile_features(argparse INTERFACE cxx_std_17)
|
||||
target_include_directories(argparse INTERFACE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
|
29
README.md
29
README.md
@ -687,25 +687,30 @@ main
|
||||
|
||||
### Parent Parsers
|
||||
|
||||
Sometimes, several parsers share a common set of arguments. Rather than repeating the definitions of these arguments, a single parser with all the common arguments can be added as a parent to another ArgumentParser instance. The ```.add_parents``` method takes a list of ArgumentParser objects, collects all the positional and optional actions from them, and adds these actions to the ArgumentParser object being constructed:
|
||||
A parser may use arguments that could be used by other parsers.
|
||||
|
||||
These shared arguments can be added to a parser which is then used as a "parent" for parsers which also need those arguments. One or more parent parsers may be added to a parser with `.add_parents`. The positional and optional arguments in each parent is added to the child parser.
|
||||
|
||||
```cpp
|
||||
argparse::ArgumentParser parent_parser("main");
|
||||
parent_parser.add_argument("--parent")
|
||||
argparse::ArgumentParser surface_parser("surface", 1.0, argparse::default_arguments::none);
|
||||
parent_parser.add_argument("--area")
|
||||
.default_value(0)
|
||||
.scan<'i', int>();
|
||||
|
||||
argparse::ArgumentParser foo_parser("foo");
|
||||
foo_parser.add_argument("foo");
|
||||
foo_parser.add_parents(parent_parser);
|
||||
foo_parser.parse_args({ "./main", "--parent", "2", "XXX" }); // parent = 2, foo = XXX
|
||||
argparse::ArgumentParser floor_parser("floor");
|
||||
floor_parser.add_argument("tile_size").scan<'i', int>();
|
||||
floor_parser.add_parents(surface_parser);
|
||||
floor_parser.parse_args({ "./main", "--area", "200", "12" }); // --area = 200, tile_size = 12
|
||||
|
||||
argparse::ArgumentParser bar_parser("bar");
|
||||
bar_parser.add_argument("--bar");
|
||||
bar_parser.parse_args({ "./main", "--bar", "YYY" }); // bar = YYY
|
||||
argparse::ArgumentParser ceiling_parser("ceiling");
|
||||
ceiling_parser.add_argument("--color");
|
||||
ceiling_parser.add_parents(surface_parser);
|
||||
ceiling_parser.parse_args({ "./main", "--color", "gray" }); // --area = 0, --color = "gray"
|
||||
```
|
||||
|
||||
Note You must fully initialize the parsers before passing them via ```.add_parents```. If you change the parent parsers after the child parser, those changes will not be reflected in the child.
|
||||
Changes made to parents after they are added to a parser are not reflected in any child parsers. Completely initialize parent parsers before adding them to a parser.
|
||||
|
||||
Each parser will have the standard set of default arguments. Disable the default arguments in parent parsers to avoid duplicate help output.
|
||||
|
||||
### Subcommands
|
||||
|
||||
@ -1157,7 +1162,7 @@ sudo make install
|
||||
| :------------------- | :--------------- | :----------------- |
|
||||
| GCC >= 8.3.0 | libstdc++ | Ubuntu 18.04 |
|
||||
| Clang >= 7.0.0 | libc++ | Xcode 10.2 |
|
||||
| MSVC >= 14.16 | Microsoft STL | Visual Studio 2017 |
|
||||
| MSVC >= 16.8 | Microsoft STL | Visual Studio 2019 |
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.
|
||||
|
@ -376,7 +376,8 @@ class Argument {
|
||||
explicit Argument(std::string_view prefix_chars,
|
||||
std::array<std::string_view, N> &&a,
|
||||
std::index_sequence<I...> /*unused*/)
|
||||
: m_is_optional((is_optional(a[I], prefix_chars) || ...)),
|
||||
: m_accepts_optional_like_value(false),
|
||||
m_is_optional((is_optional(a[I], prefix_chars) || ...)),
|
||||
m_is_required(false), m_is_repeatable(false), m_is_used(false),
|
||||
m_prefix_chars(prefix_chars) {
|
||||
((void)m_names.emplace_back(a[I]), ...);
|
||||
@ -702,10 +703,13 @@ public:
|
||||
if constexpr (!details::IsContainer<T>) {
|
||||
return get<T>() == rhs;
|
||||
} else {
|
||||
using ValueType = typename T::value_type;
|
||||
auto lhs = get<T>();
|
||||
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
|
||||
std::end(rhs),
|
||||
[](const auto &a, const auto &b) { return a == b; });
|
||||
[](const auto &a, const auto &b) {
|
||||
return std::any_cast<const ValueType &>(a) == b;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,18 +976,16 @@ private:
|
||||
* Get argument value given a type
|
||||
* @throws std::logic_error in case of incompatible types
|
||||
*/
|
||||
template <typename T>
|
||||
auto get() const
|
||||
-> std::conditional_t<details::IsContainer<T>, T, const T &> {
|
||||
template <typename T> T get() const {
|
||||
if (!m_values.empty()) {
|
||||
if constexpr (details::IsContainer<T>) {
|
||||
return any_cast_container<T>(m_values);
|
||||
} else {
|
||||
return *std::any_cast<T>(&m_values.front());
|
||||
return std::any_cast<T>(m_values.front());
|
||||
}
|
||||
}
|
||||
if (m_default_value.has_value()) {
|
||||
return *std::any_cast<T>(&m_default_value);
|
||||
return std::any_cast<T>(m_default_value);
|
||||
}
|
||||
if constexpr (details::IsContainer<T>) {
|
||||
if (!m_accepts_optional_like_value) {
|
||||
@ -1019,7 +1021,7 @@ private:
|
||||
T result;
|
||||
std::transform(
|
||||
std::begin(operand), std::end(operand), std::back_inserter(result),
|
||||
[](const auto &value) { return *std::any_cast<ValueType>(&value); });
|
||||
[](const auto &value) { return std::any_cast<ValueType>(value); });
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1037,11 +1039,12 @@ private:
|
||||
[](const std::string &value) { return value; }};
|
||||
std::vector<std::any> m_values;
|
||||
NArgsRange m_num_args_range{1, 1};
|
||||
bool m_accepts_optional_like_value = false;
|
||||
bool m_is_optional : true;
|
||||
bool m_is_required : true;
|
||||
bool m_is_repeatable : true;
|
||||
bool m_is_used : true; // True if the optional argument is used by user
|
||||
// Bit field of bool values. Set default value in ctor.
|
||||
bool m_accepts_optional_like_value : 1;
|
||||
bool m_is_optional : 1;
|
||||
bool m_is_required : 1;
|
||||
bool m_is_repeatable : 1;
|
||||
bool m_is_used : 1;
|
||||
std::string_view m_prefix_chars; // ArgumentParser has the prefix_chars
|
||||
};
|
||||
|
||||
@ -1249,9 +1252,7 @@ public:
|
||||
* @throws std::logic_error if the option has no value
|
||||
* @throws std::bad_any_cast if the option is not of type T
|
||||
*/
|
||||
template <typename T = std::string>
|
||||
auto get(std::string_view arg_name) const
|
||||
-> std::conditional_t<details::IsContainer<T>, T, const T &> {
|
||||
template <typename T = std::string> T get(std::string_view arg_name) const {
|
||||
if (!m_is_parsed) {
|
||||
throw std::logic_error("Nothing parsed, no arguments are available.");
|
||||
}
|
||||
|
@ -33,3 +33,10 @@ TEST_CASE("Implicit argument" * test_suite("ArgumentParser::get")) {
|
||||
REQUIRE_THROWS_WITH_AS(program.get("--stuff"),
|
||||
"No value provided for '--stuff'.", std::logic_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Mismatched type for argument" * test_suite("ArgumentParser::get")) {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("-s", "--stuff"); // as default type, a std::string
|
||||
REQUIRE_NOTHROW(program.parse_args({"test", "-s", "321"}));
|
||||
REQUIRE_THROWS_AS(program.get<int>("--stuff"), std::bad_any_cast);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user