standout_dispatch/
dispatch.rs1use clap::ArgMatches;
7
8pub fn extract_command_path(matches: &ArgMatches) -> Vec<String> {
12 let mut path = Vec::new();
13 let mut current = matches;
14
15 while let Some((name, sub)) = current.subcommand() {
16 if name == "help" {
18 break;
19 }
20 path.push(name.to_string());
21 current = sub;
22 }
23
24 path
25}
26
27pub fn get_deepest_matches(matches: &ArgMatches) -> &ArgMatches {
32 let mut current = matches;
33
34 while let Some((name, sub)) = current.subcommand() {
35 if name == "help" {
36 break;
37 }
38 current = sub;
39 }
40
41 current
42}
43
44pub fn has_subcommand(matches: &ArgMatches) -> bool {
48 matches
49 .subcommand()
50 .map(|(name, _)| name != "help")
51 .unwrap_or(false)
52}
53
54pub fn insert_default_command<I, S>(args: I, command: &str) -> Vec<String>
58where
59 I: IntoIterator<Item = S>,
60 S: Into<String>,
61{
62 let mut result: Vec<String> = args.into_iter().map(Into::into).collect();
63 if !result.is_empty() {
64 result.insert(1, command.to_string());
65 } else {
66 result.push(command.to_string());
67 }
68 result
69}
70
71pub fn path_to_string(path: &[String]) -> String {
75 path.join(".")
76}
77
78pub fn string_to_path(s: &str) -> Vec<String> {
82 if s.is_empty() {
83 Vec::new()
84 } else {
85 s.split('.').map(String::from).collect()
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use clap::Command;
93
94 #[test]
95 fn test_extract_command_path() {
96 let cmd =
97 Command::new("app").subcommand(Command::new("config").subcommand(Command::new("get")));
98
99 let matches = cmd.try_get_matches_from(["app", "config", "get"]).unwrap();
100 let path = extract_command_path(&matches);
101
102 assert_eq!(path, vec!["config", "get"]);
103 }
104
105 #[test]
106 fn test_extract_command_path_single() {
107 let cmd = Command::new("app").subcommand(Command::new("list"));
108
109 let matches = cmd.try_get_matches_from(["app", "list"]).unwrap();
110 let path = extract_command_path(&matches);
111
112 assert_eq!(path, vec!["list"]);
113 }
114
115 #[test]
116 fn test_extract_command_path_empty() {
117 let cmd = Command::new("app");
118
119 let matches = cmd.try_get_matches_from(["app"]).unwrap();
120 let path = extract_command_path(&matches);
121
122 assert!(path.is_empty());
123 }
124
125 #[test]
126 fn test_has_subcommand_true() {
127 let cmd = Command::new("app").subcommand(Command::new("list"));
128
129 let matches = cmd.try_get_matches_from(["app", "list"]).unwrap();
130 assert!(has_subcommand(&matches));
131 }
132
133 #[test]
134 fn test_has_subcommand_false() {
135 let cmd = Command::new("app").subcommand(Command::new("list"));
136
137 let matches = cmd.try_get_matches_from(["app"]).unwrap();
138 assert!(!has_subcommand(&matches));
139 }
140
141 #[test]
142 fn test_has_subcommand_help_excluded() {
143 let cmd = Command::new("app")
144 .disable_help_subcommand(true)
145 .subcommand(Command::new("help"));
146
147 let matches = cmd.try_get_matches_from(["app", "help"]).unwrap();
148 assert!(!has_subcommand(&matches));
149 }
150
151 #[test]
152 fn test_insert_default_command() {
153 let args = vec!["myapp", "-v"];
154 let result = insert_default_command(args, "list");
155 assert_eq!(result, vec!["myapp", "list", "-v"]);
156 }
157
158 #[test]
159 fn test_insert_default_command_no_args() {
160 let args = vec!["myapp"];
161 let result = insert_default_command(args, "list");
162 assert_eq!(result, vec!["myapp", "list"]);
163 }
164
165 #[test]
166 fn test_insert_default_command_empty() {
167 let args: Vec<String> = vec![];
168 let result = insert_default_command(args, "list");
169 assert_eq!(result, vec!["list"]);
170 }
171
172 #[test]
173 fn test_path_to_string() {
174 assert_eq!(
175 path_to_string(&["db".into(), "migrate".into()]),
176 "db.migrate"
177 );
178 assert_eq!(path_to_string(&["list".into()]), "list");
179 assert_eq!(path_to_string(&[]), "");
180 }
181
182 #[test]
183 fn test_string_to_path() {
184 assert_eq!(string_to_path("db.migrate"), vec!["db", "migrate"]);
185 assert_eq!(string_to_path("list"), vec!["list"]);
186 assert_eq!(string_to_path(""), Vec::<String>::new());
187 }
188}