mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-12 19:31: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>
|
||||
|
||||
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 {
|
||||
template <typename T> class copyable_atomic {
|
||||
public:
|
||||
@@ -72,6 +98,7 @@ namespace argument_parser {
|
||||
[[nodiscard]] virtual bool expects_parameter() const = 0;
|
||||
virtual void invoke() 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;
|
||||
};
|
||||
|
||||
@@ -92,8 +119,31 @@ namespace argument_parser {
|
||||
}
|
||||
|
||||
void invoke_with_parameter(const std::string ¶m) const override {
|
||||
T parsed_value = parsing_traits::parser_trait<T>::parse(param);
|
||||
invoke(parsed_value);
|
||||
bool parse_success = false;
|
||||
try {
|
||||
T parsed_value = parsing_traits::parser_trait<T>::parse(param);
|
||||
parse_success = true;
|
||||
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 {
|
||||
@@ -120,6 +170,10 @@ namespace argument_parser {
|
||||
invoke();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override {
|
||||
return {"", ""};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
|
||||
return std::make_unique<non_parametered_action>(handler);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#include <vector>
|
||||
|
||||
namespace argument_parser::v2 {
|
||||
namespace internal {
|
||||
static inline fake_parser fake_parser{};
|
||||
}
|
||||
|
||||
enum class add_argument_flags { ShortArgument, LongArgument, HelpText, Action, Required };
|
||||
|
||||
namespace flags {
|
||||
@@ -104,30 +100,6 @@ namespace argument_parser::v2 {
|
||||
}
|
||||
|
||||
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>
|
||||
void add_argument_impl(ArgsMap const &argument_pairs) {
|
||||
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||
@@ -174,8 +146,8 @@ namespace argument_parser::v2 {
|
||||
switch (suggested_add) {
|
||||
case candidate_type::typed_action:
|
||||
if (help_text.empty()) {
|
||||
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||
if constexpr (internal::sfinae::has_format_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 purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||
help_text = "Triggers action with " + std::string(purpose_hint) + " (" +
|
||||
@@ -190,8 +162,8 @@ namespace argument_parser::v2 {
|
||||
break;
|
||||
case candidate_type::store_other:
|
||||
if (help_text.empty()) {
|
||||
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||
if constexpr (internal::sfinae::has_format_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 purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||
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>
|
||||
#define ALLOW_DASH_FOR_WINDOWS 0
|
||||
|
||||
#include <argparse>
|
||||
#include <fstream>
|
||||
@@ -24,7 +23,7 @@ template <> struct argument_parser::parsing_traits::parser_trait<Point> {
|
||||
return {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> {
|
||||
@@ -178,11 +177,9 @@ int v2Examples() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
return v2Examples();
|
||||
|
||||
try {
|
||||
return v2Examples();
|
||||
} catch (std::exception const &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return -1;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
std::vector<std::pair<std::string, argument>> &found_arguments,
|
||||
std::optional<argument> const &found_help) {
|
||||
@@ -244,7 +255,9 @@ namespace argument_parser {
|
||||
}
|
||||
value.set_invoked(true);
|
||||
} 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";
|
||||
display_help(convention_types);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user