Explorar o código

Search for long options through matches

Casualty here was that you can’t have static values reference one another directly, so the static args slice had to be turned into a slice *of references* rather than of values. No big deal, just have to write & a few more times.
Benjamin Sago %!s(int64=8) %!d(string=hai) anos
pai
achega
53dc370a41
Modificáronse 1 ficheiros con 107 adicións e 6 borrados
  1. 107 6
      src/options/parser.rs

+ 107 - 6
src/options/parser.rs

@@ -13,6 +13,15 @@ pub enum Flag {
     Long(LongArg),
 }
 
+impl Flag {
+    fn matches(&self, arg: &Arg) -> bool {
+        match *self {
+            Flag::Short(short)  => arg.short == Some(short),
+            Flag::Long(long)    => arg.long == long,
+        }
+    }
+}
+
 #[derive(PartialEq, Debug)]
 pub enum Strictness {
     ComplainAboutRedundantArguments,
@@ -33,7 +42,7 @@ pub struct Arg {
 }
 
 #[derive(PartialEq, Debug)]
-pub struct Args(&'static [Arg]);
+pub struct Args(&'static [&'static Arg]);
 
 impl Args {
     fn lookup_short<'a>(&self, short: ShortArg) -> Result<&Arg, ParseError<'a>> {
@@ -60,6 +69,20 @@ pub struct Matches<'a> {
     frees: Vec<&'a OsStr>,
 }
 
+impl<'a> Matches<'a> {
+    fn has(&self, arg: &Arg) -> bool {
+        self.flags.iter().rev()
+            .find(|tuple| tuple.1.is_none() && tuple.0.matches(arg))
+            .is_some()
+    }
+
+    fn get(&self, arg: &Arg) -> Option<&OsStr> {
+        self.flags.iter().rev()
+            .find(|tuple| tuple.1.is_some() && tuple.0.matches(arg))
+            .map(|tuple| tuple.1.unwrap())
+    }
+}
+
 #[derive(PartialEq, Debug)]
 pub enum ParseError<'a> {
     NeedsValue { flag: Flag },
@@ -233,7 +256,7 @@ mod split_test {
 
 
 #[cfg(test)]
-mod test {
+mod parse_test {
     use super::*;
 
     macro_rules! test {
@@ -247,10 +270,10 @@ mod test {
         };
     }
 
-    static TEST_ARGS: &'static [Arg] = &[
-        Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
-        Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
-        Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary }
+    static TEST_ARGS: &[&Arg] = &[
+        &Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden },
+        &Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden },
+        &Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary }
     ];
 
 
@@ -302,3 +325,81 @@ mod test {
     test!(unknown_short_eq:      [os("-q=shhh")]      => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
     test!(unknown_short_2nd_eq:  [os("-lq=shhh")]     => Err(ParseError::UnknownShortArgument { attempt: b'q' }));
 }
+
+
+#[cfg(test)]
+mod matches_test {
+    use super::*;
+
+    static LONG:    Arg = Arg { short: Some(b'l'), long: "long",     takes_value: TakesValue::Forbidden };
+    static VERBOSE: Arg = Arg { short: Some(b'v'), long: "verbose",  takes_value: TakesValue::Forbidden };
+    static COUNT:   Arg = Arg { short: Some(b'c'), long: "count",    takes_value: TakesValue::Necessary };
+    static TEST_ARGS: &[&Arg] = &[ &LONG, &VERBOSE, &COUNT ];
+
+    #[test]
+    fn has_long() {
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: vec![ (Flag::Short(b'l'), None) ],
+        };
+
+        assert!(matches.has(&LONG));
+    }
+
+    #[test]
+    fn has_long_twice() {
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: vec![ (Flag::Short(b'l'), None),
+                         (Flag::Short(b'l'), None) ],
+        };
+
+        assert!(matches.has(&LONG));
+    }
+
+    #[test]
+    fn no_long() {
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: Vec::new(),
+        };
+
+        assert!(!matches.has(&LONG));
+    }
+
+    #[test]
+    fn only_count() {
+        let everything = os("everything");
+
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: vec![ (Flag::Short(b'c'), Some(&*everything)) ],
+        };
+
+        assert_eq!(matches.get(&COUNT), Some(&*everything));
+    }
+
+    #[test]
+    fn rightmost_count() {
+        let everything = os("everything");
+        let nothing    = os("nothing");
+
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: vec![ (Flag::Short(b'c'), Some(&*everything)),
+                         (Flag::Short(b'c'), Some(&*nothing)) ],
+        };
+
+        assert_eq!(matches.get(&COUNT), Some(&*nothing));
+    }
+
+    #[test]
+    fn no_count() {
+        let matches = Matches {
+            frees: Vec::new(),
+            flags: Vec::new(),
+        };
+
+        assert!(!matches.has(&COUNT));
+    }
+}