mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
chore: improve error generation. exit on missing required arg. remove redundant fake_parser.
This commit is contained in:
@@ -20,6 +20,32 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
|
namespace internal::sfinae {
|
||||||
|
template <typename T> struct has_format_hint {
|
||||||
|
private:
|
||||||
|
typedef char YesType[1];
|
||||||
|
typedef char NoType[2];
|
||||||
|
|
||||||
|
template <typename C> static YesType &test(decltype(&C::format_hint));
|
||||||
|
template <typename> static NoType &test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct has_purpose_hint {
|
||||||
|
private:
|
||||||
|
typedef char YesType[1];
|
||||||
|
typedef char NoType[2];
|
||||||
|
|
||||||
|
template <typename C> static YesType &test(decltype(&C::purpose_hint));
|
||||||
|
template <typename> static NoType &test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
||||||
|
};
|
||||||
|
} // namespace internal::sfinae
|
||||||
|
|
||||||
namespace internal::atomic {
|
namespace internal::atomic {
|
||||||
template <typename T> class copyable_atomic {
|
template <typename T> class copyable_atomic {
|
||||||
public:
|
public:
|
||||||
@@ -72,6 +98,7 @@ namespace argument_parser {
|
|||||||
[[nodiscard]] virtual bool expects_parameter() const = 0;
|
[[nodiscard]] virtual bool expects_parameter() const = 0;
|
||||||
virtual void invoke() const = 0;
|
virtual void invoke() const = 0;
|
||||||
virtual void invoke_with_parameter(const std::string ¶m) const = 0;
|
virtual void invoke_with_parameter(const std::string ¶m) const = 0;
|
||||||
|
[[nodiscard]] virtual std::pair<std::string, std::string> get_trait_hints() const = 0;
|
||||||
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
|
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,8 +119,31 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void invoke_with_parameter(const std::string ¶m) const override {
|
void invoke_with_parameter(const std::string ¶m) const override {
|
||||||
|
bool parse_success = false;
|
||||||
|
try {
|
||||||
T parsed_value = parsing_traits::parser_trait<T>::parse(param);
|
T parsed_value = parsing_traits::parser_trait<T>::parse(param);
|
||||||
|
parse_success = true;
|
||||||
invoke(parsed_value);
|
invoke(parsed_value);
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
if (!parse_success) {
|
||||||
|
auto [format_hint, purpose_hint] = get_trait_hints();
|
||||||
|
if (purpose_hint.empty())
|
||||||
|
purpose_hint = "value";
|
||||||
|
std::string error_text{"'" + param + "' is not a valid " + purpose_hint + " ${KEY}"};
|
||||||
|
if (!format_hint.empty())
|
||||||
|
error_text += "\nExpected format: " + format_hint;
|
||||||
|
throw std::runtime_error(error_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override {
|
||||||
|
if constexpr (internal::sfinae::has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||||
|
internal::sfinae::has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||||
|
return {parsing_traits::parser_trait<T>::format_hint, parsing_traits::parser_trait<T>::purpose_hint};
|
||||||
|
} else {
|
||||||
|
return {"", "value"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
|
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
|
||||||
@@ -120,6 +170,10 @@ namespace argument_parser {
|
|||||||
invoke();
|
invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override {
|
||||||
|
return {"", ""};
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
|
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
|
||||||
return std::make_unique<non_parametered_action>(handler);
|
return std::make_unique<non_parametered_action>(handler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace argument_parser::v2 {
|
namespace argument_parser::v2 {
|
||||||
namespace internal {
|
|
||||||
static inline fake_parser fake_parser{};
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class add_argument_flags { ShortArgument, LongArgument, HelpText, Action, Required };
|
enum class add_argument_flags { ShortArgument, LongArgument, HelpText, Action, Required };
|
||||||
|
|
||||||
namespace flags {
|
namespace flags {
|
||||||
@@ -104,30 +100,6 @@ namespace argument_parser::v2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T> struct has_format_hint {
|
|
||||||
private:
|
|
||||||
typedef char YesType[1];
|
|
||||||
typedef char NoType[2];
|
|
||||||
|
|
||||||
template <typename C> static YesType &test(decltype(&C::format_hint));
|
|
||||||
template <typename> static NoType &test(...);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> struct has_purpose_hint {
|
|
||||||
private:
|
|
||||||
typedef char YesType[1];
|
|
||||||
typedef char NoType[2];
|
|
||||||
|
|
||||||
template <typename C> static YesType &test(decltype(&C::purpose_hint));
|
|
||||||
template <typename> static NoType &test(...);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
|
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
|
||||||
void add_argument_impl(ArgsMap const &argument_pairs) {
|
void add_argument_impl(ArgsMap const &argument_pairs) {
|
||||||
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||||
@@ -174,8 +146,8 @@ namespace argument_parser::v2 {
|
|||||||
switch (suggested_add) {
|
switch (suggested_add) {
|
||||||
case candidate_type::typed_action:
|
case candidate_type::typed_action:
|
||||||
if (help_text.empty()) {
|
if (help_text.empty()) {
|
||||||
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
if constexpr (internal::sfinae::has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||||
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
internal::sfinae::has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||||
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
||||||
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||||
help_text = "Triggers action with " + std::string(purpose_hint) + " (" +
|
help_text = "Triggers action with " + std::string(purpose_hint) + " (" +
|
||||||
@@ -190,8 +162,8 @@ namespace argument_parser::v2 {
|
|||||||
break;
|
break;
|
||||||
case candidate_type::store_other:
|
case candidate_type::store_other:
|
||||||
if (help_text.empty()) {
|
if (help_text.empty()) {
|
||||||
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
if constexpr (internal::sfinae::has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||||
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
internal::sfinae::has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||||
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
||||||
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||||
help_text =
|
help_text =
|
||||||
|
|||||||
11
src/main.cpp
11
src/main.cpp
@@ -1,6 +1,5 @@
|
|||||||
#include "headers/parser/parsing_traits/traits.hpp"
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#define ALLOW_DASH_FOR_WINDOWS 0
|
|
||||||
|
|
||||||
#include <argparse>
|
#include <argparse>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -24,7 +23,7 @@ template <> struct argument_parser::parsing_traits::parser_trait<Point> {
|
|||||||
return {x, y};
|
return {x, y};
|
||||||
}
|
}
|
||||||
static constexpr argument_parser::parsing_traits::hint_type format_hint = "x,y";
|
static constexpr argument_parser::parsing_traits::hint_type format_hint = "x,y";
|
||||||
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "point coordinates";
|
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "coordinates";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct argument_parser::parsing_traits::parser_trait<std::regex> {
|
template <> struct argument_parser::parsing_traits::parser_trait<std::regex> {
|
||||||
@@ -178,11 +177,9 @@ int v2Examples() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
return v2Examples();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
return v2Examples();
|
||||||
} catch (std::exception const &e) {
|
} catch (std::exception const &e) {
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,6 +225,17 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string replace_var(std::string text, const std::string &var_name, const std::string &value) {
|
||||||
|
std::string placeholder = "${" + var_name + "}";
|
||||||
|
size_t pos = text.find(placeholder);
|
||||||
|
|
||||||
|
while (pos != std::string::npos) {
|
||||||
|
text.replace(pos, placeholder.length(), value);
|
||||||
|
pos = text.find(placeholder, pos + value.length());
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
void base_parser::invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
void base_parser::invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
||||||
std::vector<std::pair<std::string, argument>> &found_arguments,
|
std::vector<std::pair<std::string, argument>> &found_arguments,
|
||||||
std::optional<argument> const &found_help) {
|
std::optional<argument> const &found_help) {
|
||||||
@@ -244,7 +255,9 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
value.set_invoked(true);
|
value.set_invoked(true);
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
error_stream << "Argument " << key << " failed with: " << e.what() << "\n";
|
std::string err{e.what()};
|
||||||
|
err = replace_var(err, "KEY", "for " + key);
|
||||||
|
error_stream << "Error: " << err << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +380,7 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
std::cerr << "\n";
|
std::cerr << "\n";
|
||||||
display_help(convention_types);
|
display_help(convention_types);
|
||||||
|
std::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user