Commit f7cf890543693e5cb8653f61ad8910861e2a1223

Authored by Henry Fredrick Schreiner
1 parent 081bb93b

Adding new style enums too

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();
... ...