Răsfoiți Sursa

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 8 ani în urmă
părinte
comite
53dc370a41
1 a modificat fișierele cu 107 adăugiri și 6 ștergeri
  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));
+    }
+}