simple_args/
lib.rs

1use multimap::MultiMap;
2
3/// Parsed Arguments
4pub struct Arguments {
5    arg_map: MultiMap<String, Option<String>>,
6}
7
8impl Arguments {
9    /// Parse arguments. This cannot fail. Arguments are simply
10    /// denoted by a single `-` followed by the argument,
11    /// and the value is immediately after. Multiple instances
12    /// can be contained, and arguments can contain no value
13    ///
14    /// # Arguments
15    ///
16    /// `args`: The arguments
17    pub fn parse<S: AsRef<str>>(args: &[S]) -> Arguments {
18        let mut arg_map = MultiMap::new();
19        for (key, val) in args.iter().map(|s| s.as_ref()).zip(
20            args.iter()
21                .map(|s| s.as_ref())
22                .skip(1)
23                .chain(std::iter::once("")),
24        ) {
25            if let Some(stripped) = key.strip_prefix('-') {
26                arg_map.insert(
27                    stripped.to_string(),
28                    if val.is_empty() || val.starts_with('-') {
29                        None
30                    } else {
31                        Some(val.to_string())
32                    },
33                );
34            }
35        }
36        Arguments { arg_map }
37    }
38
39    /// Checks whether or not an argument is present in the list
40    ///
41    /// # Arguments
42    ///
43    /// `key`: The key to check
44    pub fn contains(&self, key: &str) -> bool {
45        self.arg_map.contains_key(key)
46    }
47
48    /// Checks whether or not an argument is present in the list
49    /// with a non-empty value
50    ///
51    /// # Arguments
52    ///
53    /// `key`: The key to check
54    pub fn contains_val(&self, key: &str) -> bool {
55        self.arg_map
56            .get_vec(key)
57            .and_then(|vals| vals.iter().find(|&val| val.is_some()))
58            .is_some()
59    }
60
61    /// Checks whether or not the arguments are empty
62    pub fn is_empty(&self) -> bool {
63        self.arg_map.is_empty()
64    }
65
66    /// Gets the first value with the given key
67    ///
68    /// # Arguments
69    ///
70    /// `key`: The key to fetch
71    pub fn get(&self, key: &str) -> Option<Option<&str>> {
72        Some(self.arg_map.get(key)?.as_ref().map(String::as_ref))
73    }
74
75    /// Gets all values with the given key
76    ///
77    /// # Arguments
78    ///
79    /// `key`: The key to fetch
80    pub fn get_vec(&self, key: &str) -> Option<&Vec<Option<String>>> {
81        self.arg_map.get_vec(key)
82    }
83
84    /// Returns the number of arguments that were parsed
85    pub fn len(&self) -> usize {
86        self.arg_map.len()
87    }
88}
89
90#[cfg(test)]
91mod test {
92    use super::Arguments;
93
94    #[test]
95    fn empty() {
96        let args = Arguments::parse::<String>(&[]);
97        assert!(args.is_empty());
98        assert_eq!(args.len(), 0);
99    }
100
101    #[test]
102    fn no_arg() {
103        let args = Arguments::parse(&["arg"]);
104        assert!(args.is_empty());
105        assert_eq!(args.len(), 0);
106    }
107
108    #[test]
109    fn one_empty() {
110        let args = Arguments::parse(&["-key"]);
111        assert!(!args.is_empty());
112        assert_eq!(args.len(), 1);
113        assert!(args.contains("key"));
114        assert!(!args.contains_val("key"));
115        assert!(args.get("key").is_some());
116        assert_eq!(args.get_vec("key").unwrap().len(), 1);
117    }
118
119    #[test]
120    fn one_key() {
121        let args = Arguments::parse(&["-key", "val"]);
122        assert!(!args.is_empty());
123        assert_eq!(args.len(), 1);
124        assert!(args.contains("key"));
125        assert!(args.contains_val("key"));
126        assert!(args.get("key").is_some());
127        assert_eq!(args.get("key").unwrap().unwrap(), "val");
128        assert_eq!(args.get_vec("key").unwrap().len(), 1);
129    }
130
131    #[test]
132    fn one_key_repeated() {
133        let args = Arguments::parse(&["-key", "val", "-key", "val2"]);
134        assert!(!args.is_empty());
135        assert_eq!(args.len(), 1);
136        assert!(args.contains("key"));
137        assert!(args.contains_val("key"));
138        assert!(args.get("key").is_some());
139        assert_eq!(args.get("key").unwrap().unwrap(), "val");
140        assert_eq!(
141            args.get_vec("key").unwrap(),
142            &vec!(Some("val".to_string()), Some("val2".to_string()))
143        );
144        assert_eq!(args.get_vec("key").unwrap().len(), 2);
145    }
146
147    #[test]
148    fn one_key_cut_short() {
149        let args = Arguments::parse(&["-key", "-key", "val2"]);
150        assert!(!args.is_empty());
151        assert_eq!(args.len(), 1);
152        assert!(args.contains("key"));
153        assert!(args.contains_val("key"));
154        assert!(args.get("key").is_some());
155        assert_eq!(args.get("key").unwrap(), None);
156        assert_eq!(
157            args.get_vec("key").unwrap(),
158            &vec!(None, Some("val2".to_string()))
159        );
160        assert_eq!(args.get_vec("key").unwrap().len(), 2);
161    }
162
163    #[test]
164    fn two_keys() {
165        let args = Arguments::parse(&["-key", "val", "-key2", "val2"]);
166        assert!(!args.is_empty());
167        assert_eq!(args.len(), 2);
168        assert!(args.contains("key"));
169        assert!(args.contains("key2"));
170        assert!(args.contains_val("key"));
171        assert!(args.contains_val("key2"));
172        assert!(args.get("key").is_some());
173        assert!(args.get("key2").is_some());
174        assert_eq!(args.get("key").unwrap().unwrap(), "val");
175        assert_eq!(args.get("key2").unwrap().unwrap(), "val2");
176        assert_eq!(args.get_vec("key").unwrap().len(), 1);
177        assert_eq!(args.get_vec("key2").unwrap().len(), 1);
178    }
179
180    #[test]
181    fn two_keys_cut_short() {
182        let args = Arguments::parse(&["-key", "-key2", "val2"]);
183        assert!(!args.is_empty());
184        assert_eq!(args.len(), 2);
185        assert!(args.contains("key"));
186        assert!(args.contains("key2"));
187        assert!(!args.contains_val("key"));
188        assert!(args.contains_val("key2"));
189        assert!(args.get("key").is_some());
190        assert!(args.get("key2").is_some());
191        assert_eq!(args.get("key").unwrap(), None);
192        assert_eq!(args.get("key2").unwrap().unwrap(), "val2");
193        assert_eq!(args.get_vec("key").unwrap().len(), 1);
194        assert_eq!(args.get_vec("key2").unwrap().len(), 1);
195    }
196
197    #[test]
198    fn ergonomics() {
199        let sys_args: Vec<String> = vec!["-key".into(), "val".into()];
200        let args = Arguments::parse(&sys_args);
201        assert!(!args.is_empty());
202        assert_eq!(args.len(), 1);
203        assert!(args.contains("key"));
204        assert!(args.contains_val("key"));
205        assert!(args.get("key").is_some());
206        assert_eq!(args.get("key").unwrap().unwrap(), "val");
207        assert_eq!(args.get_vec("key").unwrap().len(), 1);
208    }
209}