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
pub mod name;

/// Command line argument flag for on/off state.
///
/// Uses `std::env:args()` to determine the arguments passed to the program.
/// If there is an argument matching the flag's name then this variable will be
/// truthy.
/// ```
/// use ezcli::flag;
///
/// // accepts "--my_boolean"
/// // if passed in, "my_boolean" is true
/// flag!(my_boolean);
/// ```
/// In some case of not wanting to use the program's environment arguments
/// using a slice is also possible.
/// ```
/// use ezcli::flag;
///
/// let args = ["--my_boolean"];
///
/// // accepts "--my_boolean"
/// // if passed in, "my_boolean" is true
/// flag!(my_boolean, args);
/// ```
/// If the command line argument name should be different to the variable name
/// then use [`named_flag`].
///
/// [`named_flag`]: ./macro.named_flag.html
#[macro_export]
macro_rules! flag {
    ($name:tt, $args:ident) => {
        let $name: bool = $args
            .iter()
            .find(|s| **s == format!("--{}", stringify!($name)))
            .is_some();
    };
    ($name:tt) => {
        let $name: bool = std::env::args()
            .into_iter()
            .find(|s| *s == format!("--{}", stringify!($name)))
            .is_some();
    };
}

/// Optional command line argument with associated value.
///
/// When provided via command line it will return `Some` wrapping the value
/// passed along with it. `None` will be returned when the option is not
/// provided or does not follow syntax.
/// ```
/// use ezcli::option;
///
/// // accepts "--my_option"
/// // "my_option" will be an Option<String>
/// option!(my_option);
/// ```
/// In some case of not wanting to use the program's environment arguments
/// using a slice is also possible.
/// ```
/// use ezcli::option;
///
/// let args = ["--my_option", "value"];
///
/// // accepts "--my_option"
/// // "my_option" will be an Option<String>
/// option!(my_option, args);
/// ```
#[macro_export]
macro_rules! option {
    ($name:tt, $args:ident) => {
        let $name: Option<String> = {
            let args: Vec<String> = $args.iter().map(|s| s.to_string()).collect();
            $crate::_option(stringify!($name), args.as_slice())
        };
    };
    ($name:tt) => {
        let $name: Option<String> = {
            let args: Vec<String> = std::env::args().collect();
            $crate::_option(stringify!($name), args.as_slice())
        };
    };
}

pub fn _option(name: &str, args: &[String]) -> Option<String> {
    let mut optional = None;
    let wanted_arg = format!("--{}", name);
    for i in 0..args.len() {
        if args[i] == wanted_arg && args.len() > i + 1 {
            optional = Some(args[i + 1].clone());
            break;
        }
    }

    optional
}