mithril_doc/
extract_clap_info.rs

1use clap::{Arg, Command, builder::StyledStr};
2
3use super::{FieldDoc, StructDoc};
4
5/// Extract information of an command line argument.
6fn extract_arg(arg: &Arg) -> FieldDoc {
7    let parameter = arg.get_id().to_string();
8    let short_option = arg.get_short().map_or("".into(), |c| format!("-{c}"));
9    let long_option = arg.get_long().map_or("".into(), |c| format!("--{c}"));
10    let env_variable = arg.get_env().map(|s| format!("{}", s.to_string_lossy()));
11    let description = arg.get_help().map_or("-".into(), StyledStr::to_string);
12    let default_value = if arg.get_default_values().iter().count() == 0 {
13        None
14    } else {
15        Some(
16            arg.get_default_values()
17                .iter()
18                .map(|s| format!("{}", s.to_string_lossy()))
19                .collect::<Vec<String>>()
20                .join(","),
21        )
22    };
23    let example = None;
24
25    FieldDoc {
26        parameter,
27        command_line_long: long_option,
28        command_line_short: short_option,
29        environment_variable: env_variable,
30        description,
31        default_value,
32        example,
33        is_mandatory: arg.is_required_set(),
34    }
35}
36
37pub fn extract_parameters(cmd: &Command) -> StructDoc {
38    let fields = cmd.get_arguments().map(extract_arg).collect();
39    StructDoc::new(fields)
40}
41
42#[cfg(test)]
43mod tests {
44
45    use super::*;
46    use clap::{CommandFactory, Parser};
47
48    #[derive(Parser, Debug, Clone)]
49    #[command(version)]
50    pub struct MyCommand {
51        /// Run Mode
52        #[clap(short, long, default_value = "dev")]
53        run_mode: String,
54
55        #[clap()]
56        param_without_default: String,
57    }
58
59    #[test]
60    fn test_extract_arg_info() {
61        let command = MyCommand::command();
62        let arg = command.get_arguments().next().unwrap();
63        let parameter: FieldDoc = extract_arg(arg);
64
65        assert_eq!("run_mode", parameter.parameter);
66        assert_eq!("-r".to_string(), parameter.command_line_short);
67        assert_eq!("--run-mode".to_string(), parameter.command_line_long);
68        assert_eq!(Some("dev".to_string()), parameter.default_value);
69        assert_eq!("Run Mode".to_string(), parameter.description);
70        assert!(parameter.example.is_none());
71        assert!(!parameter.is_mandatory);
72    }
73
74    #[test]
75    fn test_extract_required_arg() {
76        let command = MyCommand::command();
77        let arg = command
78            .get_arguments()
79            .find(|arg| arg.get_id() == "param_without_default")
80            .unwrap();
81        let parameter: FieldDoc = extract_arg(arg);
82
83        assert!(parameter.is_mandatory);
84    }
85
86    #[test]
87    fn test_extract_command_info() {
88        let command = MyCommand::command();
89        let command_parameters: StructDoc = extract_parameters(&command);
90
91        //assert_eq!(1, command_parameters.data.len());
92        assert_eq!(
93            "run_mode",
94            command_parameters.get_ordered_data().first().unwrap().parameter
95        );
96        for arg in command.get_arguments() {
97            println!("{} {}", arg.get_id(), arg.is_required_set());
98        }
99    }
100}