From 8d5e59398fbf28eec4f7ad9a240d75284c8a3034 Mon Sep 17 00:00:00 2001 From: Jay Oster Date: Mon, 19 Feb 2024 12:01:26 -0800 Subject: [PATCH] Fix required positional arguments --- onlyargs_derive/Cargo.toml | 1 + onlyargs_derive/src/lib.rs | 13 ++++++++++++- onlyargs_derive/tests/parsing.rs | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/onlyargs_derive/Cargo.toml b/onlyargs_derive/Cargo.toml index 099a76c..68aac80 100644 --- a/onlyargs_derive/Cargo.toml +++ b/onlyargs_derive/Cargo.toml @@ -11,6 +11,7 @@ categories = ["command-line-interface"] license = "MIT" exclude = [ "/compile_tests", + "/tests", ] [lib] diff --git a/onlyargs_derive/src/lib.rs b/onlyargs_derive/src/lib.rs index 3568b90..0d55f50 100644 --- a/onlyargs_derive/src/lib.rs +++ b/onlyargs_derive/src/lib.rs @@ -357,7 +357,18 @@ pub fn derive_parser(input: TokenStream) -> TokenStream { .collect::(); let positional_ident = ast .positional - .map(|opt| format!("{},", opt.name)) + .map(|opt| { + if matches!(opt.property, ArgProperty::Positional { required: true }) { + format!( + r#"{}: {}.required("{arg}")?,"#, + opt.name, + opt.name, + arg = to_arg_name(&opt.name), + ) + } else { + format!("{},", opt.name) + } + }) .unwrap_or_default(); let name = ast.name; diff --git a/onlyargs_derive/tests/parsing.rs b/onlyargs_derive/tests/parsing.rs index 89ded90..8388526 100644 --- a/onlyargs_derive/tests/parsing.rs +++ b/onlyargs_derive/tests/parsing.rs @@ -84,3 +84,26 @@ fn test_required_multivalue() -> Result<(), CliError> { Ok(()) } + +#[test] +fn test_required_positional() -> Result<(), CliError> { + #[derive(Debug, OnlyArgs)] + struct Args { + #[required] + #[positional] + rest: Vec, + } + + // Empty positional is not allowed. + assert!(matches!( + dbg!(Args::parse(vec![])), + Err(CliError::MissingRequired(name)) if name == "rest", + )); + + // At least one positional is required. + let args = Args::parse(["Bob"].into_iter().map(OsString::from).collect())?; + + assert_eq!(args.rest, ["Bob"]); + + Ok(()) +}