Skip to content

Commit 45c1bb9

Browse files
lovejia2022jia2024plus7wist
authored
Add choices list for flags (#111)
* Add enum flag Set type to "enum" and add a "choices" list. If flag value is not one of the choices, this task will fail. * Remove the enum type Only choices list is needed if you want to check flag value. --------- Co-authored-by: jia2024 <[email protected]> Co-authored-by: plus7wist <[email protected]>
1 parent b35d76c commit 45c1bb9

File tree

6 files changed

+115
-0
lines changed

6 files changed

+115
-0
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,28 @@ echo "Total: $(($price * $TAX))"
154154
~~~
155155
```
156156

157+
If you add a `choices` list, `mask` will validate if the flag value is one of them.
158+
159+
**Example:**
160+
161+
`````markdown
162+
## print (text)
163+
164+
> Print text with color
165+
166+
**OPTIONS**
167+
* color
168+
* flags: -c --color
169+
* type: string
170+
* choices: RED, BLUE, GREEN
171+
* desc: Color of the text.
172+
173+
```sh
174+
COLOR=${color:RED} # Fallback to RED if not supplied
175+
echo "$COLOR: $text"
176+
```
177+
`````
178+
157179
If you exclude the `type` field, `mask` will treat it as a `boolean` flag. If the flag is passed, its environment variable will be `"true"`, otherwise it will be unset/non-existent.
158180

159181
Important to note that `mask` auto injects a very common `boolean` flag called `verbose` into every single command even if it's not used, which saves a bit of typing for you. This means every command implicitly has a `-v` and `--verbose` flag already.

mask-parser/src/maskfile.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl Command {
5757
takes_value: false,
5858
required: false,
5959
validate_as_number: false,
60+
choices: vec![],
6061
val: "".to_string(),
6162
});
6263
}
@@ -107,6 +108,7 @@ pub struct NamedFlag {
107108
pub multiple: bool, // Can it have multiple values? (-vvv OR -i one -i two)
108109
pub takes_value: bool, // Does it take a value? (-i value)
109110
pub validate_as_number: bool, // Should we validate it as a number?
111+
pub choices: Vec<String>, // Choices of flag value.
110112
pub required: bool,
111113
/// Used within mask. TODO: store in a different place within mask instead of here.
112114
#[serde(skip)]
@@ -124,6 +126,7 @@ impl NamedFlag {
124126
takes_value: false,
125127
required: false,
126128
validate_as_number: false,
129+
choices: vec![],
127130
val: "".to_string(),
128131
}
129132
}

mask-parser/src/parser.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ pub fn parse(maskfile_contents: String) -> Maskfile {
135135
}
136136
}
137137
}
138+
"choices" => {
139+
current_option_flag.choices = val
140+
.split(',')
141+
.map(|choice| choice.trim().to_owned())
142+
.collect();
143+
}
138144
"required" => {
139145
current_option_flag.required = true;
140146
}
@@ -299,6 +305,7 @@ mod parse {
299305
"takes_value": false,
300306
"required": false,
301307
"validate_as_number": false,
308+
"choices": [],
302309
});
303310

304311
assert_eq!(

mask/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ fn get_command_options(mut cmd: Command, matches: &ArgMatches) -> Command {
184184
.unwrap()
185185
.to_string();
186186

187+
if !flag.choices.is_empty() {
188+
if !flag.choices.iter().any(|choice| choice == &raw_value) {
189+
eprintln!(
190+
"{} flag `{}` expects one of {:?}",
191+
"ERROR:".red(),
192+
flag.name,
193+
flag.choices,
194+
);
195+
std::process::exit(1);
196+
}
197+
}
198+
187199
if flag.validate_as_number && raw_value != "" {
188200
// Try converting to an integer or float to validate it
189201
if raw_value.parse::<isize>().is_err() && raw_value.parse::<f32>().is_err() {

mask/tests/arguments_and_flags_test.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,76 @@ Write-Output $sum
177177
}
178178
}
179179

180+
mod choices {
181+
use super::*;
182+
183+
#[test]
184+
fn properly_validates_flag_with_choices() {
185+
let (_temp, maskfile_path) = common::maskfile(
186+
r#"
187+
## color
188+
189+
**OPTIONS**
190+
* val
191+
* flags: --val
192+
* type: string
193+
* choices: RED, BLUE, GREEN
194+
195+
```bash
196+
echo "Value: $val"
197+
```
198+
199+
```powershell
200+
param (
201+
$in = $env:val
202+
)
203+
Write-Output "Value: $in"
204+
```
205+
"#,
206+
);
207+
208+
common::run_mask(&maskfile_path)
209+
.cli("color --val RED")
210+
.assert()
211+
.stdout(contains("Value: RED"))
212+
.success();
213+
}
214+
215+
#[test]
216+
fn out_of_choices() {
217+
let (_temp, maskfile_path) = common::maskfile(
218+
r#"
219+
## color
220+
221+
**OPTIONS**
222+
* val
223+
* flags: --val
224+
* type: string
225+
* choices: RED, BLUE, GREEN
226+
227+
```bash
228+
echo "Value: $val"
229+
```
230+
231+
```powershell
232+
param (
233+
$in = $env:val
234+
)
235+
Write-Output "Value: $in"
236+
```
237+
"#,
238+
);
239+
240+
common::run_mask(&maskfile_path)
241+
.cli("color --val YELLOW")
242+
.assert()
243+
.stderr(contains(
244+
"flag `val` expects one of [\"RED\", \"BLUE\", \"GREEN\"]",
245+
))
246+
.failure();
247+
}
248+
}
249+
180250
mod numerical_option_flag {
181251
use super::*;
182252

mask/tests/introspect_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ echo something
2727
"takes_value": false,
2828
"required": false,
2929
"validate_as_number": false,
30+
"choices": [],
3031
});
3132

3233
let expected_json = json!({

0 commit comments

Comments
 (0)