From 43f792f91e15e832cdc01c5d6b8f5351c2d8c333 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 19 Dec 2023 15:13:12 +0100 Subject: [PATCH 1/4] remove parse and rename try_parse to parse --- README.md | 2 +- docs/guide/port.md | 10 +-- docs/guide/quick.md | 35 ++++---- examples/completion.rs | 2 +- examples/deprecated.rs | 17 +++- examples/hello_world.rs | 3 +- examples/value.rs | 2 +- src/lib.rs | 37 +------- tests/coreutils/arch.rs | 6 +- tests/coreutils/b2sum.rs | 52 +++++++++-- tests/coreutils/base32.rs | 22 ++++- tests/coreutils/basename.rs | 2 +- tests/coreutils/cat.rs | 16 ++-- tests/coreutils/dd.rs | 23 +++-- tests/coreutils/echo.rs | 6 +- tests/coreutils/head.rs | 2 +- tests/coreutils/ls.rs | 54 ++++++----- tests/coreutils/mktemp.rs | 22 ++--- tests/coreutils/tail.rs | 2 +- tests/flags.rs | 131 +++++++++++++++++++-------- tests/options.rs | 173 ++++++++++++++++++++++++++++-------- 21 files changed, 414 insertions(+), 205 deletions(-) diff --git a/README.md b/README.md index 839a510..d27b71e 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ impl Options for Settings { } fn run(args: &[&str]) -> String { - let (s, operands) = Settings::default().parse(args); + let (s, operands) = Settings::default().parse(args).unwrap(); let text = operands.iter().map(|s| s.to_string_lossy()).collect::>().join(" "); let mut output = if s.caps { text.to_uppercase() diff --git a/docs/guide/port.md b/docs/guide/port.md index 2cc2981..f7d6070 100644 --- a/docs/guide/port.md +++ b/docs/guide/port.md @@ -101,7 +101,7 @@ impl Options for Settings { } } -let a = Settings::default().parse(std::env::args_os()).0.a; +let a = Settings::default().parse(std::env::args_os()).unwrap().0.a; ``` ### `ArgAction::SetFalse` @@ -144,7 +144,7 @@ impl Options for Settings { } } -let a = Settings::default().parse(std::env::args_os()).0.a; +let a = Settings::default().parse(std::env::args_os()).unwrap().0.a; ``` ### `ArgAction::Count` @@ -182,7 +182,7 @@ impl Options for Settings { } } -let a = Settings::default().parse(std::env::args_os()).0.a; +let a = Settings::default().parse(std::env::args_os()).unwrap().0.a; ``` ### `ArgAction::Set` @@ -222,7 +222,7 @@ impl Options for Settings { } } -let a = Settings::default().parse(std::env::args_os()).0.a; +let a = Settings::default().parse(std::env::args_os()).unwrap().0.a; ``` ### `ArgAction::Append` @@ -262,7 +262,7 @@ impl Options for Settings { } } -let a = Settings::default().parse(std::env::args_os()).0.a; +let a = Settings::default().parse(std::env::args_os()).unwrap().0.a; ```
diff --git a/docs/guide/quick.md b/docs/guide/quick.md index 6b928ea..31f515b 100644 --- a/docs/guide/quick.md +++ b/docs/guide/quick.md @@ -66,14 +66,14 @@ impl Options for Settings { } } -let (settings, operands) = Settings::default().parse(["test"]); +let (settings, operands) = Settings::default().parse(["test"]).unwrap(); assert!(!settings.force); assert_eq!(operands, Vec::::new()); -let (settings, operands) = Settings::default().parse(["test", "-f"]); +let (settings, operands) = Settings::default().parse(["test", "-f"]).unwrap(); assert!(settings.force); -let (settings, operands) = Settings::default().parse(["test", "foo"]); +let (settings, operands) = Settings::default().parse(["test", "foo"]).unwrap(); assert!(!settings.force); assert_eq!(operands, vec![OsString::from("foo")]); ``` @@ -108,17 +108,16 @@ impl Options for Settings { } } -let (settings, operands) = Settings::default().parse(["test"]); +let (settings, operands) = Settings::default().parse(["test"]).unwrap(); assert!(!settings.force); assert_eq!(operands, Vec::::new()); -let (settings, operands) = Settings::default().parse(["test", "-f", "some-operand"]); +let (settings, operands) = Settings::default().parse(["test", "-f", "some-operand"]).unwrap(); assert!(settings.force); - assert_eq!(operands, vec!["some-operand"]); -let (settings, operands) = Settings::default().parse(["test", "-f", "-F", "some-other-operand"]); -assert!(!settings.force); +let (settings, operands) = Settings::default().parse(["test", "-f", "-F", "some-other-operand"]).unwrap(); +assert!(!settings.force); assert_eq!(operands, vec!["some-other-operand"]); ``` @@ -169,11 +168,11 @@ enum Arg { # } # # assert_eq!( -# Settings::default().parse(["test"]).0.name, +# Settings::default().parse(["test"]).unwrap().0.name, # OsString::new(), # ); # assert_eq!( -# Settings::default().parse(["test", "--name=John"]).0.name, +# Settings::default().parse(["test", "--name=John"]).unwrap().0.name, # OsString::from("John"), # ); ``` @@ -206,11 +205,11 @@ enum Arg { # } # # assert_eq!( -# Settings::default().parse(["test", "--name"]).0.name, +# Settings::default().parse(["test", "--name"]).unwrap().0.name, # OsString::from("anonymous"), # ); # assert_eq!( -# Settings::default().parse(["test", "--name=John"]).0.name, +# Settings::default().parse(["test", "--name=John"]).unwrap().0.name, # OsString::from("John"), # ); ``` @@ -242,9 +241,9 @@ enum Arg { # } # } # -# assert!(!Settings::default().parse(["test"]).0.force); -# assert!(Settings::default().parse(["test", "-f"]).0.force); -# assert!(!Settings::default().parse(["test", "-F"]).0.force); +# assert!(!Settings::default().parse(["test"]).unwrap().0.force); +# assert!(Settings::default().parse(["test", "-f"]).unwrap().0.force); +# assert!(!Settings::default().parse(["test", "-F"]).unwrap().0.force); ``` This is particularly interesting for defining "shortcut" arguments. For example, `ls` takes a `--sort=WORD` argument, that defines how the files should be sorted. But it also has shorthands like `-t`, which is the same as `--sort=time`. All of these can be implemented on one variant: @@ -277,9 +276,9 @@ enum Arg { # } # } # -# assert_eq!(Settings::default().parse(["test"]).0.sort, String::new()); -# assert_eq!(Settings::default().parse(["test", "--sort=time"]).0.sort, String::from("time")); -# assert_eq!(Settings::default().parse(["test", "-t"]).0.sort, String::from("time")); +# assert_eq!(Settings::default().parse(["test"]).unwrap().0.sort, String::new()); +# assert_eq!(Settings::default().parse(["test", "--sort=time"]).unwrap().0.sort, String::from("time")); +# assert_eq!(Settings::default().parse(["test", "-t"]).unwrap().0.sort, String::from("time")); ```
diff --git a/examples/completion.rs b/examples/completion.rs index 22679c6..112cc60 100644 --- a/examples/completion.rs +++ b/examples/completion.rs @@ -38,5 +38,5 @@ impl Options for Settings { } fn main() { - Settings.parse(std::env::args_os()); + Settings.parse(std::env::args_os()).unwrap(); } diff --git a/examples/deprecated.rs b/examples/deprecated.rs index 25484b6..2a6d5bd 100644 --- a/examples/deprecated.rs +++ b/examples/deprecated.rs @@ -43,8 +43,17 @@ impl Options for Settings { } fn main() { - assert_eq!(Settings::default().parse(["test", "-10"]).0.n1, 10usize); - assert!(Settings::default().try_parse(["test", "--10"]).is_err()); - assert_eq!(Settings::default().parse(["test", "+10"]).0.n2, 10isize); - assert_eq!(Settings::default().parse(["test", "+-10"]).0.n2, -10isize); + assert_eq!( + Settings::default().parse(["test", "-10"]).unwrap().0.n1, + 10usize + ); + assert!(Settings::default().parse(["test", "--10"]).is_err()); + assert_eq!( + Settings::default().parse(["test", "+10"]).unwrap().0.n2, + 10isize + ); + assert_eq!( + Settings::default().parse(["test", "+-10"]).unwrap().0.n2, + -10isize + ); } diff --git a/examples/hello_world.rs b/examples/hello_world.rs index a8eb551..7bd4eb0 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -36,7 +36,8 @@ fn main() -> Result<(), uutils_args::Error> { name: String::new(), count: 1, } - .parse(std::env::args_os()); + .parse(std::env::args_os()) + .unwrap(); for _ in 0..settings.count { println!("Hello, {}!", settings.name); diff --git a/examples/value.rs b/examples/value.rs index 997d136..5359192 100644 --- a/examples/value.rs +++ b/examples/value.rs @@ -33,6 +33,6 @@ impl Options for Settings { } fn main() { - let (settings, _operands) = Settings::default().parse(std::env::args_os()); + let (settings, _operands) = Settings::default().parse(std::env::args_os()).unwrap(); println!("{:?}", settings.color); } diff --git a/src/lib.rs b/src/lib.rs index 8e76960..ac971cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,16 +67,6 @@ pub enum Argument { Custom(T), } -fn exit_if_err(res: Result) -> T { - match res { - Ok(v) => v, - Err(err) => { - eprintln!("{err}"); - std::process::exit(err.exit_code); - } - } -} - /// Defines how the arguments are parsed. /// /// If a type `T` implements this trait, we can construct an `ArgumentIter`, @@ -112,23 +102,11 @@ pub trait Arguments: Sized { /// Get the version string for this command. fn version() -> String; - /// Check all arguments immediately and exit on errors. - /// - /// This is useful if you want to validate the arguments. This method will - /// exit if `--help` or `--version` are passed and if any errors are found. - fn check(args: I) - where - I: IntoIterator, - I::Item: Into, - { - exit_if_err(Self::try_check(args)) - } - /// Check all arguments immediately and return any errors. /// /// This is useful if you want to validate the arguments. This method will /// exit if `--help` or `--version` are passed. - fn try_check(args: I) -> Result<(), Error> + fn check(args: I) -> Result<(), Error> where I: IntoIterator, I::Item: Into, @@ -145,8 +123,7 @@ pub trait Arguments: Sized { /// An iterator over arguments. /// /// Can be constructed by calling [`Arguments::parse`]. Usually, this method -/// won't be used directly, but is used internally in [`Options::parse`] and -/// [`Options::try_parse`]. +/// won't be used directly, but is used internally in [`Options::parse`]. pub struct ArgumentIter { parser: lexopt::Parser, positional_arguments: Vec, @@ -218,16 +195,8 @@ pub trait Options: Sized { fn apply(&mut self, arg: Arg); /// Parse an iterator of arguments into the options - fn parse(self, args: I) -> (Self, Vec) - where - I: IntoIterator, - I::Item: Into, - { - exit_if_err(self.try_parse(args)) - } - #[allow(unused_mut)] - fn try_parse(mut self, args: I) -> Result<(Self, Vec), Error> + fn parse(mut self, args: I) -> Result<(Self, Vec), Error> where I: IntoIterator, I::Item: Into, diff --git a/tests/coreutils/arch.rs b/tests/coreutils/arch.rs index e69b639..266505d 100644 --- a/tests/coreutils/arch.rs +++ b/tests/coreutils/arch.rs @@ -5,11 +5,11 @@ enum Arg {} #[test] fn no_args() { - assert!(Arg::try_check(["arch"]).is_ok()); + assert!(Arg::check(["arch"]).is_ok()); } #[test] fn one_arg_fails() { - assert!(Arg::try_check(["arch", "-f"]).is_err()); - assert!(Arg::try_check(["arch", "--foo"]).is_err()); + assert!(Arg::check(["arch", "-f"]).is_err()); + assert!(Arg::check(["arch", "--foo"]).is_err()); } diff --git a/tests/coreutils/b2sum.rs b/tests/coreutils/b2sum.rs index adae103..3f24c71 100644 --- a/tests/coreutils/b2sum.rs +++ b/tests/coreutils/b2sum.rs @@ -62,26 +62,52 @@ impl Options for Settings { #[test] fn binary() { - assert!(!Settings::default().parse(["b2sum"]).0.binary); - assert!(!Settings::default().parse(["b2sum", "--text"]).0.binary); - assert!(!Settings::default().parse(["b2sum", "-t"]).0.binary); + assert!(!Settings::default().parse(["b2sum"]).unwrap().0.binary); + assert!( + !Settings::default() + .parse(["b2sum", "--text"]) + .unwrap() + .0 + .binary + ); + assert!(!Settings::default().parse(["b2sum", "-t"]).unwrap().0.binary); assert!( !Settings::default() .parse(["b2sum", "--binary", "--text"]) + .unwrap() + .0 + .binary + ); + assert!( + !Settings::default() + .parse(["b2sum", "-b", "-t"]) + .unwrap() .0 .binary ); - assert!(!Settings::default().parse(["b2sum", "-b", "-t"]).0.binary); - assert!(Settings::default().parse(["b2sum", "--binary"]).0.binary); - assert!(Settings::default().parse(["b2sum", "-b"]).0.binary); + assert!( + Settings::default() + .parse(["b2sum", "--binary"]) + .unwrap() + .0 + .binary + ); + assert!(Settings::default().parse(["b2sum", "-b"]).unwrap().0.binary); assert!( Settings::default() .parse(["b2sum", "--text", "--binary"]) + .unwrap() + .0 + .binary + ); + assert!( + Settings::default() + .parse(["b2sum", "-t", "-b"]) + .unwrap() .0 .binary ); - assert!(Settings::default().parse(["b2sum", "-t", "-b"]).0.binary); } #[test] @@ -89,6 +115,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--warn"]) + .unwrap() .0 .check_output, CheckOutput::Warn @@ -96,6 +123,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--quiet"]) + .unwrap() .0 .check_output, CheckOutput::Quiet @@ -103,6 +131,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--status"]) + .unwrap() .0 .check_output, CheckOutput::Status @@ -110,6 +139,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--status", "--warn"]) + .unwrap() .0 .check_output, CheckOutput::Warn @@ -117,6 +147,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--status", "--warn"]) + .unwrap() .0 .check_output, CheckOutput::Warn @@ -125,6 +156,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--warn", "--quiet"]) + .unwrap() .0 .check_output, CheckOutput::Quiet @@ -133,6 +165,7 @@ fn check_output() { assert_eq!( Settings::default() .parse(["b2sum", "--quiet", "--status"]) + .unwrap() .0 .check_output, CheckOutput::Status @@ -142,7 +175,10 @@ fn check_output() { #[test] fn files() { assert_eq!( - Settings::default().parse(["b2sum", "foo", "bar"]).1, + Settings::default() + .parse(["b2sum", "foo", "bar"]) + .unwrap() + .1, vec![OsString::from("foo"), OsString::from("bar")] ); } diff --git a/tests/coreutils/base32.rs b/tests/coreutils/base32.rs index be54c57..de32e74 100644 --- a/tests/coreutils/base32.rs +++ b/tests/coreutils/base32.rs @@ -41,14 +41,28 @@ impl Options for Settings { #[test] fn wrap() { - assert_eq!(Settings::default().parse(["base32"]).0.wrap, Some(76)); - assert_eq!(Settings::default().parse(["base32", "-w0"]).0.wrap, None); assert_eq!( - Settings::default().parse(["base32", "-w100"]).0.wrap, + Settings::default().parse(["base32"]).unwrap().0.wrap, + Some(76) + ); + assert_eq!( + Settings::default().parse(["base32", "-w0"]).unwrap().0.wrap, + None + ); + assert_eq!( + Settings::default() + .parse(["base32", "-w100"]) + .unwrap() + .0 + .wrap, Some(100) ); assert_eq!( - Settings::default().parse(["base32", "--wrap=100"]).0.wrap, + Settings::default() + .parse(["base32", "--wrap=100"]) + .unwrap() + .0 + .wrap, Some(100) ); } diff --git a/tests/coreutils/basename.rs b/tests/coreutils/basename.rs index accb8ce..7f0716e 100644 --- a/tests/coreutils/basename.rs +++ b/tests/coreutils/basename.rs @@ -36,7 +36,7 @@ impl Options for Settings { } fn parse(args: &[&str]) -> Settings { - let (mut settings, operands) = Settings::default().parse(args); + let (mut settings, operands) = Settings::default().parse(args).unwrap(); settings.names = operands; if !settings.multiple { assert_eq!(settings.names.len(), 2); diff --git a/tests/coreutils/cat.rs b/tests/coreutils/cat.rs index 190d6c1..03df331 100644 --- a/tests/coreutils/cat.rs +++ b/tests/coreutils/cat.rs @@ -75,27 +75,27 @@ impl Options for Settings { #[test] fn show() { - let (s, _) = Settings::default().parse(["cat", "-v"]); + let (s, _) = Settings::default().parse(["cat", "-v"]).unwrap(); assert!(!s.show_ends && !s.show_tabs && s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-E"]); + let (s, _) = Settings::default().parse(["cat", "-E"]).unwrap(); assert!(s.show_ends && !s.show_tabs && !s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-T"]); + let (s, _) = Settings::default().parse(["cat", "-T"]).unwrap(); assert!(!s.show_ends && s.show_tabs && !s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-e"]); + let (s, _) = Settings::default().parse(["cat", "-e"]).unwrap(); assert!(s.show_ends && !s.show_tabs && s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-t"]); + let (s, _) = Settings::default().parse(["cat", "-t"]).unwrap(); assert!(!s.show_ends && s.show_tabs && s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-A"]); + let (s, _) = Settings::default().parse(["cat", "-A"]).unwrap(); assert!(s.show_ends && s.show_tabs && s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-te"]); + let (s, _) = Settings::default().parse(["cat", "-te"]).unwrap(); assert!(s.show_ends && s.show_tabs && s.show_nonprinting); - let (s, _) = Settings::default().parse(["cat", "-vET"]); + let (s, _) = Settings::default().parse(["cat", "-vET"]).unwrap(); assert!(s.show_ends && s.show_tabs && s.show_nonprinting); } diff --git a/tests/coreutils/dd.rs b/tests/coreutils/dd.rs index 20ae14c..fe5ef69 100644 --- a/tests/coreutils/dd.rs +++ b/tests/coreutils/dd.rs @@ -116,13 +116,16 @@ impl Options for Settings { #[test] fn empty() { - assert_eq!(Settings::default().parse(["dd"]).0, Settings::default()) + assert_eq!( + Settings::default().parse(["dd"]).unwrap().0, + Settings::default() + ) } #[test] fn infile() { assert_eq!( - Settings::default().parse(["dd", "if=hello"]).0, + Settings::default().parse(["dd", "if=hello"]).unwrap().0, Settings { infile: Some(PathBuf::from("hello")), ..Settings::default() @@ -133,7 +136,7 @@ fn infile() { #[test] fn outfile() { assert_eq!( - Settings::default().parse(["dd", "of=hello"]).0, + Settings::default().parse(["dd", "of=hello"]).unwrap().0, Settings { outfile: Some(PathBuf::from("hello")), ..Settings::default() @@ -144,7 +147,7 @@ fn outfile() { #[test] fn bs() { assert_eq!( - Settings::default().parse(["dd", "ibs=1"]).0, + Settings::default().parse(["dd", "ibs=1"]).unwrap().0, Settings { ibs: 1, obs: 512, @@ -152,7 +155,7 @@ fn bs() { } ); assert_eq!( - Settings::default().parse(["dd", "obs=1"]).0, + Settings::default().parse(["dd", "obs=1"]).unwrap().0, Settings { ibs: 512, obs: 1, @@ -160,7 +163,10 @@ fn bs() { } ); assert_eq!( - Settings::default().parse(["dd", "ibs=10", "obs=1"]).0, + Settings::default() + .parse(["dd", "ibs=10", "obs=1"]) + .unwrap() + .0, Settings { ibs: 10, obs: 1, @@ -168,7 +174,10 @@ fn bs() { } ); assert_eq!( - Settings::default().parse(["dd", "ibs=10", "bs=1"]).0, + Settings::default() + .parse(["dd", "ibs=10", "bs=1"]) + .unwrap() + .0, Settings { ibs: 1, obs: 1, diff --git a/tests/coreutils/echo.rs b/tests/coreutils/echo.rs index 4016c46..2d561f2 100644 --- a/tests/coreutils/echo.rs +++ b/tests/coreutils/echo.rs @@ -39,16 +39,16 @@ impl Options for Settings { #[test] #[ignore = "needs to be fixed after positional argument refactor"] fn double_hyphen() { - let (_, operands) = Settings::default().parse(["echo", "--"]); + let (_, operands) = Settings::default().parse(["echo", "--"]).unwrap(); assert_eq!(operands, vec![OsString::from("--")]); - let (_, operands) = Settings::default().parse(["echo", "--", "-n"]); + let (_, operands) = Settings::default().parse(["echo", "--", "-n"]).unwrap(); assert_eq!(operands, vec![OsString::from("--"), OsString::from("-n")]); } #[test] #[ignore] fn nonexistent_options_are_values() { - let (_, operands) = Settings::default().parse(["echo", "-f"]); + let (_, operands) = Settings::default().parse(["echo", "-f"]).unwrap(); assert_eq!(operands, vec![OsString::from("-f")]); } diff --git a/tests/coreutils/head.rs b/tests/coreutils/head.rs index ab08a9e..cdf8326 100644 --- a/tests/coreutils/head.rs +++ b/tests/coreutils/head.rs @@ -212,7 +212,7 @@ where { match parse_deprecated(iter.clone()) { Some(s) => Ok(s), - None => Settings::default().try_parse(iter), + None => Settings::default().parse(iter), } } diff --git a/tests/coreutils/ls.rs b/tests/coreutils/ls.rs index 1a23c92..681e83c 100644 --- a/tests/coreutils/ls.rs +++ b/tests/coreutils/ls.rs @@ -423,7 +423,7 @@ impl Options for Settings { #[test] fn default() { assert_eq!( - Settings::default().parse(["ls"]).0, + Settings::default().parse(["ls"]).unwrap().0, Settings { format: Format::Columns, sort: Sort::Name, @@ -454,87 +454,95 @@ fn default() { #[test] fn color() { - let (s, _operands) = Settings::default().parse(["ls", "--color"]); + let (s, _operands) = Settings::default().parse(["ls", "--color"]).unwrap(); assert!(s.color); - let (s, _operands) = Settings::default().parse(["ls", "--color=always"]); + let (s, _operands) = Settings::default().parse(["ls", "--color=always"]).unwrap(); assert!(s.color); - let (s, _operands) = Settings::default().parse(["ls", "--color=never"]); + let (s, _operands) = Settings::default().parse(["ls", "--color=never"]).unwrap(); assert!(!s.color); } #[test] fn format() { - let (s, _operands) = Settings::default().parse(["ls", "-l"]); + let (s, _operands) = Settings::default().parse(["ls", "-l"]).unwrap(); assert_eq!(s.format, Format::Long); - let (s, _operands) = Settings::default().parse(["ls", "-m"]); + let (s, _operands) = Settings::default().parse(["ls", "-m"]).unwrap(); assert_eq!(s.format, Format::Commas); - let (s, _operands) = Settings::default().parse(["ls", "--format=across"]); + let (s, _operands) = Settings::default() + .parse(["ls", "--format=across"]) + .unwrap(); assert_eq!(s.format, Format::Across); - let (s, _operands) = Settings::default().parse(["ls", "--format=acr"]); + let (s, _operands) = Settings::default().parse(["ls", "--format=acr"]).unwrap(); assert_eq!(s.format, Format::Across); - let (s, _operands) = Settings::default().parse(["ls", "-o"]); + let (s, _operands) = Settings::default().parse(["ls", "-o"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(s.long_no_group && !s.long_no_owner && !s.long_numeric_uid_gid); - let (s, _operands) = Settings::default().parse(["ls", "-g"]); + let (s, _operands) = Settings::default().parse(["ls", "-g"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(!s.long_no_group && s.long_no_owner && !s.long_numeric_uid_gid); - let (s, _operands) = Settings::default().parse(["ls", "-n"]); + let (s, _operands) = Settings::default().parse(["ls", "-n"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(!s.long_no_group && !s.long_no_owner && s.long_numeric_uid_gid); - let (s, _operands) = Settings::default().parse(["ls", "-og"]); + let (s, _operands) = Settings::default().parse(["ls", "-og"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(s.long_no_group && s.long_no_owner && !s.long_numeric_uid_gid); - let (s, _operands) = Settings::default().parse(["ls", "-on"]); + let (s, _operands) = Settings::default().parse(["ls", "-on"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(s.long_no_group && !s.long_no_owner && s.long_numeric_uid_gid); - let (s, _operands) = Settings::default().parse(["ls", "-onCl"]); + let (s, _operands) = Settings::default().parse(["ls", "-onCl"]).unwrap(); assert_eq!(s.format, Format::Long); assert!(s.long_no_group && !s.long_no_owner && s.long_numeric_uid_gid); } #[test] fn time() { - let (s, _operands) = Settings::default().parse(["ls", "--time=access"]); + let (s, _operands) = Settings::default().parse(["ls", "--time=access"]).unwrap(); assert_eq!(s.time, Time::Access); - let (s, _operands) = Settings::default().parse(["ls", "--time=a"]); + let (s, _operands) = Settings::default().parse(["ls", "--time=a"]).unwrap(); assert_eq!(s.time, Time::Access); } #[test] fn classify() { - let (s, _operands) = Settings::default().parse(["ls", "--indicator-style=classify"]); + let (s, _operands) = Settings::default() + .parse(["ls", "--indicator-style=classify"]) + .unwrap(); assert_eq!(s.indicator_style, IndicatorStyle::Classify); - let (s, _operands) = Settings::default().parse(["ls", "--classify"]); + let (s, _operands) = Settings::default().parse(["ls", "--classify"]).unwrap(); assert_eq!(s.indicator_style, IndicatorStyle::Classify); - let (s, _operands) = Settings::default().parse(["ls", "--classify=always"]); + let (s, _operands) = Settings::default() + .parse(["ls", "--classify=always"]) + .unwrap(); assert_eq!(s.indicator_style, IndicatorStyle::Classify); - let (s, _operands) = Settings::default().parse(["ls", "--classify=none"]); + let (s, _operands) = Settings::default() + .parse(["ls", "--classify=none"]) + .unwrap(); assert_eq!(s.indicator_style, IndicatorStyle::None); - let (s, _operands) = Settings::default().parse(["ls", "-F"]); + let (s, _operands) = Settings::default().parse(["ls", "-F"]).unwrap(); assert_eq!(s.indicator_style, IndicatorStyle::Classify); } #[test] fn sort() { - let (s, _operands) = Settings::default().parse(["ls", "--sort=time"]); + let (s, _operands) = Settings::default().parse(["ls", "--sort=time"]).unwrap(); assert_eq!(s.sort, Sort::Time); - let (s, _operands) = Settings::default().parse(["ls", "-X"]); + let (s, _operands) = Settings::default().parse(["ls", "-X"]).unwrap(); assert_eq!(s.sort, Sort::Extension); } diff --git a/tests/coreutils/mktemp.rs b/tests/coreutils/mktemp.rs index c90d019..1319709 100644 --- a/tests/coreutils/mktemp.rs +++ b/tests/coreutils/mktemp.rs @@ -48,35 +48,37 @@ impl Options for Settings { #[test] fn suffix() { - let (s, _operands) = Settings::default().parse(["mktemp", "--suffix=hello"]); + let (s, _operands) = Settings::default() + .parse(["mktemp", "--suffix=hello"]) + .unwrap(); assert_eq!(s.suffix.unwrap(), "hello"); - let (s, _operands) = Settings::default().parse(["mktemp", "--suffix="]); + let (s, _operands) = Settings::default().parse(["mktemp", "--suffix="]).unwrap(); assert_eq!(s.suffix.unwrap(), ""); - let (s, _operands) = Settings::default().parse(["mktemp", "--suffix="]); + let (s, _operands) = Settings::default().parse(["mktemp", "--suffix="]).unwrap(); assert_eq!(s.suffix.unwrap(), ""); - let (s, _operands) = Settings::default().parse(["mktemp"]); + let (s, _operands) = Settings::default().parse(["mktemp"]).unwrap(); assert_eq!(s.suffix, None); } #[test] fn tmpdir() { - let (s, _operands) = Settings::default().parse(["mktemp", "--tmpdir"]); + let (s, _operands) = Settings::default().parse(["mktemp", "--tmpdir"]).unwrap(); assert_eq!(s.tmp_dir.unwrap(), Path::new(".")); - let (s, _operands) = Settings::default().parse(["mktemp", "--tmpdir="]); + let (s, _operands) = Settings::default().parse(["mktemp", "--tmpdir="]).unwrap(); assert_eq!(s.tmp_dir.unwrap(), Path::new("")); - let (s, _operands) = Settings::default().parse(["mktemp", "-p", "foo"]); + let (s, _operands) = Settings::default().parse(["mktemp", "-p", "foo"]).unwrap(); assert_eq!(s.tmp_dir.unwrap(), Path::new("foo")); - let (s, _operands) = Settings::default().parse(["mktemp", "-pfoo"]); + let (s, _operands) = Settings::default().parse(["mktemp", "-pfoo"]).unwrap(); assert_eq!(s.tmp_dir.unwrap(), Path::new("foo")); - let (s, _operands) = Settings::default().parse(["mktemp", "-p", ""]); + let (s, _operands) = Settings::default().parse(["mktemp", "-p", ""]).unwrap(); assert_eq!(s.tmp_dir.unwrap(), Path::new("")); - assert!(Settings::default().try_parse(["mktemp", "-p"]).is_err()); + assert!(Settings::default().parse(["mktemp", "-p"]).is_err()); } diff --git a/tests/coreutils/tail.rs b/tests/coreutils/tail.rs index f8f75d2..2c9573e 100644 --- a/tests/coreutils/tail.rs +++ b/tests/coreutils/tail.rs @@ -278,7 +278,7 @@ where { match parse_deprecated(iter.clone()) { Some(s) => Ok(s), - None => Settings::default().try_parse(iter), + None => Settings::default().parse(iter), } } diff --git a/tests/flags.rs b/tests/flags.rs index c1960cf..c9877d1 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -21,7 +21,7 @@ fn one_flag() { } } - let (settings, _) = Settings::default().parse(["test", "-f"]); + let (settings, _) = Settings::default().parse(["test", "-f"]).unwrap(); assert!(settings.foo); } @@ -51,19 +51,19 @@ fn two_flags() { } assert_eq!( - Settings::default().parse(["test", "-a"]).0, + Settings::default().parse(["test", "-a"]).unwrap().0, Settings { a: true, b: false } ); assert_eq!( - Settings::default().parse(["test"]).0, + Settings::default().parse(["test"]).unwrap().0, Settings { a: false, b: false } ); assert_eq!( - Settings::default().parse(["test", "-b"]).0, + Settings::default().parse(["test", "-b"]).unwrap().0, Settings { a: false, b: true } ); assert_eq!( - Settings::default().parse(["test", "-a", "-b"]).0, + Settings::default().parse(["test", "-a", "-b"]).unwrap().0, Settings { a: true, b: true } ); } @@ -87,9 +87,9 @@ fn long_and_short_flag() { } } - assert!(!Settings::default().parse(["test"]).0.foo); - assert!(Settings::default().parse(["test", "--foo"]).0.foo); - assert!(Settings::default().parse(["test", "-f"]).0.foo); + assert!(!Settings::default().parse(["test"]).unwrap().0.foo); + assert!(Settings::default().parse(["test", "--foo"]).unwrap().0.foo); + assert!(Settings::default().parse(["test", "-f"]).unwrap().0.foo); } #[test] @@ -111,7 +111,7 @@ fn short_alias() { } } - assert!(Settings::default().parse(["test", "-b"]).0.foo); + assert!(Settings::default().parse(["test", "-b"]).unwrap().0.foo); } #[test] @@ -133,7 +133,7 @@ fn long_alias() { } } - assert!(Settings::default().parse(["test", "--bar"]).0.foo); + assert!(Settings::default().parse(["test", "--bar"]).unwrap().0.foo); } #[test] @@ -171,10 +171,22 @@ fn short_and_long_alias() { bar: true, }; - assert_eq!(Settings::default().parse(["test", "--bar"]).0, foo_true); - assert_eq!(Settings::default().parse(["test", "-b"]).0, foo_true); - assert_eq!(Settings::default().parse(["test", "--foo"]).0, bar_true); - assert_eq!(Settings::default().parse(["test", "-f"]).0, bar_true); + assert_eq!( + Settings::default().parse(["test", "--bar"]).unwrap().0, + foo_true + ); + assert_eq!( + Settings::default().parse(["test", "-b"]).unwrap().0, + foo_true + ); + assert_eq!( + Settings::default().parse(["test", "--foo"]).unwrap().0, + bar_true + ); + assert_eq!( + Settings::default().parse(["test", "-f"]).unwrap().0, + bar_true + ); } #[test] @@ -217,7 +229,7 @@ fn xyz_map_to_abc() { } assert_eq!( - Settings::default().parse(["test", "-x"]).0, + Settings::default().parse(["test", "-x"]).unwrap().0, Settings { a: true, b: true, @@ -226,7 +238,7 @@ fn xyz_map_to_abc() { ); assert_eq!( - Settings::default().parse(["test", "-y"]).0, + Settings::default().parse(["test", "-y"]).unwrap().0, Settings { a: false, b: true, @@ -235,7 +247,7 @@ fn xyz_map_to_abc() { ); assert_eq!( - Settings::default().parse(["test", "-xy"]).0, + Settings::default().parse(["test", "-xy"]).unwrap().0, Settings { a: true, b: true, @@ -244,7 +256,7 @@ fn xyz_map_to_abc() { ); assert_eq!( - Settings::default().parse(["test", "-z"]).0, + Settings::default().parse(["test", "-z"]).unwrap().0, Settings { a: true, b: true, @@ -281,6 +293,7 @@ fn non_rust_ident() { assert_eq!( Settings::default() .parse(["test", "--foo-bar", "--super"]) + .unwrap() .0, Settings { a: true, b: true } ) @@ -304,7 +317,7 @@ fn number_flag() { } } - assert!(Settings::default().parse(["test", "-1"]).0.one) + assert!(Settings::default().parse(["test", "-1"]).unwrap().0.one) } #[test] @@ -331,12 +344,24 @@ fn false_bool() { } } - assert!(Settings::default().parse(["test", "-a"]).0.foo); - assert!(!Settings::default().parse(["test", "-b"]).0.foo); - assert!(!Settings::default().parse(["test", "-ab"]).0.foo); - assert!(Settings::default().parse(["test", "-ba"]).0.foo); - assert!(!Settings::default().parse(["test", "-a", "-b"]).0.foo); - assert!(Settings::default().parse(["test", "-b", "-a"]).0.foo); + assert!(Settings::default().parse(["test", "-a"]).unwrap().0.foo); + assert!(!Settings::default().parse(["test", "-b"]).unwrap().0.foo); + assert!(!Settings::default().parse(["test", "-ab"]).unwrap().0.foo); + assert!(Settings::default().parse(["test", "-ba"]).unwrap().0.foo); + assert!( + !Settings::default() + .parse(["test", "-a", "-b"]) + .unwrap() + .0 + .foo + ); + assert!( + Settings::default() + .parse(["test", "-b", "-a"]) + .unwrap() + .0 + .foo + ); } #[test] @@ -358,9 +383,30 @@ fn verbosity() { } } - assert_eq!(Settings::default().parse(["test", "-v"]).0.verbosity, 1); - assert_eq!(Settings::default().parse(["test", "-vv"]).0.verbosity, 2); - assert_eq!(Settings::default().parse(["test", "-vvv"]).0.verbosity, 3); + assert_eq!( + Settings::default() + .parse(["test", "-v"]) + .unwrap() + .0 + .verbosity, + 1 + ); + assert_eq!( + Settings::default() + .parse(["test", "-vv"]) + .unwrap() + .0 + .verbosity, + 2 + ); + assert_eq!( + Settings::default() + .parse(["test", "-vvv"]) + .unwrap() + .0 + .verbosity, + 3 + ); } #[test] @@ -392,10 +438,22 @@ fn infer_long_args() { } } - assert!(Settings::default().parse(["test", "--all"]).0.all); - assert!(Settings::default().parse(["test", "--alm"]).0.almost_all); - assert!(Settings::default().parse(["test", "--au"]).0.author); - assert!(Settings::default().try_parse(["test", "--a"]).is_err()); + assert!(Settings::default().parse(["test", "--all"]).unwrap().0.all); + assert!( + Settings::default() + .parse(["test", "--alm"]) + .unwrap() + .0 + .almost_all + ); + assert!( + Settings::default() + .parse(["test", "--au"]) + .unwrap() + .0 + .author + ); + assert!(Settings::default().parse(["test", "--a"]).is_err()); } #[test] @@ -433,13 +491,16 @@ fn enum_flag() { } } - assert_eq!(Settings::default().parse(["test"]).0.foo, SomeEnum::Foo); assert_eq!( - Settings::default().parse(["test", "--bar"]).0.foo, + Settings::default().parse(["test"]).unwrap().0.foo, + SomeEnum::Foo + ); + assert_eq!( + Settings::default().parse(["test", "--bar"]).unwrap().0.foo, SomeEnum::Bar ); assert_eq!( - Settings::default().parse(["test", "--baz"]).0.foo, + Settings::default().parse(["test", "--baz"]).unwrap().0.foo, SomeEnum::Baz, ); } diff --git a/tests/options.rs b/tests/options.rs index 4a328d5..2a41f27 100644 --- a/tests/options.rs +++ b/tests/options.rs @@ -24,6 +24,7 @@ fn string_option() { assert_eq!( Settings::default() .parse(["test", "--message=hello"]) + .unwrap() .0 .message, "hello" @@ -61,13 +62,18 @@ fn enum_option() { } assert_eq!( - Settings::default().parse(["test", "--format=bar"]).0.format, + Settings::default() + .parse(["test", "--format=bar"]) + .unwrap() + .0 + .format, Format::Bar ); assert_eq!( Settings::default() .parse(["test", "--format", "baz"]) + .unwrap() .0 .format, Format::Baz @@ -103,11 +109,19 @@ fn enum_option_with_fields() { } assert_eq!( - Settings::default().parse(["test", "-i=thin"]).0.indent, + Settings::default() + .parse(["test", "-i=thin"]) + .unwrap() + .0 + .indent, Indent::Spaces(4) ); assert_eq!( - Settings::default().parse(["test", "-i=wide"]).0.indent, + Settings::default() + .parse(["test", "-i=wide"]) + .unwrap() + .0 + .indent, Indent::Spaces(8) ); } @@ -152,11 +166,19 @@ fn enum_with_complex_from_value() { } assert_eq!( - Settings::default().parse(["test", "-i=tabs"]).0.indent, + Settings::default() + .parse(["test", "-i=tabs"]) + .unwrap() + .0 + .indent, Indent::Tabs ); assert_eq!( - Settings::default().parse(["test", "-i=4"]).0.indent, + Settings::default() + .parse(["test", "-i=4"]) + .unwrap() + .0 + .indent, Indent::Spaces(4) ); } @@ -192,30 +214,51 @@ fn color() { } assert_eq!( - Settings::default().parse(["test", "--color=yes"]).0.color, + Settings::default() + .parse(["test", "--color=yes"]) + .unwrap() + .0 + .color, Color::Always ); assert_eq!( Settings::default() .parse(["test", "--color=always"]) + .unwrap() .0 .color, Color::Always ); assert_eq!( - Settings::default().parse(["test", "--color=no"]).0.color, + Settings::default() + .parse(["test", "--color=no"]) + .unwrap() + .0 + .color, Color::Never ); assert_eq!( - Settings::default().parse(["test", "--color=never"]).0.color, + Settings::default() + .parse(["test", "--color=never"]) + .unwrap() + .0 + .color, Color::Never ); assert_eq!( - Settings::default().parse(["test", "--color=auto"]).0.color, + Settings::default() + .parse(["test", "--color=auto"]) + .unwrap() + .0 + .color, Color::Auto ); assert_eq!( - Settings::default().parse(["test", "--color"]).0.color, + Settings::default() + .parse(["test", "--color"]) + .unwrap() + .0 + .color, Color::Always ) } @@ -252,8 +295,9 @@ fn actions() { } } - let (settings, _operands) = - Settings::default().parse(["test", "-m=Hello", "-m=World", "--send"]); + let (settings, _operands) = Settings::default() + .parse(["test", "-m=Hello", "-m=World", "--send"]) + .unwrap(); assert_eq!(settings.messages, vec!["Hello", "World"]); assert_eq!(settings.last_message, "World"); assert!(settings.send); @@ -281,8 +325,14 @@ fn width() { } } - assert_eq!(Settings::default().parse(["test", "-w=0"]).0.width, None); - assert_eq!(Settings::default().parse(["test", "-w=1"]).0.width, Some(1)); + assert_eq!( + Settings::default().parse(["test", "-w=0"]).unwrap().0.width, + None + ); + assert_eq!( + Settings::default().parse(["test", "-w=1"]).unwrap().0.width, + Some(1) + ); } #[test] @@ -333,17 +383,47 @@ fn integers() { } } - assert_eq!(Settings::default().parse(["test", "--u8=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--u16=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--u32=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--u64=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--u128=5"]).0.n, 5); + assert_eq!( + Settings::default().parse(["test", "--u8=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--u16=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--u32=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--u64=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--u128=5"]).unwrap().0.n, + 5 + ); - assert_eq!(Settings::default().parse(["test", "--i8=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--i16=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--i32=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--i64=5"]).0.n, 5); - assert_eq!(Settings::default().parse(["test", "--i128=5"]).0.n, 5); + assert_eq!( + Settings::default().parse(["test", "--i8=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--i16=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--i32=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--i64=5"]).unwrap().0.n, + 5 + ); + assert_eq!( + Settings::default().parse(["test", "--i128=5"]).unwrap().0.n, + 5 + ); } #[test] @@ -379,23 +459,35 @@ fn ls_classify() { } } - assert_eq!(Settings::default().parse(["test"]).0.classify, When::Auto); + assert_eq!( + Settings::default().parse(["test"]).unwrap().0.classify, + When::Auto + ); assert_eq!( Settings::default() .parse(["test", "--classify=never"]) + .unwrap() .0 .classify, When::Never, ); assert_eq!( - Settings::default().parse(["test", "--classify"]).0.classify, + Settings::default() + .parse(["test", "--classify"]) + .unwrap() + .0 + .classify, When::Always, ); assert_eq!( - Settings::default().parse(["test", "-F"]).0.classify, + Settings::default() + .parse(["test", "-F"]) + .unwrap() + .0 + .classify, When::Always, ); - assert!(Settings::default().try_parse(["test", "-Falways"]).is_err()); + assert!(Settings::default().parse(["test", "-Falways"]).is_err()); } #[test] @@ -420,16 +512,16 @@ fn mktemp_tmpdir() { } } - let (settings, _operands) = Settings::default().parse(["test", "-p", "X"]); + let (settings, _operands) = Settings::default().parse(["test", "-p", "X"]).unwrap(); assert_eq!(settings.tmpdir.unwrap(), "X"); - let (settings, _operands) = Settings::default().parse(["test", "--tmpdir=X"]); + let (settings, _operands) = Settings::default().parse(["test", "--tmpdir=X"]).unwrap(); assert_eq!(settings.tmpdir.unwrap(), "X"); - let (settings, _operands) = Settings::default().parse(["test", "--tmpdir"]); + let (settings, _operands) = Settings::default().parse(["test", "--tmpdir"]).unwrap(); assert_eq!(settings.tmpdir.unwrap(), "/tmp"); - assert!(Settings::default().try_parse(["test", "-p"]).is_err()); + assert!(Settings::default().parse(["test", "-p"]).is_err()); } #[test] @@ -497,8 +589,17 @@ fn deprecated() { } } - assert_eq!(Settings::default().parse(["test", "-10"]).0.n1, 10usize); - assert!(Settings::default().try_parse(["test", "--10"]).is_err()); - assert_eq!(Settings::default().parse(["test", "+10"]).0.n2, 10isize); - assert_eq!(Settings::default().parse(["test", "+-10"]).0.n2, -10isize); + assert_eq!( + Settings::default().parse(["test", "-10"]).unwrap().0.n1, + 10usize + ); + assert!(Settings::default().parse(["test", "--10"]).is_err()); + assert_eq!( + Settings::default().parse(["test", "+10"]).unwrap().0.n2, + 10isize + ); + assert_eq!( + Settings::default().parse(["test", "+-10"]).unwrap().0.n2, + -10isize + ); } From c206234fa02618cf9f1b3848ba789a6ff51f01c9 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 19 Dec 2023 15:21:56 +0100 Subject: [PATCH 2/4] simplify external API --- src/lib.rs | 47 ++++++++--------------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ac971cd..780f7ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,9 +69,6 @@ pub enum Argument { /// Defines how the arguments are parsed. /// -/// If a type `T` implements this trait, we can construct an `ArgumentIter`, -/// meaning that we can parse the individual arguments to `T`.\ -/// /// Usually, this trait will be implemented via the /// [derive macro](derive@Arguments) and does not need to be implemented /// manually. @@ -79,19 +76,7 @@ pub trait Arguments: Sized { /// The exit code to exit the program with on error. const EXIT_CODE: i32; - /// Parse an iterator of arguments into an - /// [`ArgumentIter`](ArgumentIter). - fn parse(args: I) -> ArgumentIter - where - I: IntoIterator, - I::Item: Into, - { - ArgumentIter::::from_args(args) - } - /// Parse the next argument from the lexopt parser. - /// - /// This method is called by [`ArgumentIter::next_arg`]. fn next_arg(parser: &mut lexopt::Parser) -> Result>, ErrorKind>; /// Print the help string for this command. @@ -111,7 +96,7 @@ pub trait Arguments: Sized { I: IntoIterator, I::Item: Into, { - let mut iter = Self::parse(args); + let mut iter = ArgumentIter::::from_args(args); while iter.next_arg()?.is_some() {} Ok(()) } @@ -121,10 +106,7 @@ pub trait Arguments: Sized { } /// An iterator over arguments. -/// -/// Can be constructed by calling [`Arguments::parse`]. Usually, this method -/// won't be used directly, but is used internally in [`Options::parse`]. -pub struct ArgumentIter { +struct ArgumentIter { parser: lexopt::Parser, positional_arguments: Vec, t: PhantomData, @@ -150,11 +132,11 @@ impl ArgumentIter { })? { match arg { Argument::Help => { - self.help().unwrap(); + T::help(self.parser.bin_name().unwrap()).unwrap(); std::process::exit(0); } Argument::Version => { - print!("{}", self.version()); + print!("{}", T::version()); std::process::exit(0); } Argument::Positional(arg) => { @@ -165,18 +147,6 @@ impl ArgumentIter { } Ok(None) } - - fn get_positional_arguments(self) -> Vec { - self.positional_arguments - } - - fn help(&self) -> std::io::Result<()> { - T::help(self.parser.bin_name().unwrap()) - } - - fn version(&self) -> String { - T::version() - } } /// Defines the app settings by consuming [`Arguments`]. @@ -187,9 +157,8 @@ impl ArgumentIter { /// - the [`apply`](Options::apply) method, which defines to how map that /// type onto the options. /// -/// By default, the [`Options::parse`] method will -/// 1. repeatedly call [`ArgumentIter::next_arg`] and call [`Options::apply`] -/// on the result until the arguments are exhausted. +/// By default, the [`Options::parse`] method iterate over the arguments and +/// call [`Options::apply`] on the result until the arguments are exhausted. pub trait Options: Sized { /// Apply a single argument to the options. fn apply(&mut self, arg: Arg); @@ -215,11 +184,11 @@ pub trait Options: Sized { #[cfg(not(feature = "parse-is-complete"))] { - let mut iter = Arg::parse(args); + let mut iter = ArgumentIter::::from_args(args); while let Some(arg) = iter.next_arg()? { self.apply(arg); } - Ok((self, iter.get_positional_arguments())) + Ok((self, iter.positional_arguments)) } } From b3ee70b84cbb4ea74f8e9fc9165bafc2b30325f3 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 19 Dec 2023 15:29:20 +0100 Subject: [PATCH 3/4] make help() return a String --- derive/src/help.rs | 16 ++++++++-------- derive/src/lib.rs | 2 +- src/internal.rs | 17 ++++++++--------- src/lib.rs | 4 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/derive/src/help.rs b/derive/src/help.rs index a606ecf..77af149 100644 --- a/derive/src/help.rs +++ b/derive/src/help.rs @@ -74,27 +74,27 @@ pub fn help_string( } let options = if !options.is_empty() { - quote!(::uutils_args::internal::print_flags(&mut w, #indent, #width, [#(#options),*])?;) + quote!(::uutils_args::internal::print_flags(&mut w, #indent, #width, [#(#options),*]);) } else { quote!() }; quote!( - let mut w = ::std::io::stdout(); - use ::std::io::Write; + let mut w = String::new(); + use ::std::fmt::Write; writeln!(w, "{} {}", option_env!("CARGO_BIN_NAME").unwrap_or(env!("CARGO_PKG_NAME")), env!("CARGO_PKG_VERSION"), - )?; + ).unwrap(); - writeln!(w, "{}", #summary)?; + writeln!(w, "{}", #summary).unwrap(); - writeln!(w, "\nUsage:\n {}", format!(#usage, bin_name))?; + writeln!(w, "\nUsage:\n {}", format!(#usage, bin_name)).unwrap(); #options - writeln!(w, "{}", #after_options)?; - Ok(()) + writeln!(w, "{}", #after_options).unwrap(); + w ) } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 486530c..45b8df5 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -95,7 +95,7 @@ pub fn arguments(input: TokenStream) -> TokenStream { } } - fn help(bin_name: &str) -> ::std::io::Result<()> { + fn help(bin_name: &str) -> String { #help_string } diff --git a/src/internal.rs b/src/internal.rs index 412c737..b74dedd 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -14,7 +14,7 @@ use crate::error::ErrorKind; use crate::value::Value; use std::{ ffi::{OsStr, OsString}, - io::Write, + fmt::Write, }; /// Parses an echo-style positional argument @@ -118,33 +118,32 @@ pub fn print_flags( indent_size: usize, width: usize, options: impl IntoIterator, -) -> std::io::Result<()> { +) { let indent = " ".repeat(indent_size); - writeln!(w, "\nOptions:")?; + writeln!(w, "\nOptions:").unwrap(); for (flags, help_string) in options { let mut help_lines = help_string.lines(); - write!(w, "{}{}", &indent, &flags)?; + write!(w, "{}{}", &indent, &flags).unwrap(); if flags.len() <= width { let line = match help_lines.next() { Some(line) => line, None => { - writeln!(w)?; + writeln!(w).unwrap(); continue; } }; let help_indent = " ".repeat(width - flags.len() + 2); - writeln!(w, "{}{}", help_indent, line)?; + writeln!(w, "{}{}", help_indent, line).unwrap(); } else { - writeln!(w)?; + writeln!(w).unwrap(); } let help_indent = " ".repeat(width + indent_size + 2); for line in help_lines { - writeln!(w, "{}{}", help_indent, line)?; + writeln!(w, "{}{}", help_indent, line).unwrap(); } } - Ok(()) } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index 780f7ac..694bcdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,7 +82,7 @@ pub trait Arguments: Sized { /// Print the help string for this command. /// /// The `bin_name` specifies the name that executable was called with. - fn help(bin_name: &str) -> std::io::Result<()>; + fn help(bin_name: &str) -> String; /// Get the version string for this command. fn version() -> String; @@ -132,7 +132,7 @@ impl ArgumentIter { })? { match arg { Argument::Help => { - T::help(self.parser.bin_name().unwrap()).unwrap(); + print!("{}", T::help(self.parser.bin_name().unwrap())); std::process::exit(0); } Argument::Version => { From 922979135d815888a519c9a99151d18e3963c64c Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 19 Dec 2023 16:34:05 +0100 Subject: [PATCH 4/4] make value derive not fail without #[value] --- derive/src/lib.rs | 11 +++++++---- tests/options.rs | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 45b8df5..3b2fbdd 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -150,16 +150,18 @@ pub fn value(input: TokenStream) -> TokenStream { options.push(quote!(&[#(#keys),*])); let stmt = if let Some(v) = value { - quote!(#(| #keys)* => #v) + quote!(#(| #keys)* => #v,) } else { let mut v = variant.clone(); v.attrs = vec![]; - quote!(#(| #keys)* => Self::#v) + quote!(#(| #keys)* => Self::#v,) }; match_arms.push(stmt); } } + let keys_len = all_keys.len(); + let expanded = quote!( impl #impl_generics Value for #name #ty_generics #where_clause { fn from_value(value: &::std::ffi::OsStr) -> ::uutils_args::ValueResult { @@ -191,15 +193,16 @@ pub fn value(input: TokenStream) -> TokenStream { }; Ok(match opt { - #(#match_arms),*, + #(#match_arms)* _ => unreachable!("Should be caught by (None, []) case above.") }) } #[cfg(feature = "complete")] fn value_hint() -> ::uutils_args_complete::ValueHint { + let keys: [&str; #keys_len] = [#(#all_keys),*]; ::uutils_args_complete::ValueHint::Strings( - [#(#all_keys),*] + keys .into_iter() .map(ToString::to_string) .collect() diff --git a/tests/options.rs b/tests/options.rs index 2a41f27..1f1e972 100644 --- a/tests/options.rs +++ b/tests/options.rs @@ -603,3 +603,27 @@ fn deprecated() { -10isize ); } + +#[test] +#[allow(unreachable_code)] +fn empty_value() { + // We just check that this compiles + #[derive(Value)] + enum V {} + + #[derive(Arguments)] + enum Arg { + #[arg("--val=VAL")] + Val(V), + } + + struct Settings {} + + impl Options for Settings { + fn apply(&mut self, arg: Arg) { + match arg { + Arg::Val(_) => {} + } + } + } +}