Commit 5f43f4cbfee5d92560ece7811a2a44c763f9fb73
Committed by
GitHub
1 parent
1b660d56
Fixes #245: Mention the option name when throwing on "no value" (#246)
* Fixes #245: * Added a new exception type: `option_has_no_value_exception`; throwing it when an option has no value we can cast with `as()`, instead of an `std::domain_error`. * The `OptionValue` type now holds a pointer to the long option name (in its corresponding key within ParseResults's `m_results` field.
Showing
2 changed files
with
20 additions
and
2 deletions
include/cxxopts.hpp
| ... | ... | @@ -443,6 +443,18 @@ namespace cxxopts |
| 443 | 443 | } |
| 444 | 444 | }; |
| 445 | 445 | |
| 446 | + class option_has_no_value_exception : public OptionException | |
| 447 | + { | |
| 448 | + public: | |
| 449 | + explicit option_has_no_value_exception(const std::string& option) | |
| 450 | + : OptionException( | |
| 451 | + option.empty() ? | |
| 452 | + ("Option " + LQUOTE + option + RQUOTE + " has no value") : | |
| 453 | + "Option has no value") | |
| 454 | + { | |
| 455 | + } | |
| 456 | + }; | |
| 457 | + | |
| 446 | 458 | class argument_incorrect_type : public OptionParseException |
| 447 | 459 | { |
| 448 | 460 | public: |
| ... | ... | @@ -1077,6 +1089,7 @@ namespace cxxopts |
| 1077 | 1089 | ensure_value(details); |
| 1078 | 1090 | ++m_count; |
| 1079 | 1091 | m_value->parse(text); |
| 1092 | + m_long_name = &details->long_name(); | |
| 1080 | 1093 | } |
| 1081 | 1094 | |
| 1082 | 1095 | void |
| ... | ... | @@ -1084,6 +1097,7 @@ namespace cxxopts |
| 1084 | 1097 | { |
| 1085 | 1098 | ensure_value(details); |
| 1086 | 1099 | m_default = true; |
| 1100 | + m_long_name = &details->long_name(); | |
| 1087 | 1101 | m_value->parse(); |
| 1088 | 1102 | } |
| 1089 | 1103 | |
| ... | ... | @@ -1105,7 +1119,8 @@ namespace cxxopts |
| 1105 | 1119 | as() const |
| 1106 | 1120 | { |
| 1107 | 1121 | if (m_value == nullptr) { |
| 1108 | - throw_or_mimic<std::domain_error>("No value"); | |
| 1122 | + throw_or_mimic<option_has_no_value_exception>( | |
| 1123 | + m_long_name == nullptr ? "" : *m_long_name); | |
| 1109 | 1124 | } |
| 1110 | 1125 | |
| 1111 | 1126 | #ifdef CXXOPTS_NO_RTTI |
| ... | ... | @@ -1125,6 +1140,9 @@ namespace cxxopts |
| 1125 | 1140 | } |
| 1126 | 1141 | } |
| 1127 | 1142 | |
| 1143 | + const std::string* m_long_name = nullptr; | |
| 1144 | + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, | |
| 1145 | + // where the key has the string we point to. | |
| 1128 | 1146 | std::shared_ptr<Value> m_value; |
| 1129 | 1147 | size_t m_count = 0; |
| 1130 | 1148 | bool m_default = false; | ... | ... |
test/options.cpp
| ... | ... | @@ -94,7 +94,7 @@ TEST_CASE("Basic options", "[options]") |
| 94 | 94 | CHECK(arguments[2].key() == "value"); |
| 95 | 95 | CHECK(arguments[3].key() == "av"); |
| 96 | 96 | |
| 97 | - CHECK_THROWS_AS(result["nothing"].as<std::string>(), std::domain_error&); | |
| 97 | + CHECK_THROWS_AS(result["nothing"].as<std::string>(), cxxopts::option_has_no_value_exception&); | |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | 100 | TEST_CASE("Short options", "[options]") | ... | ... |