Commit f7cf890543693e5cb8653f61ad8910861e2a1223
1 parent
081bb93b
Adding new style enums too
Showing
2 changed files
with
120 additions
and
13 deletions
include/CLI/App.hpp
| @@ -213,13 +213,14 @@ class App { | @@ -213,13 +213,14 @@ class App { | ||
| 213 | } else | 213 | } else |
| 214 | throw OptionAlreadyAdded(myopt.get_name()); | 214 | throw OptionAlreadyAdded(myopt.get_name()); |
| 215 | } | 215 | } |
| 216 | + | ||
| 217 | + | ||
| 216 | 218 | ||
| 217 | - /// Add option for non-vectors | 219 | + /// Add option for non-vectors (duplicate copy needed without defaulted to avoid `iostream << value`) |
| 218 | template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> | 220 | template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> |
| 219 | Option *add_option(std::string name, | 221 | Option *add_option(std::string name, |
| 220 | T &variable, ///< The variable to set | 222 | T &variable, ///< The variable to set |
| 221 | - std::string description = "", | ||
| 222 | - bool defaulted = false) { | 223 | + std::string description = "") { |
| 223 | 224 | ||
| 224 | CLI::callback_t fun = [&variable](CLI::results_t res) { | 225 | CLI::callback_t fun = [&variable](CLI::results_t res) { |
| 225 | if(res.size() != 1) | 226 | if(res.size() != 1) |
| @@ -227,6 +228,24 @@ class App { | @@ -227,6 +228,24 @@ class App { | ||
| 227 | return detail::lexical_cast(res[0], variable); | 228 | return detail::lexical_cast(res[0], variable); |
| 228 | }; | 229 | }; |
| 229 | 230 | ||
| 231 | + Option *opt = add_option(name, fun, description, false); | ||
| 232 | + opt->set_custom_option(detail::type_name<T>()); | ||
| 233 | + return opt; | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + /// Add option for non-vectors with a default print | ||
| 237 | + template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> | ||
| 238 | + Option *add_option(std::string name, | ||
| 239 | + T &variable, ///< The variable to set | ||
| 240 | + std::string description, | ||
| 241 | + bool defaulted) { | ||
| 242 | + | ||
| 243 | + CLI::callback_t fun = [&variable](CLI::results_t res) { | ||
| 244 | + if(res.size() != 1) | ||
| 245 | + return false; | ||
| 246 | + return detail::lexical_cast(res[0], variable); | ||
| 247 | + }; | ||
| 248 | + | ||
| 230 | Option *opt = add_option(name, fun, description, defaulted); | 249 | Option *opt = add_option(name, fun, description, defaulted); |
| 231 | opt->set_custom_option(detail::type_name<T>()); | 250 | opt->set_custom_option(detail::type_name<T>()); |
| 232 | if(defaulted) { | 251 | if(defaulted) { |
| @@ -236,13 +255,34 @@ class App { | @@ -236,13 +255,34 @@ class App { | ||
| 236 | } | 255 | } |
| 237 | return opt; | 256 | return opt; |
| 238 | } | 257 | } |
| 239 | - | 258 | + |
| 259 | + /// Add option for vectors (no default) | ||
| 260 | + template <typename T> | ||
| 261 | + Option *add_option(std::string name, | ||
| 262 | + std::vector<T> &variable, ///< The variable vector to set | ||
| 263 | + std::string description = "") { | ||
| 264 | + | ||
| 265 | + CLI::callback_t fun = [&variable](CLI::results_t res) { | ||
| 266 | + bool retval = true; | ||
| 267 | + variable.clear(); | ||
| 268 | + for(const auto &a : res) { | ||
| 269 | + variable.emplace_back(); | ||
| 270 | + retval &= detail::lexical_cast(a, variable.back()); | ||
| 271 | + } | ||
| 272 | + return variable.size() > 0 && retval; | ||
| 273 | + }; | ||
| 274 | + | ||
| 275 | + Option *opt = add_option(name, fun, description, false); | ||
| 276 | + opt->set_custom_option(detail::type_name<T>(), -1, true); | ||
| 277 | + return opt; | ||
| 278 | + } | ||
| 279 | + | ||
| 240 | /// Add option for vectors | 280 | /// Add option for vectors |
| 241 | template <typename T> | 281 | template <typename T> |
| 242 | Option *add_option(std::string name, | 282 | Option *add_option(std::string name, |
| 243 | std::vector<T> &variable, ///< The variable vector to set | 283 | std::vector<T> &variable, ///< The variable vector to set |
| 244 | - std::string description = "", | ||
| 245 | - bool defaulted = false) { | 284 | + std::string description, |
| 285 | + bool defaulted) { | ||
| 246 | 286 | ||
| 247 | CLI::callback_t fun = [&variable](CLI::results_t res) { | 287 | CLI::callback_t fun = [&variable](CLI::results_t res) { |
| 248 | bool retval = true; | 288 | bool retval = true; |
| @@ -311,13 +351,12 @@ class App { | @@ -311,13 +351,12 @@ class App { | ||
| 311 | return opt; | 351 | return opt; |
| 312 | } | 352 | } |
| 313 | 353 | ||
| 314 | - /// Add set of options | 354 | + /// Add set of options (No default) |
| 315 | template <typename T> | 355 | template <typename T> |
| 316 | Option *add_set(std::string name, | 356 | Option *add_set(std::string name, |
| 317 | T &member, ///< The selected member of the set | 357 | T &member, ///< The selected member of the set |
| 318 | std::set<T> options, ///< The set of posibilities | 358 | std::set<T> options, ///< The set of posibilities |
| 319 | - std::string description = "", | ||
| 320 | - bool defaulted = false) { | 359 | + std::string description = "") { |
| 321 | 360 | ||
| 322 | CLI::callback_t fun = [&member, options](CLI::results_t res) { | 361 | CLI::callback_t fun = [&member, options](CLI::results_t res) { |
| 323 | if(res.size() != 1) { | 362 | if(res.size() != 1) { |
| @@ -329,6 +368,31 @@ class App { | @@ -329,6 +368,31 @@ class App { | ||
| 329 | return std::find(std::begin(options), std::end(options), member) != std::end(options); | 368 | return std::find(std::begin(options), std::end(options), member) != std::end(options); |
| 330 | }; | 369 | }; |
| 331 | 370 | ||
| 371 | + Option *opt = add_option(name, fun, description, false); | ||
| 372 | + std::string typeval = detail::type_name<T>(); | ||
| 373 | + typeval += " in {" + detail::join(options) + "}"; | ||
| 374 | + opt->set_custom_option(typeval); | ||
| 375 | + return opt; | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + /// Add set of options | ||
| 379 | + template <typename T> | ||
| 380 | + Option *add_set(std::string name, | ||
| 381 | + T &member, ///< The selected member of the set | ||
| 382 | + std::set<T> options, ///< The set of posibilities | ||
| 383 | + std::string description, | ||
| 384 | + bool defaulted) { | ||
| 385 | + | ||
| 386 | + CLI::callback_t fun = [&member, options](CLI::results_t res) { | ||
| 387 | + if(res.size() != 1) { | ||
| 388 | + return false; | ||
| 389 | + } | ||
| 390 | + bool retval = detail::lexical_cast(res[0], member); | ||
| 391 | + if(!retval) | ||
| 392 | + return false; | ||
| 393 | + return std::find(std::begin(options), std::end(options), member) != std::end(options); | ||
| 394 | + }; | ||
| 395 | + | ||
| 332 | Option *opt = add_option(name, fun, description, defaulted); | 396 | Option *opt = add_option(name, fun, description, defaulted); |
| 333 | std::string typeval = detail::type_name<T>(); | 397 | std::string typeval = detail::type_name<T>(); |
| 334 | typeval += " in {" + detail::join(options) + "}"; | 398 | typeval += " in {" + detail::join(options) + "}"; |
| @@ -341,12 +405,11 @@ class App { | @@ -341,12 +405,11 @@ class App { | ||
| 341 | return opt; | 405 | return opt; |
| 342 | } | 406 | } |
| 343 | 407 | ||
| 344 | - /// Add set of options, string only, ignore case | 408 | + /// Add set of options, string only, ignore case (no default) |
| 345 | Option *add_set_ignore_case(std::string name, | 409 | Option *add_set_ignore_case(std::string name, |
| 346 | std::string &member, ///< The selected member of the set | 410 | std::string &member, ///< The selected member of the set |
| 347 | std::set<std::string> options, ///< The set of posibilities | 411 | std::set<std::string> options, ///< The set of posibilities |
| 348 | - std::string description = "", | ||
| 349 | - bool defaulted = false) { | 412 | + std::string description = "") { |
| 350 | 413 | ||
| 351 | CLI::callback_t fun = [&member, options](CLI::results_t res) { | 414 | CLI::callback_t fun = [&member, options](CLI::results_t res) { |
| 352 | if(res.size() != 1) { | 415 | if(res.size() != 1) { |
| @@ -364,6 +427,37 @@ class App { | @@ -364,6 +427,37 @@ class App { | ||
| 364 | } | 427 | } |
| 365 | }; | 428 | }; |
| 366 | 429 | ||
| 430 | + Option *opt = add_option(name, fun, description, false); | ||
| 431 | + std::string typeval = detail::type_name<std::string>(); | ||
| 432 | + typeval += " in {" + detail::join(options) + "}"; | ||
| 433 | + opt->set_custom_option(typeval); | ||
| 434 | + | ||
| 435 | + return opt; | ||
| 436 | + } | ||
| 437 | + | ||
| 438 | + /// Add set of options, string only, ignore case | ||
| 439 | + Option *add_set_ignore_case(std::string name, | ||
| 440 | + std::string &member, ///< The selected member of the set | ||
| 441 | + std::set<std::string> options, ///< The set of posibilities | ||
| 442 | + std::string description, | ||
| 443 | + bool defaulted) { | ||
| 444 | + | ||
| 445 | + CLI::callback_t fun = [&member, options](CLI::results_t res) { | ||
| 446 | + if(res.size() != 1) { | ||
| 447 | + return false; | ||
| 448 | + } | ||
| 449 | + member = detail::to_lower(res[0]); | ||
| 450 | + auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) { | ||
| 451 | + return detail::to_lower(val) == member; | ||
| 452 | + }); | ||
| 453 | + if(iter == std::end(options)) | ||
| 454 | + return false; | ||
| 455 | + else { | ||
| 456 | + member = *iter; | ||
| 457 | + return true; | ||
| 458 | + } | ||
| 459 | + }; | ||
| 460 | + | ||
| 367 | Option *opt = add_option(name, fun, description, defaulted); | 461 | Option *opt = add_option(name, fun, description, defaulted); |
| 368 | std::string typeval = detail::type_name<std::string>(); | 462 | std::string typeval = detail::type_name<std::string>(); |
| 369 | typeval += " in {" + detail::join(options) + "}"; | 463 | typeval += " in {" + detail::join(options) + "}"; |
tests/AppTest.cpp
| @@ -217,7 +217,20 @@ TEST_F(TApp, EnumTest) { | @@ -217,7 +217,20 @@ TEST_F(TApp, EnumTest) { | ||
| 217 | EXPECT_EQ(level, Level::Medium); | 217 | EXPECT_EQ(level, Level::Medium); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | -// New style enums do not work, since << is not supported. Could be fixed without changing API by duplicating the `add_` methods with and without the extra flag. | 220 | +TEST_F(TApp, NewEnumTest) { |
| 221 | + enum class Level2 : std::int32_t { | ||
| 222 | + High, | ||
| 223 | + Medium, | ||
| 224 | + Low | ||
| 225 | + }; | ||
| 226 | + Level2 level = Level2::Low; | ||
| 227 | + app.add_option("--level", level); | ||
| 228 | + | ||
| 229 | + args = {"--level", "1"}; | ||
| 230 | + run(); | ||
| 231 | + EXPECT_EQ(level, Level2::Medium); | ||
| 232 | +} | ||
| 233 | + | ||
| 221 | 234 | ||
| 222 | TEST_F(TApp, RequiredFlags) { | 235 | TEST_F(TApp, RequiredFlags) { |
| 223 | app.add_flag("-a")->required(); | 236 | app.add_flag("-a")->required(); |