Commit cc3fa6009d04a0f6d1d70c81334d45018542c1f4

Authored by Henry Fredrick Schreiner
1 parent a80ac7b7

Support for multiple names on option

include/CLI.hpp
... ... @@ -287,34 +287,6 @@ inline void cleanup_names(const std::vector<std::string> &input) {
287 287 }
288 288 }
289 289  
290   -// Splits a string into long and short names
291   -inline std::tuple<std::string, std::string> split(std::string fullname) {
292   - if(fullname.find(" ") != std::string::npos)
293   - throw BadNameString("Cannot have space in name string: "+fullname);
294   - std::vector<std::string> output = split_names(fullname);
295   - cleanup_names(output);
296   -
297   - if(output.size() > 2)
298   - throw BadNameString(fullname);
299   - else if (output.size() == 2) {
300   - if(output[0].length()==0 && output[1].length()==0)
301   - throw BadNameString("EMPTY");
302   - else if(output[0].length()<2)
303   - return std::tuple<std::string,std::string>(output[0], output[1]);
304   - else if(output[1].length() < 2)
305   - return std::tuple<std::string,std::string>(output[0], output[1]);
306   - else
307   - throw BadNameString(fullname);
308   - } else {
309   - if(output[0].length()==0)
310   - throw BadNameString("EMPTY");
311   - else if(output[0].length() == 1)
312   - return std::tuple<std::string,std::string>(output[0], "");
313   - else
314   - return std::tuple<std::string,std::string>("", output[0]);
315   - }
316   -}
317   -
318 290  
319 291 const Combiner NOTHING {0, false,false,false, {}};
320 292 const Combiner REQUIRED {1, false,true, false, {}};
... ... @@ -339,8 +311,8 @@ class Option {
339 311 public:
340 312 protected:
341 313 // Config
342   - std::string sname;
343   - std::string lname;
  314 + std::vector<std::string> snames;
  315 + std::vector<std::string> lnames;
344 316 Combiner opts;
345 317 std::string discription;
346 318 callback_t callback;
... ... @@ -352,7 +324,7 @@ protected:
352 324 public:
353 325 Option(std::string name, std::string discription = "", Combiner opts=NOTHING, std::function<bool(results_t)> callback=[](results_t){return true;}) :
354 326 opts(opts), discription(discription), callback(callback){
355   - std::tie(sname, lname) = split(name);
  327 + std::tie(snames, lnames) = get_names(split_names(name));
356 328 }
357 329  
358 330 void clear() {
... ... @@ -386,44 +358,44 @@ public:
386 358 return callback(results);
387 359 }
388 360  
389   - /// Indistinguishible options are equal
  361 + /// If options share any of the same names, they are equal
390 362 bool operator== (const Option& other) const {
391   - if(sname=="" && other.sname=="")
392   - return lname==other.lname;
393   - else if(lname=="" && other.lname=="")
394   - return sname==other.sname;
395   - else
396   - return sname==other.sname || lname==other.lname;
  363 + for(const std::string &sname : snames)
  364 + for(const std::string &othersname : other.snames)
  365 + if(sname == othersname)
  366 + return true;
  367 + for(const std::string &lname : lnames)
  368 + for(const std::string &otherlname : other.lnames)
  369 + if(lname == otherlname)
  370 + return true;
  371 + return false;
397 372 }
398 373  
399 374 std::string get_name() const {
400   - if(sname=="")
401   - return "--" + lname;
402   - else if (lname=="")
403   - return "-" + sname;
404   - else
405   - return "-" + sname + ", --" + lname;
  375 + std::vector<std::string> name_list;
  376 + for(const std::string& sname : snames)
  377 + name_list.push_back("-"+sname);
  378 + for(const std::string& lname : lnames)
  379 + name_list.push_back("--"+lname);
  380 + return join(name_list);
406 381 }
407 382  
408   - bool check_name(const std::string& name) const {
409   - return name == sname || name == lname || name == sname + "," + lname;
  383 + bool check_name(std::string name) const {
  384 + for(int i=0; i<2; i++)
  385 + if(name.length()>2 && name[0] == '-')
  386 + name = name.substr(1);
  387 +
  388 + return check_sname(name) || check_lname(name);
410 389 }
411 390  
412 391 bool check_sname(const std::string& name) const {
413   - return name == sname;
  392 + return std::find(std::begin(snames), std::end(snames), name) != std::end(snames);
414 393 }
415 394  
416 395 bool check_lname(const std::string& name) const {
417   - return name == lname;
  396 + return std::find(std::begin(lnames), std::end(lnames), name) != std::end(lnames);
418 397 }
419 398  
420   - std::string get_sname() const {
421   - return sname;
422   - }
423   -
424   - std::string get_lname() const {
425   - return lname;
426   - }
427 399  
428 400 void add_result(int r, std::string s) {
429 401 logit("Adding result: " + s);
... ... @@ -976,7 +948,7 @@ public:
976 948 auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_sname(name);});
977 949  
978 950 if(op == std::end(options)) {
979   - missing_options.push_back("-" + op->get_sname());
  951 + missing_options.push_back("-" + name);
980 952 return;
981 953 }
982 954  
... ... @@ -1044,7 +1016,7 @@ public:
1044 1016 auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_lname(name);});
1045 1017  
1046 1018 if(op == std::end(options)) {
1047   - missing_options.push_back("--" + op->get_lname());
  1019 + missing_options.push_back("--" + name);
1048 1020 return;
1049 1021 }
1050 1022  
... ...
tests/CLITest.cpp
... ... @@ -52,6 +52,21 @@ TEST_F(TApp, OneFlagLong) {
52 52 EXPECT_EQ(1, app.count("count"));
53 53 }
54 54  
  55 +TEST_F(TApp, DashedOptions) {
  56 + app.add_flag("-c");
  57 + app.add_flag("--q");
  58 + app.add_flag("--this,--that");
  59 +
  60 + args = {"-c", "--q", "--this", "--that"};
  61 + EXPECT_NO_THROW(run());
  62 + EXPECT_EQ(1, app.count("c"));
  63 + EXPECT_EQ(1, app.count("q"));
  64 + EXPECT_EQ(2, app.count("this"));
  65 + EXPECT_EQ(2, app.count("--that"));
  66 +
  67 +}
  68 +
  69 +
55 70 TEST_F(TApp, OneFlagRef) {
56 71 int ref;
57 72 app.add_flag("c,count", ref);
... ... @@ -454,9 +469,6 @@ TEST_F(TAppValue, DoubleVector) {
454 469 EXPECT_EQ(std::vector<double>({1.2, 3.4, -1}), *value);
455 470 }
456 471  
457   -// TODO: Maybe add function to call on subcommand parse? Stashed.
458 472 // TODO: Check help output, better formatting
459 473 // TODO: Add default/type info to help
460   -// TODO: Add regex replacement function (GCC 4.8 support)
461 474 // TODO: Add README
462   -// TODO: Change format of option specifications?
... ...
tests/SmallTest.cpp
... ... @@ -4,44 +4,6 @@
4 4 #include <fstream>
5 5  
6 6  
7   -TEST(Split, GoodStrings) {
8   - std::string s, l;
9   -
10   - std::tie(s, l) = CLI::split("a,boo");
11   - EXPECT_EQ("a", s);
12   - EXPECT_EQ("boo", l);
13   -
14   - std::tie(s, l) = CLI::split(",coo");
15   - EXPECT_EQ("", s);
16   - EXPECT_EQ("coo", l);
17   -
18   - std::tie(s, l) = CLI::split("d,");
19   - EXPECT_EQ("d", s);
20   - EXPECT_EQ("", l);
21   -
22   - std::tie(s, l) = CLI::split("Q,this-is");
23   - EXPECT_EQ("Q", s);
24   - EXPECT_EQ("this-is", l);
25   -
26   - std::tie(s, l) = CLI::split("s");
27   - EXPECT_EQ("s", s);
28   - EXPECT_EQ("", l);
29   -
30   - std::tie(s, l) = CLI::split("single");
31   - EXPECT_EQ("", s);
32   - EXPECT_EQ("single", l);
33   - }
34   -
35   -TEST(Split, BadStrings) {
36   -
37   - EXPECT_THROW(CLI::split("a,,boo"), CLI::BadNameString);
38   - EXPECT_THROW(CLI::split("a,b,c"), CLI::BadNameString);
39   - EXPECT_THROW(CLI::split("ssd,sfd"), CLI::BadNameString);
40   - EXPECT_THROW(CLI::split("-a"), CLI::BadNameString);
41   - EXPECT_THROW(CLI::split(""), CLI::BadNameString);
42   - EXPECT_THROW(CLI::split(","), CLI::BadNameString);
43   - EXPECT_THROW(CLI::split("one two"), CLI::BadNameString);
44   -}
45 7  
46 8 TEST(Validators, FileExists) {
47 9 std::string myfile{"TestFileNotUsed.txt"};
... ...