Skip to content

Commit f374954

Browse files
authored
Merge branch 'jacobdeichert:master' into optional
2 parents bd9a2c5 + 37af673 commit f374954

File tree

7 files changed

+116
-0
lines changed

7 files changed

+116
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
## UNRELEASED
55

66
* ci: Fix php tests on macos actions runner [#110](https://github.com/jacobdeichert/mask/pull/110)
7+
* Add choices list for flags [#111](https://github.com/jacobdeichert/mask/pull/111) ([@lovejia2022](https://github.com/lovejia2022))
78

89
## v0.11.4 (2023-10-15)
910

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+
Coming in v0.11.5: 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
@@ -59,6 +59,7 @@ impl Command {
5959
takes_value: false,
6060
required: false,
6161
validate_as_number: false,
62+
choices: vec![],
6263
val: "".to_string(),
6364
});
6465
}
@@ -126,6 +127,7 @@ pub struct NamedFlag {
126127
pub multiple: bool, // Can it have multiple values? (-vvv OR -i one -i two)
127128
pub takes_value: bool, // Does it take a value? (-i value)
128129
pub validate_as_number: bool, // Should we validate it as a number?
130+
pub choices: Vec<String>, // Choices of flag value.
129131
pub required: bool,
130132
/// Used within mask. TODO: store in a different place within mask instead of here.
131133
#[serde(skip)]
@@ -143,6 +145,7 @@ impl NamedFlag {
143145
takes_value: false,
144146
required: false,
145147
validate_as_number: false,
148+
choices: vec![],
146149
val: "".to_string(),
147150
}
148151
}

mask-parser/src/parser.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ pub fn parse(maskfile_contents: String) -> Maskfile {
137137
}
138138
}
139139
}
140+
"choices" => {
141+
current_option_flag.choices = val
142+
.split(',')
143+
.map(|choice| choice.trim().to_owned())
144+
.collect();
145+
}
140146
"required" => {
141147
current_option_flag.required = true;
142148
}
@@ -327,6 +333,7 @@ mod parse {
327333
"takes_value": false,
328334
"required": false,
329335
"validate_as_number": false,
336+
"choices": [],
330337
});
331338

332339
assert_eq!(

mask/src/main.rs

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

201+
if !flag.choices.is_empty() {
202+
if !flag.choices.iter().any(|choice| choice == &raw_value) {
203+
eprintln!(
204+
"{} flag `{}` expects one of {:?}",
205+
"ERROR:".red(),
206+
flag.name,
207+
flag.choices,
208+
);
209+
std::process::exit(1);
210+
}
211+
}
212+
201213
if flag.validate_as_number && raw_value != "" {
202214
// Try converting to an integer or float to validate it
203215
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)