From e6e41d43c68f3796d5de79cd0e36abf2e324e131 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 12 Mar 2024 10:42:37 +0100 Subject: [PATCH] Add a ArgumentParser::add_hidden_alias_for() method It is sometimes desirable to offer an alias for an argument, but without it appearing it in the usage. For example, to phase out a deprecated wording of an argument while not breaking backwards compatible. This can be done with the ``ArgumentParser::add_hidden_alias_for()` method. ```cpp argparse::ArgumentParser program("test"); auto &arg = program.add_argument("--suppress").flag(); program.add_hidden_alias_for(arg, "--supress"); // old misspelled alias ``` --- README.md | 15 +++++++++++++++ include/argparse/argparse.hpp | 15 +++++++++++++++ test/CMakeLists.txt | 1 + test/test_hidden_alias.cpp | 18 ++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 test/test_hidden_alias.cpp diff --git a/README.md b/README.md index 2fbb746a..edbb2cf0 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ * [Parent Parsers](#parent-parsers) * [Subcommands](#subcommands) * [Parse Known Args](#parse-known-args) + * [Hidden alias](#hidden-alias) * [ArgumentParser in bool Context](#argumentparser-in-bool-context) * [Custom Prefix Characters](#custom-prefix-characters) * [Custom Assignment Characters](#custom-assignment-characters) @@ -970,6 +971,20 @@ int main(int argc, char *argv[]) { } ``` +### Hidden alias + +It is sometimes desirable to offer an alias for an argument, but without it +appearing it in the usage. For example, to phase out a deprecated wording of +an argument while not breaking backwards compatible. This can be done with +the ``ArgumentParser::add_hidden_alias_for()` method. + +```cpp +argparse::ArgumentParser program("test"); + +auto &arg = program.add_argument("--suppress").flag(); +program.add_hidden_alias_for(arg, "--supress"); // old misspelled alias +``` + ### ArgumentParser in bool Context An `ArgumentParser` is `false` until it (or one of its subparsers) have extracted diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index c41cdb14..435e1dc7 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -1578,6 +1578,21 @@ class ArgumentParser { return *this; } + // Add a un-documented/hidden alias for an argument. + // Ideally we'd want this to be a method of Argument, but Argument + // does not own its owing ArgumentParser. + ArgumentParser &add_hidden_alias_for(Argument &arg, std::string_view alias) { + for (auto it = m_optional_arguments.begin(); + it != m_optional_arguments.end(); ++it) { + if (&(*it) == &arg) { + m_argument_map.insert_or_assign(std::string(alias), it); + return *this; + } + } + throw std::logic_error( + "Argument is not an optional argument of this parser"); + } + /* Getter for arguments and subparsers. * @throws std::logic_error in case of an invalid argument or subparser name */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 587eb824..8f3bbfc5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -55,6 +55,7 @@ file(GLOB ARGPARSE_TEST_SOURCES test_parse_known_args.cpp test_equals_form.cpp test_prefix_chars.cpp + test_hidden_alias.cpp ) set_source_files_properties(main.cpp PROPERTIES diff --git a/test/test_hidden_alias.cpp b/test/test_hidden_alias.cpp new file mode 100644 index 00000000..c67d89e5 --- /dev/null +++ b/test/test_hidden_alias.cpp @@ -0,0 +1,18 @@ +#ifdef WITH_MODULE +import argparse; +#else +#include +#endif +#include + +using doctest::test_suite; + +TEST_CASE("Test setting a hidden alias for an argument" * + test_suite("hidden_alias")) { + argparse::ArgumentParser program("test"); + auto &arg = program.add_argument("--suppress").flag(); + program.add_hidden_alias_for(arg, "--supress"); // old misspelled alias + + program.parse_args({"./test.exe", "--supress"}); + REQUIRE(program.get("--suppress") == true); +}