Stop sharing argument values with parent parsers

See also: p-ranav/argparse#50
This commit is contained in:
Zhihao Yuan 2019-11-16 03:32:38 -06:00
parent 2208ec5b2d
commit 3f949fc3f1
No known key found for this signature in database
GPG Key ID: A2E474BDAA37E11C
3 changed files with 35 additions and 34 deletions

View File

@ -349,7 +349,7 @@ Here's what's happening:
### Parent Parsers ### 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 shared 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: 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:
```cpp ```cpp
argparse::ArgumentParser parent_parser("main"); argparse::ArgumentParser parent_parser("main");

View File

@ -35,7 +35,6 @@ SOFTWARE.
#include <iterator> #include <iterator>
#include <list> #include <list>
#include <map> #include <map>
#include <memory>
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
@ -383,37 +382,30 @@ public:
// Parameter packing // Parameter packing
// Call add_argument with variadic number of string arguments // Call add_argument with variadic number of string arguments
template <typename... Targs> Argument &add_argument(Targs... Fargs) { template <typename... Targs> Argument &add_argument(Targs... Fargs) {
std::shared_ptr<Argument> tArgument = auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments),
std::make_shared<Argument>(std::move(Fargs)...); std::move(Fargs)...);
if (tArgument->mIsOptional) if (!tArgument->mIsOptional)
mOptionalArguments.emplace_back(tArgument); mPositionalArguments.splice(cend(mPositionalArguments),
else mOptionalArguments, tArgument);
mPositionalArguments.emplace_back(tArgument);
for (const auto &mName : tArgument->mNames) { index_argument(tArgument);
mArgumentMap.insert_or_assign(mName, tArgument);
}
return *tArgument; return *tArgument;
} }
// Parameter packed add_parents method // Parameter packed add_parents method
// Accepts a variadic number of ArgumentParser objects // Accepts a variadic number of ArgumentParser objects
template <typename... Targs> void add_parents(Targs... Fargs) { template <typename... Targs> void add_parents(const Targs &... Fargs) {
const auto tNewParentParsers = {Fargs...}; for (auto &tParentParser : {Fargs...}) {
for (const auto &tParentParser : tNewParentParsers) { for (auto &tArgument : tParentParser.mPositionalArguments) {
const auto &tPositionalArguments = tParentParser.mPositionalArguments; auto it =
std::copy(std::begin(tPositionalArguments), mPositionalArguments.insert(cend(mPositionalArguments), tArgument);
std::end(tPositionalArguments), index_argument(it);
std::back_inserter(mPositionalArguments)); }
for (auto &tArgument : tParentParser.mOptionalArguments) {
const auto &tOptionalArguments = tParentParser.mOptionalArguments; auto it =
std::copy(std::begin(tOptionalArguments), std::end(tOptionalArguments), mOptionalArguments.insert(cend(mOptionalArguments), tArgument);
std::back_inserter(mOptionalArguments)); index_argument(it);
const auto &tArgumentMap = tParentParser.mArgumentMap;
for (const auto &[tKey, tValue] : tArgumentMap) {
mArgumentMap.insert_or_assign(tKey, tValue);
} }
} }
} }
@ -471,7 +463,7 @@ public:
size_t tLongestArgumentLength = parser.get_length_of_longest_argument(); size_t tLongestArgumentLength = parser.get_length_of_longest_argument();
for (const auto &argument : parser.mPositionalArguments) { for (const auto &argument : parser.mPositionalArguments) {
stream << argument->mNames.front() << " "; stream << argument.mNames.front() << " ";
} }
stream << "\n\n"; stream << "\n\n";
@ -480,7 +472,7 @@ public:
for (const auto &mPositionalArgument : parser.mPositionalArguments) { for (const auto &mPositionalArgument : parser.mPositionalArguments) {
stream.width(tLongestArgumentLength); stream.width(tLongestArgumentLength);
stream << *mPositionalArgument; stream << mPositionalArgument;
} }
if (!parser.mOptionalArguments.empty()) if (!parser.mOptionalArguments.empty())
@ -489,7 +481,7 @@ public:
for (const auto &mOptionalArgument : parser.mOptionalArguments) { for (const auto &mOptionalArgument : parser.mOptionalArguments) {
stream.width(tLongestArgumentLength); stream.width(tLongestArgumentLength);
stream << *mOptionalArgument; stream << mOptionalArgument;
} }
} }
@ -533,7 +525,7 @@ private:
throw std::runtime_error( throw std::runtime_error(
"Maximum number of positional arguments exceeded"); "Maximum number of positional arguments exceeded");
} }
auto tArgument = *(positionalArgumentIt++); auto tArgument = positionalArgumentIt++;
it = tArgument->consume(it, end); it = tArgument->consume(it, end);
} else if (auto tIterator = mArgumentMap.find(tCurrentArgument); } else if (auto tIterator = mArgumentMap.find(tCurrentArgument);
tIterator != mArgumentMap.end()) { tIterator != mArgumentMap.end()) {
@ -585,10 +577,17 @@ private:
std::end(argumentLengths)); std::end(argumentLengths));
} }
using list_iterator = std::list<Argument>::iterator;
void index_argument(list_iterator argIt) {
for (auto &mName : std::as_const(argIt->mNames))
mArgumentMap.insert_or_assign(mName, argIt);
}
std::string mProgramName; std::string mProgramName;
std::vector<std::shared_ptr<Argument>> mPositionalArguments; std::list<Argument> mPositionalArguments;
std::vector<std::shared_ptr<Argument>> mOptionalArguments; std::list<Argument> mOptionalArguments;
std::map<std::string, std::shared_ptr<Argument>> mArgumentMap; std::map<std::string, list_iterator, std::less<>> mArgumentMap;
}; };
} // namespace argparse } // namespace argparse

View File

@ -12,6 +12,7 @@ TEST_CASE("Add parent parsers", "[parent_parsers]") {
child_parser.add_parents(parent_parser); child_parser.add_parents(parent_parser);
child_parser.parse_args({ "./main", "--verbose"}); child_parser.parse_args({ "./main", "--verbose"});
REQUIRE(child_parser["--verbose"] == true); REQUIRE(child_parser["--verbose"] == true);
REQUIRE(parent_parser["--verbose"] == false);
} }
TEST_CASE("Add parent to multiple parent parsers", "[parent_parsers]") { TEST_CASE("Add parent to multiple parent parsers", "[parent_parsers]") {
@ -26,6 +27,7 @@ TEST_CASE("Add parent to multiple parent parsers", "[parent_parsers]") {
foo_parser.parse_args({ "./main", "--parent", "2", "XXX" }); foo_parser.parse_args({ "./main", "--parent", "2", "XXX" });
REQUIRE(foo_parser["--parent"] == 2); REQUIRE(foo_parser["--parent"] == 2);
REQUIRE(foo_parser["foo"] == std::string("XXX")); REQUIRE(foo_parser["foo"] == std::string("XXX"));
REQUIRE(parent_parser["--parent"] == 0);
argparse::ArgumentParser bar_parser("bar"); argparse::ArgumentParser bar_parser("bar");
bar_parser.add_argument("--bar"); bar_parser.add_argument("--bar");