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 | 213 | } else |
| 214 | 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 | 220 | template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> |
| 219 | 221 | Option *add_option(std::string name, |
| 220 | 222 | T &variable, ///< The variable to set |
| 221 | - std::string description = "", | |
| 222 | - bool defaulted = false) { | |
| 223 | + std::string description = "") { | |
| 223 | 224 | |
| 224 | 225 | CLI::callback_t fun = [&variable](CLI::results_t res) { |
| 225 | 226 | if(res.size() != 1) |
| ... | ... | @@ -227,6 +228,24 @@ class App { |
| 227 | 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 | 249 | Option *opt = add_option(name, fun, description, defaulted); |
| 231 | 250 | opt->set_custom_option(detail::type_name<T>()); |
| 232 | 251 | if(defaulted) { |
| ... | ... | @@ -236,13 +255,34 @@ class App { |
| 236 | 255 | } |
| 237 | 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 | 280 | /// Add option for vectors |
| 241 | 281 | template <typename T> |
| 242 | 282 | Option *add_option(std::string name, |
| 243 | 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 | 287 | CLI::callback_t fun = [&variable](CLI::results_t res) { |
| 248 | 288 | bool retval = true; |
| ... | ... | @@ -311,13 +351,12 @@ class App { |
| 311 | 351 | return opt; |
| 312 | 352 | } |
| 313 | 353 | |
| 314 | - /// Add set of options | |
| 354 | + /// Add set of options (No default) | |
| 315 | 355 | template <typename T> |
| 316 | 356 | Option *add_set(std::string name, |
| 317 | 357 | T &member, ///< The selected member of the set |
| 318 | 358 | std::set<T> options, ///< The set of posibilities |
| 319 | - std::string description = "", | |
| 320 | - bool defaulted = false) { | |
| 359 | + std::string description = "") { | |
| 321 | 360 | |
| 322 | 361 | CLI::callback_t fun = [&member, options](CLI::results_t res) { |
| 323 | 362 | if(res.size() != 1) { |
| ... | ... | @@ -329,6 +368,31 @@ class App { |
| 329 | 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 | 396 | Option *opt = add_option(name, fun, description, defaulted); |
| 333 | 397 | std::string typeval = detail::type_name<T>(); |
| 334 | 398 | typeval += " in {" + detail::join(options) + "}"; |
| ... | ... | @@ -341,12 +405,11 @@ class App { |
| 341 | 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 | 409 | Option *add_set_ignore_case(std::string name, |
| 346 | 410 | std::string &member, ///< The selected member of the set |
| 347 | 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 | 414 | CLI::callback_t fun = [&member, options](CLI::results_t res) { |
| 352 | 415 | if(res.size() != 1) { |
| ... | ... | @@ -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 | 461 | Option *opt = add_option(name, fun, description, defaulted); |
| 368 | 462 | std::string typeval = detail::type_name<std::string>(); |
| 369 | 463 | typeval += " in {" + detail::join(options) + "}"; | ... | ... |
tests/AppTest.cpp
| ... | ... | @@ -217,7 +217,20 @@ TEST_F(TApp, EnumTest) { |
| 217 | 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 | 235 | TEST_F(TApp, RequiredFlags) { |
| 223 | 236 | app.add_flag("-a")->required(); | ... | ... |