]> git.lizzy.rs Git - rust.git/commitdiff
Turn OptGroups into a main opt and a main and an aliased opts
authorJordi Boggiano <j.boggiano@seld.be>
Mon, 5 Aug 2013 12:37:54 +0000 (14:37 +0200)
committerCorey Richardson <corey@octayn.net>
Thu, 8 Aug 2013 02:41:13 +0000 (22:41 -0400)
This way opt_present("apple") will match no matter if the user passed -a or --apple

src/libextra/getopts.rs

index 5ec6713509ec02b35f57a7df7ebdaa4b2bca77c5..1b65528923a100c16a5c50108447d92dd1a637e1 100644 (file)
@@ -114,7 +114,8 @@ pub enum Occur {
 pub struct Opt {
     name: Name,
     hasarg: HasArg,
-    occur: Occur
+    occur: Occur,
+    aliases: ~[Opt],
 }
 
 fn mkname(nm: &str) -> Name {
@@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name {
 
 /// Create an option that is required and takes an argument
 pub fn reqopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Req};
+    return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
 }
 
 /// Create an option that is optional and takes an argument
 pub fn optopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Optional};
+    return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
 }
 
 /// Create an option that is optional and does not take an argument
 pub fn optflag(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Optional};
+    return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
 }
 
 /** Create an option that is optional, does not take an argument,
   * and may occur multiple times.
   */
 pub fn optflagmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: No, occur: Multi};
+    return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
 }
 
 /// Create an option that is optional and takes an optional argument
 pub fn optflagopt(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Maybe, occur: Optional};
+    return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
 }
 
 /**
@@ -157,7 +158,7 @@ pub fn optflagopt(name: &str) -> Opt {
  * multiple times
  */
 pub fn optmulti(name: &str) -> Opt {
-    return Opt {name: mkname(name), hasarg: Yes, occur: Multi};
+    return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
 }
 
 #[deriving(Clone, Eq)]
@@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str {
 }
 
 fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
-    opts.iter().position(|opt| opt.name == nm)
+    // search main options
+    let pos = opts.iter().position(|opt| opt.name == nm);
+    if pos.is_some() {
+        return pos
+    }
+
+    // search in aliases
+    for candidate in opts.iter() {
+        if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
+            return opts.iter().position(|opt| opt.name == candidate.name);
+        }
+    }
+
+    None
 }
 
 /**
@@ -488,8 +502,6 @@ pub mod groups {
     use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
     use getopts::{Short, Yes};
 
-    use std::vec;
-
     /** one group of options, e.g., both -h and --help, along with
      * their shared description and properties
      */
@@ -587,7 +599,7 @@ pub fn optmulti(short_name: &str, long_name: &str,
 
     // translate OptGroup into Opt
     // (both short and long names correspond to different Opts)
-    pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
+    pub fn long_to_short(lopt: &OptGroup) -> Opt {
         let OptGroup{short_name: short_name,
                      long_name: long_name,
                      hasarg: hasarg,
@@ -595,24 +607,29 @@ pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
                      _} = (*lopt).clone();
 
         match (short_name.len(), long_name.len()) {
-           (0,0) => fail!("this long-format option was given no name"),
-
-           (0,_) => ~[Opt {name: Long((long_name)),
-                           hasarg: hasarg,
-                           occur: occur}],
-
-           (1,0) => ~[Opt {name: Short(short_name.char_at(0)),
-                           hasarg: hasarg,
-                           occur: occur}],
-
-           (1,_) => ~[Opt {name: Short(short_name.char_at(0)),
-                           hasarg: hasarg,
-                           occur:  occur},
-                      Opt {name:   Long((long_name)),
-                           hasarg: hasarg,
-                           occur:  occur}],
-
-           (_,_) => fail!("something is wrong with the long-form opt")
+            (0,0) => fail!("this long-format option was given no name"),
+
+            (0,_) => Opt {name: Long((long_name)),
+                          hasarg: hasarg,
+                          occur: occur,
+                          aliases: ~[]},
+
+            (1,0) => Opt {name: Short(short_name.char_at(0)),
+                          hasarg: hasarg,
+                          occur: occur,
+                          aliases: ~[]},
+
+            (1,_) => Opt {name: Long((long_name)),
+                          hasarg: hasarg,
+                          occur:  occur,
+                          aliases: ~[Opt {
+                              name: Short(short_name.char_at(0)),
+                              hasarg: hasarg,
+                              occur:  occur,
+                              aliases: ~[]
+                          }]},
+
+            (_,_) => fail!("something is wrong with the long-form opt")
         }
     }
 
@@ -620,7 +637,7 @@ pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
      * Parse command line args with the provided long format options
      */
     pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
-        ::getopts::getopts(args, vec::flat_map(opts, long_to_short))
+        ::getopts::getopts(args, opts.map(long_to_short))
     }
 
     /**
@@ -1454,7 +1471,8 @@ fn test_groups_optmulti() {
 
     #[test]
     fn test_groups_long_to_short() {
-        let short = ~[reqopt("b"), reqopt("banana")];
+        let mut short = reqopt("banana");
+        short.aliases = ~[reqopt("b")];
         let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
 
         assert_eq!(groups::long_to_short(&verbose), short);
@@ -1462,10 +1480,16 @@ fn test_groups_long_to_short() {
 
     #[test]
     fn test_groups_getopts() {
+        let mut banana = reqopt("banana");
+        banana.aliases = ~[reqopt("b")];
+        let mut apple = optopt("apple");
+        apple.aliases = ~[optopt("a")];
+        let mut kiwi = optflag("kiwi");
+        kiwi.aliases = ~[optflag("k")];
         let short = ~[
-            reqopt("b"), reqopt("banana"),
-            optopt("a"), optopt("apple"),
-            optflag("k"), optflagopt("kiwi"),
+            banana,
+            apple,
+            kiwi,
             optflagopt("p"),
             optmulti("l")
         ];
@@ -1478,7 +1502,7 @@ fn test_groups_getopts() {
             groups::optmulti("l", "", "Desc", "VAL"),
         ];
 
-        let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k",
+        let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k",
                             ~"-p", ~"16", ~"l", ~"35"];
 
         // FIXME #4681: sort options here?
@@ -1486,6 +1510,19 @@ fn test_groups_getopts() {
             == groups::getopts(sample_args, verbose));
     }
 
+    #[test]
+    fn test_groups_aliases_long_and_short() {
+        let opts = ~[
+            groups::optflagmulti("a", "apple", "Desc"),
+        ];
+
+        let args = ~[~"-a", ~"--apple", ~"-a"];
+
+        let matches = groups::getopts(args, opts).unwrap();
+        assert_eq!(3, opt_count(&matches, "a"));
+        assert_eq!(3, opt_count(&matches, "apple"));
+    }
+
     #[test]
     fn test_groups_usage() {
         let optgroups = ~[