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
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
use crate::{Flag, FlagValue};

pub struct Context {
    pub args: Vec<String>,
    flags: Option<Vec<(String, Option<FlagValue>)>>
}

impl Context {
    pub fn new(args: Vec<String>, flags: Option<Vec<Flag>>) -> Self {
        let mut v = Vec::new();
        let flags_val = match flags {
            Some(flags) => {
                for flag in flags {
                    v.push((flag.name.to_string(), flag.value(args.clone())))
                }
                Some(v)
            }
            None => None
        };

        Self { args, flags: flags_val }
    }

    fn option_flag_value(&self, name: &str) -> Option<&FlagValue> {
        self.flags.as_ref()
            .and_then(|flags| flags.into_iter().find(|flag| flag.0 == name.to_string()))
            .and_then(|flag| flag.1.as_ref())
    }

    pub fn bool_flag(&self, name: &str) -> bool {
        match self.option_flag_value(name) {
            Some(FlagValue::Bool(val)) => {
                (*val).clone()
            },
            _ => false
        }
    }

    pub fn string_flag(&self, name: &str) -> Option<String> {
        match self.option_flag_value(name) {
            Some(FlagValue::String(val)) => Some((&val).to_string()),
            _ => None
        }
    }

    pub fn int_flag(&self, name: &str) -> Option<isize> {
        match self.option_flag_value(name) {
            Some(FlagValue::Int(val)) => Some(val.clone()),
            _ => None
        }
    }

    pub fn float_flag(&self, name: &str) -> Option<f64> {
        match self.option_flag_value(name) {
            Some(FlagValue::Float(val)) => Some(val.clone()),
            _ => None
        }
    }
}
#[cfg(test)]
mod tests {
    use crate::{Context, Flag, FlagType};

    #[test]
    fn context_test() {
        let args = vec![
            "cli".to_string(),
            "command".to_string(),
            "args".to_string(),
            "--bool".to_string(),
            "--string".to_string(),
            "test".to_string(),
            "--int".to_string(),
            "100".to_string(),
            "--float".to_string(),
            "1.23".to_string(),
        ];
        let flags = vec![
            Flag::new("bool", "", FlagType::Bool),
            Flag::new("string", "", FlagType::String),
            Flag::new("int", "", FlagType::Int),
            Flag::new("float", "", FlagType::Float)
        ];
        let context = Context::new(args, Some(flags));

        assert_eq!(true, context.bool_flag("bool"));

        match context.string_flag("string") {
            Some(val) => assert_eq!("test".to_string(), val),
            _ => assert!(false)
        }

        match context.int_flag("int") {
            Some(val) => assert_eq!(100, val),
            _ => assert!(false)
        }

        match context.float_flag("float") {
            Some(val) => assert_eq!(1.23, val),
            _ => assert!(false)
        }
    }
}