1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use crate::{Filter, Getter};
use clap::{ArgMatches, Values};

fn _dig<'a, 'b, 'c, IT: Iterator<Item = &'c str>>(
    m: &'a ArgMatches<'b>,
    down: &'c str,
    mut i: IT,
) -> Option<(&'a ArgMatches<'b>, &'c str)> {
    match i.next() {
        None => Some((m, down)),
        Some(s) => _dig(m.subcommand_matches(down)?, s, i),
    }
}

fn dig<'a, 'b, 'c>(m: &'a ArgMatches<'b>, s: &'c str) -> Option<(&'a ArgMatches<'b>, &'c str)> {
    let mut it = s.split(".");
    _dig(m, it.next()?, it)
}

impl<'a, 'b> Getter<'a,&'a str> for &'a ArgMatches<'b> {
    type Iter = Values<'a>;
    fn bool_flag<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        if f != Filter::Arg {
            return false;
        }
        let (r, dot_last) = match dig(self, s.as_ref()) {
            Some(v) => v,
            None => return false,
        };
        r.is_present(dot_last)
    }

    fn value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<&'a str> {
        if f != Filter::Arg {
            return None;
        }
        let (r, dot_last) = dig(self, s.as_ref())?;
        r.value_of(dot_last)
    }

    fn values<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<Values<'a>> {
        if f != Filter::Arg {
            return None;
        }
        let (r, dot_last) = dig(self, s.as_ref())?;
        r.values_of(dot_last)
    }

    fn sub<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        if f != Filter::Arg {
            return false;
        }
        let (r, dot_last) = match dig(self, s.as_ref()) {
            Some(v) => v,
            None => return false,
        };
        match r.subcommand_matches(dot_last) {
            Some(_) => true,
            None => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use clap::clap_app;
    //TODO add tests involving clap_app::App::get_matches_from
    #[test]
    pub fn test_sub_get() {
        let m = clap_app!(
            test_app=>
                (@arg a : -a +takes_value "astuff")
                (@subcommand subby =>
                    (@arg b: -b +takes_value "bstuff")
                        )

        )
        .get_matches_from("test_app -a hi subby -b world".split(" "));

        let mm = &m;

        assert_eq!(mm.sub("a", Filter::Arg), false, "A");
        assert_eq!(mm.grab().arg("a").done(), Some("hi"), "HI");
        assert_eq!(mm.sub("subby", Filter::Arg), true, "--Sub Subby--");
        assert_eq!(mm.grab().arg("subby.b").done(), Some("world"), "C");
        assert_eq!(mm.bool_flag("a", Filter::Arg), true);
    }
}