remove the Initial trait

This commit is contained in:
Terts Diepraam
2023-12-05 16:05:59 +01:00
parent 8cf652dfd2
commit 2ba46a2ae9
21 changed files with 388 additions and 486 deletions
+19 -25
View File
@@ -41,16 +41,16 @@ For more information on these traits, see their respective documentation:
Below is a minimal example of a full CLI application using this library.
```rust
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Arguments)]
enum Arg {
// The doc strings below will be part of the `--help` text
// First we define a simple flag:
/// Do not transform input text to uppercase
#[arg("-n", "--no-caps")]
NoCaps,
/// Transform input text to uppercase
#[arg("-c", "--caps")]
Caps,
// This option takes a value:
/// Add exclamation marks to output
#[arg("-e N", "--exclaim=N")]
@@ -62,10 +62,8 @@ enum Arg {
Text(String),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
// We can change the default value with the field attribute.
#[initial(true)]
caps: bool,
exclamation_marks: u8,
text: String,
@@ -76,7 +74,7 @@ struct Settings {
impl Options<Arg> for Settings {
fn apply(&mut self, arg: Arg) {
match arg {
Arg::NoCaps => self.caps = false,
Arg::Caps => self.caps = true,
Arg::ExclamationMarks(n) => self.exclamation_marks += n,
Arg::Text(s) => {
if self.text.is_empty() {
@@ -91,7 +89,7 @@ impl Options<Arg> for Settings {
}
fn run(args: &'static [&'static str]) -> String {
let s = Settings::parse(args);
let s = Settings::default().parse(args);
let mut output = if s.caps {
s.text.to_uppercase()
} else {
@@ -104,24 +102,20 @@ fn run(args: &'static [&'static str]) -> String {
}
// The first argument is the binary name. In this example it's ignored.
assert_eq!(run(&["shout", "hello"]), "HELLO");
assert_eq!(run(&["shout", "-e3", "hello"]), "HELLO!!!");
assert_eq!(run(&["shout", "-e", "3", "hello"]), "HELLO!!!");
assert_eq!(run(&["shout", "--no-caps", "hello"]), "hello");
assert_eq!(run(&["shout", "-e3", "-n", "hello"]), "hello!!!");
assert_eq!(run(&["shout", "-e3", "hello", "world"]), "HELLO WORLD!!!");
assert_eq!(run(&["shout", "hello"]), "hello");
assert_eq!(run(&["shout", "-e3", "hello"]), "hello!!!");
assert_eq!(run(&["shout", "-e", "3", "hello"]), "hello!!!");
assert_eq!(run(&["shout", "--caps", "hello"]), "HELLO");
assert_eq!(run(&["shout", "-e3", "-c", "hello"]), "HELLO!!!");
assert_eq!(run(&["shout", "-e3", "-c", "hello", "world"]), "HELLO WORLD!!!");
```
## Additional functionality
## Value parsing
To make it easier to implement [`Arguments`] and [`Options`], there are
two additional traits:
- [`Initial`] is an alternative to the [`Default`] trait from the standard
library, with a richer derive macro.
- [`Value`] allows for easy parsing from `OsStr` to any type
implementing [`Value`]. This crate also provides a derive macro for
this trait.
To make it easier to implement [`Arguments`] and [`Options`], there is the
[`Value`] trait, which allows for easy parsing from `OsStr` to any type
implementing [`Value`]. This crate also provides a derive macro for
this trait.
## Examples
-136
View File
@@ -1,136 +0,0 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use syn::{
parse::{Parse, ParseStream},
parse_macro_input, Data, DeriveInput, Fields, Token,
};
use proc_macro::TokenStream;
use quote::quote;
use syn::{punctuated::Punctuated, Attribute, Expr, LitStr};
mod kw {
syn::custom_keyword!(env);
}
enum InitialArg {
Expr(Expr),
Env(String),
}
#[derive(Default)]
struct InitialField {
expr: Option<syn::Expr>,
env: Option<String>,
}
impl Parse for InitialArg {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.peek(kw::env) && input.peek2(Token![=]) {
input.parse::<kw::env>()?;
input.parse::<Token![=]>()?;
Ok(InitialArg::Env(input.parse::<LitStr>()?.value()))
} else {
Ok(InitialArg::Expr(input.parse::<Expr>()?))
}
}
}
impl InitialField {
fn from_attribute(attribute: &Attribute) -> syn::Result<Self> {
let mut _self = Self::default();
let args =
attribute.parse_args_with(Punctuated::<InitialArg, Token![,]>::parse_terminated)?;
for arg in args {
match arg {
InitialArg::Expr(e) => {
if _self.expr.is_some() {
panic!("Can only specify one initial expression")
}
_self.expr = Some(e);
}
InitialArg::Env(s) => {
if _self.expr.is_some() {
panic!("Can only specify one env variable")
}
_self.env = Some(s);
}
}
}
Ok(_self)
}
fn into_expr(self) -> proc_macro2::TokenStream {
let mut default_value = match self.expr {
Some(val) => quote!(#val),
None => quote!(::core::default::Default::default()),
};
if let Some(env_var) = self.env {
default_value = quote!(
::std::env::var_os(#env_var)
.and_then(|v| ::uutils_args::Value::from_value(&v).ok())
.unwrap_or(#default_value)
);
}
default_value
}
}
pub fn initial(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let function_body = match input.data {
Data::Struct(data) => initial_struct(data),
_ => panic!("Initial derive macro can only be used on structs"),
};
quote!(
impl #impl_generics Initial for #name #ty_generics #where_clause {
fn initial() -> Self {
#function_body
}
}
)
.into()
}
fn initial_struct(data: syn::DataStruct) -> proc_macro2::TokenStream {
let Fields::Named(fields) = data.fields else {
panic!("Fields must be named");
};
// The key of this map is a literal pattern and the value
// is whatever code needs to be run when that pattern is encountered.
let mut defaults = Vec::new();
for field in fields.named {
let ident = field.ident;
let field = parse_field_attr(&field.attrs);
let default_value = field.into_expr();
defaults.push(quote!(#ident: #default_value));
}
quote!(
Self {
#(#defaults),*
}
)
}
fn parse_field_attr(attrs: &[Attribute]) -> InitialField {
for attr in attrs {
if attr.path().is_ident("initial") {
return InitialField::from_attribute(attr).expect("Failed to parse initial attribute");
}
}
InitialField::default()
}
-6
View File
@@ -6,7 +6,6 @@ mod attributes;
mod flags;
mod help;
mod help_parser;
mod initial;
use argument::{
free_handling, long_handling, parse_argument, parse_arguments_attr, positional_handling,
@@ -19,11 +18,6 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data::Enum, DeriveInput};
#[proc_macro_derive(Initial, attributes(initial))]
pub fn initial(input: TokenStream) -> TokenStream {
initial::initial(input)
}
#[proc_macro_derive(Arguments, attributes(arg, arguments))]
pub fn arguments(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
+6 -6
View File
@@ -1,4 +1,4 @@
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
fn parse_minus(s: &str) -> Option<&str> {
let num = s.strip_prefix('-')?;
@@ -27,7 +27,7 @@ enum Arg {
Plus(isize),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
n1: usize,
n2: isize,
@@ -43,8 +43,8 @@ impl Options<Arg> for Settings {
}
fn main() {
assert_eq!(Settings::parse(["test", "-10"]).n1, 10usize);
assert!(Settings::try_parse(["test", "--10"]).is_err());
assert_eq!(Settings::parse(["test", "+10"]).n2, 10isize);
assert_eq!(Settings::parse(["test", "+-10"]).n2, -10isize);
assert_eq!(Settings::default().parse(["test", "-10"]).n1, 10usize);
assert!(Settings::default().try_parse(["test", "--10"]).is_err());
assert_eq!(Settings::default().parse(["test", "+10"]).n2, 10isize);
assert_eq!(Settings::default().parse(["test", "+-10"]).n2, -10isize);
}
+7 -4
View File
@@ -1,4 +1,4 @@
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Arguments)]
#[arguments(file = "examples/hello_world_help.md")]
@@ -20,10 +20,8 @@ enum Arg {
Hidden,
}
#[derive(Initial)]
struct Settings {
name: String,
#[initial(1)]
count: u8,
}
@@ -38,7 +36,12 @@ impl Options<Arg> for Settings {
}
fn main() -> Result<(), uutils_args::Error> {
let settings = Settings::parse(std::env::args_os());
let settings = Settings {
name: String::new(),
count: 1,
}
.parse(std::env::args_os());
for _ in 0..settings.count {
println!("Hello, {}!", settings.name);
}
+10 -26
View File
@@ -160,21 +160,6 @@ impl<T: Arguments> ArgumentIter<T> {
}
}
/// An alternative for the [`Default`] trait, with a more feature
/// packed derive macro.
///
/// The `Initial` trait is used by `Options` to construct the initial
/// state of the options before any arguments are parsed.
///
/// The [derive macro](derive@Initial) supports setting the initial
/// value per field and parsing the initial values from environment
/// variables. Otherwise, it will be equivalent to the derive macro
/// for the [`Default`] trait.
pub trait Initial: Sized {
/// Create the initial state of `Self`
fn initial() -> Self;
}
/// Defines the app settings by consuming [`Arguments`].
///
/// When implementing this trait, only two things need to be provided:
@@ -184,35 +169,34 @@ pub trait Initial: Sized {
/// type onto the options.
///
/// By default, the [`Options::parse`] method will
/// 1. create a new instance of `Self` using [`Initial::initial`],
/// 2. repeatedly call [`ArgumentIter::next_arg`] and call [`Options::apply`]
/// 1. repeatedly call [`ArgumentIter::next_arg`] and call [`Options::apply`]
/// on the result until the arguments are exhausted,
/// 3. and finally call [`Arguments::check_missing`].
pub trait Options<Arg: Arguments>: Sized + Initial {
/// 2. and finally call [`Arguments::check_missing`] to check whether all
/// required arguments were given.
pub trait Options<Arg: Arguments>: Sized {
/// Apply a single argument to the options.
fn apply(&mut self, arg: Arg);
/// Parse an iterator of arguments into
fn parse<I>(args: I) -> Self
/// Parse an iterator of arguments into the options
fn parse<I>(self, args: I) -> Self
where
I: IntoIterator + 'static,
I::Item: Into<OsString>,
{
exit_if_err(Self::try_parse(args), Arg::EXIT_CODE)
exit_if_err(self.try_parse(args), Arg::EXIT_CODE)
}
fn try_parse<I>(args: I) -> Result<Self, Error>
fn try_parse<I>(mut self, args: I) -> Result<Self, Error>
where
I: IntoIterator + 'static,
I::Item: Into<OsString>,
{
let mut _self = Self::initial();
let mut iter = Arg::parse(args);
while let Some(arg) = iter.next_arg()? {
_self.apply(arg);
self.apply(arg);
}
Arg::check_missing(iter.positional_idx)?;
Ok(_self)
Ok(self)
}
}
+37 -19
View File
@@ -1,5 +1,5 @@
use std::path::{Path, PathBuf};
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Clone, Arguments)]
enum Arg {
@@ -39,7 +39,7 @@ enum CheckOutput {
Status,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
binary: bool,
check: bool,
@@ -67,48 +67,66 @@ impl Options<Arg> for Settings {
#[test]
fn binary() {
assert!(!Settings::parse(["b2sum"]).binary);
assert!(!Settings::parse(["b2sum", "--text"]).binary);
assert!(!Settings::parse(["b2sum", "-t"]).binary);
assert!(!Settings::parse(["b2sum", "--binary", "--text"]).binary);
assert!(!Settings::parse(["b2sum", "-b", "-t"]).binary);
assert!(!Settings::default().parse(["b2sum"]).binary);
assert!(!Settings::default().parse(["b2sum", "--text"]).binary);
assert!(!Settings::default().parse(["b2sum", "-t"]).binary);
assert!(
!Settings::default()
.parse(["b2sum", "--binary", "--text"])
.binary
);
assert!(!Settings::default().parse(["b2sum", "-b", "-t"]).binary);
assert!(Settings::parse(["b2sum", "--binary"]).binary);
assert!(Settings::parse(["b2sum", "-b"]).binary);
assert!(Settings::parse(["b2sum", "--text", "--binary"]).binary);
assert!(Settings::parse(["b2sum", "-t", "-b"]).binary);
assert!(Settings::default().parse(["b2sum", "--binary"]).binary);
assert!(Settings::default().parse(["b2sum", "-b"]).binary);
assert!(
Settings::default()
.parse(["b2sum", "--text", "--binary"])
.binary
);
assert!(Settings::default().parse(["b2sum", "-t", "-b"]).binary);
}
#[test]
fn check_output() {
assert_eq!(
Settings::parse(["b2sum", "--warn"]).check_output,
Settings::default().parse(["b2sum", "--warn"]).check_output,
CheckOutput::Warn
);
assert_eq!(
Settings::parse(["b2sum", "--quiet"]).check_output,
Settings::default().parse(["b2sum", "--quiet"]).check_output,
CheckOutput::Quiet
);
assert_eq!(
Settings::parse(["b2sum", "--status"]).check_output,
Settings::default()
.parse(["b2sum", "--status"])
.check_output,
CheckOutput::Status
);
assert_eq!(
Settings::parse(["b2sum", "--status", "--warn"]).check_output,
Settings::default()
.parse(["b2sum", "--status", "--warn"])
.check_output,
CheckOutput::Warn
);
assert_eq!(
Settings::parse(["b2sum", "--status", "--warn"]).check_output,
Settings::default()
.parse(["b2sum", "--status", "--warn"])
.check_output,
CheckOutput::Warn
);
assert_eq!(
Settings::parse(["b2sum", "--warn", "--quiet"]).check_output,
Settings::default()
.parse(["b2sum", "--warn", "--quiet"])
.check_output,
CheckOutput::Quiet
);
assert_eq!(
Settings::parse(["b2sum", "--quiet", "--status"]).check_output,
Settings::default()
.parse(["b2sum", "--quiet", "--status"])
.check_output,
CheckOutput::Status
);
}
@@ -116,7 +134,7 @@ fn check_output() {
#[test]
fn files() {
assert_eq!(
Settings::parse(["b2sum", "foo", "bar"]).files,
Settings::default().parse(["b2sum", "foo", "bar"]).files,
vec![Path::new("foo"), Path::new("bar")]
);
}
+22 -7
View File
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Clone, Arguments)]
enum Arg {
@@ -17,15 +17,24 @@ enum Arg {
File(PathBuf),
}
#[derive(Initial)]
struct Settings {
decode: bool,
ignore_garbage: bool,
#[initial(Some(76))]
wrap: Option<usize>,
file: Option<PathBuf>,
}
impl Default for Settings {
fn default() -> Self {
Self {
wrap: Some(76),
decode: Default::default(),
ignore_garbage: Default::default(),
file: Default::default(),
}
}
}
impl Options<Arg> for Settings {
fn apply(&mut self, arg: Arg) {
match arg {
@@ -40,8 +49,14 @@ impl Options<Arg> for Settings {
#[test]
fn wrap() {
assert_eq!(Settings::parse(["base32"]).wrap, Some(76));
assert_eq!(Settings::parse(["base32", "-w0"]).wrap, None);
assert_eq!(Settings::parse(["base32", "-w100"]).wrap, Some(100));
assert_eq!(Settings::parse(["base32", "--wrap=100"]).wrap, Some(100));
assert_eq!(Settings::default().parse(["base32"]).wrap, Some(76));
assert_eq!(Settings::default().parse(["base32", "-w0"]).wrap, None);
assert_eq!(
Settings::default().parse(["base32", "-w100"]).wrap,
Some(100)
);
assert_eq!(
Settings::default().parse(["base32", "--wrap=100"]).wrap,
Some(100)
);
}
+3 -3
View File
@@ -1,4 +1,4 @@
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Clone, Arguments)]
enum Arg {
@@ -15,7 +15,7 @@ enum Arg {
Names(Vec<String>),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
multiple: bool,
suffix: String,
@@ -38,7 +38,7 @@ impl Options<Arg> for Settings {
}
fn parse(args: &'static [&'static str]) -> Settings {
let mut settings = Settings::parse(args);
let mut settings = Settings::default().parse(args);
if !settings.multiple {
assert_eq!(settings.names.len(), 2);
settings.suffix = settings.names.pop().unwrap();
+10 -10
View File
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Default)]
enum NumberingMode {
@@ -43,7 +43,7 @@ enum Arg {
File(PathBuf),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
show_tabs: bool,
show_ends: bool,
@@ -82,27 +82,27 @@ impl Options<Arg> for Settings {
#[test]
fn show() {
let s = Settings::parse(["cat", "-v"]);
let s = Settings::default().parse(["cat", "-v"]);
assert!(!s.show_ends && !s.show_tabs && s.show_nonprinting);
let s = Settings::parse(["cat", "-E"]);
let s = Settings::default().parse(["cat", "-E"]);
assert!(s.show_ends && !s.show_tabs && !s.show_nonprinting);
let s = Settings::parse(["cat", "-T"]);
let s = Settings::default().parse(["cat", "-T"]);
assert!(!s.show_ends && s.show_tabs && !s.show_nonprinting);
let s = Settings::parse(["cat", "-e"]);
let s = Settings::default().parse(["cat", "-e"]);
assert!(s.show_ends && !s.show_tabs && s.show_nonprinting);
let s = Settings::parse(["cat", "-t"]);
let s = Settings::default().parse(["cat", "-t"]);
assert!(!s.show_ends && s.show_tabs && s.show_nonprinting);
let s = Settings::parse(["cat", "-A"]);
let s = Settings::default().parse(["cat", "-A"]);
assert!(s.show_ends && s.show_tabs && s.show_nonprinting);
let s = Settings::parse(["cat", "-te"]);
let s = Settings::default().parse(["cat", "-te"]);
assert!(s.show_ends && s.show_tabs && s.show_nonprinting);
let s = Settings::parse(["cat", "-vET"]);
let s = Settings::default().parse(["cat", "-vET"]);
assert!(s.show_ends && s.show_tabs && s.show_nonprinting);
}
+41 -17
View File
@@ -1,7 +1,7 @@
// spell-checker:ignore noxfer infile outfile iseek oseek conv iflag oflag iflags oflags
use std::path::PathBuf;
use uutils_args::{Arguments, Initial, Options, Value};
use uutils_args::{Arguments, Options, Value};
#[derive(Value, Debug, PartialEq, Eq)]
enum StatusLevel {
@@ -56,13 +56,11 @@ enum Arg {
Oflag(String),
}
#[derive(Initial, Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
struct Settings {
infile: Option<PathBuf>,
outfile: Option<PathBuf>,
#[initial(512)]
ibs: usize,
#[initial(512)]
obs: usize,
skip: u64,
seek: u64,
@@ -74,6 +72,25 @@ struct Settings {
status: Option<StatusLevel>,
}
impl Default for Settings {
fn default() -> Self {
Self {
ibs: 512,
obs: 512,
infile: Default::default(),
outfile: Default::default(),
skip: Default::default(),
seek: Default::default(),
count: Default::default(),
_iconv: Default::default(),
_iflags: Default::default(),
_oconv: Default::default(),
_oflags: Default::default(),
status: Default::default(),
}
}
}
impl Options<Arg> for Settings {
fn apply(&mut self, arg: Arg) {
match arg {
@@ -99,16 +116,19 @@ impl Options<Arg> for Settings {
#[test]
fn empty() {
assert_eq!(Settings::try_parse(["dd"]).unwrap(), Settings::initial())
assert_eq!(
Settings::default().try_parse(["dd"]).unwrap(),
Settings::default()
)
}
#[test]
fn infile() {
assert_eq!(
Settings::try_parse(["dd", "if=hello"]).unwrap(),
Settings::default().try_parse(["dd", "if=hello"]).unwrap(),
Settings {
infile: Some(PathBuf::from("hello")),
..Settings::initial()
..Settings::default()
}
)
}
@@ -116,10 +136,10 @@ fn infile() {
#[test]
fn outfile() {
assert_eq!(
Settings::try_parse(["dd", "of=hello"]).unwrap(),
Settings::default().try_parse(["dd", "of=hello"]).unwrap(),
Settings {
outfile: Some(PathBuf::from("hello")),
..Settings::initial()
..Settings::default()
}
)
}
@@ -127,35 +147,39 @@ fn outfile() {
#[test]
fn bs() {
assert_eq!(
Settings::try_parse(["dd", "ibs=1"]).unwrap(),
Settings::default().try_parse(["dd", "ibs=1"]).unwrap(),
Settings {
ibs: 1,
obs: 512,
..Settings::initial()
..Settings::default()
}
);
assert_eq!(
Settings::try_parse(["dd", "obs=1"]).unwrap(),
Settings::default().try_parse(["dd", "obs=1"]).unwrap(),
Settings {
ibs: 512,
obs: 1,
..Settings::initial()
..Settings::default()
}
);
assert_eq!(
Settings::try_parse(["dd", "ibs=10", "obs=1"]).unwrap(),
Settings::default()
.try_parse(["dd", "ibs=10", "obs=1"])
.unwrap(),
Settings {
ibs: 10,
obs: 1,
..Settings::initial()
..Settings::default()
}
);
assert_eq!(
Settings::try_parse(["dd", "ibs=10", "bs=1"]).unwrap(),
Settings::default()
.try_parse(["dd", "ibs=10", "bs=1"])
.unwrap(),
Settings {
ibs: 1,
obs: 1,
..Settings::initial()
..Settings::default()
}
)
}
+5 -5
View File
@@ -1,5 +1,5 @@
use std::ffi::OsString;
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Arguments)]
#[arguments(parse_echo_style)]
@@ -20,7 +20,7 @@ enum Arg {
String(Vec<OsString>),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
trailing_newline: bool,
escape: bool,
@@ -43,16 +43,16 @@ impl Options<Arg> for Settings {
#[test]
fn double_hyphen() {
let s = Settings::parse(["echo", "--"]);
let s = Settings::default().parse(["echo", "--"]);
assert_eq!(s.strings, vec![OsString::from("--")]);
let s = Settings::parse(["echo", "--", "-n"]);
let s = Settings::default().parse(["echo", "--", "-n"]);
assert_eq!(s.strings, vec![OsString::from("--"), OsString::from("-n")]);
}
#[test]
#[ignore]
fn nonexistent_options_are_values() {
let s = Settings::parse(["echo", "-f"]);
let s = Settings::default().parse(["echo", "-f"]);
assert_eq!(s.strings, vec![OsString::from("-f")]);
}
+3 -3
View File
@@ -1,6 +1,6 @@
use std::{ffi::OsString, path::PathBuf};
use uutils_args::{Arguments, Initial, Options, Value};
use uutils_args::{Arguments, Options, Value};
// This format is way to specific to implement using a library. Basically, any
// deviation should be return `None` to indicate that we're not using the
@@ -179,7 +179,7 @@ pub enum Mode {
Lines,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
mode: Mode,
number: SigNum,
@@ -215,7 +215,7 @@ where
{
match parse_deprecated(iter.clone()) {
Some(s) => Ok(s),
None => Settings::try_parse(iter),
None => Settings::default().try_parse(iter),
}
}
+56 -27
View File
@@ -1,5 +1,5 @@
use std::path::PathBuf;
use uutils_args::{Arguments, Initial, Options, Value};
use uutils_args::{Arguments, Options, Value};
#[derive(Default, Debug, PartialEq, Eq, Value)]
enum Format {
@@ -302,7 +302,7 @@ fn default_terminal_size() -> u16 {
80
}
#[derive(Initial, Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
struct Settings {
format: Format,
files: Vec<PathBuf>,
@@ -322,20 +322,49 @@ struct Settings {
long_numeric_uid_gid: bool,
// alloc_size: bool,
// block_size: Option<u64>,
#[initial(default_terminal_size())]
width: u16,
quoting_style: QuotingStyle,
indicator_style: IndicatorStyle,
// time_style: TimeStyle,
context: bool,
group_directories_first: bool,
#[initial('\n')]
eol: char,
which_files: Files,
ignore_backups: bool,
hide_control_chars: bool,
}
impl Default for Settings {
fn default() -> Self {
Self {
eol: '\n',
width: default_terminal_size(),
format: Default::default(),
files: Default::default(),
sort: Default::default(),
recursive: Default::default(),
reverse: Default::default(),
dereference: Default::default(),
ignore_patterns: Default::default(),
directory: Default::default(),
time: Default::default(),
inode: Default::default(),
color: Default::default(),
long_author: Default::default(),
long_no_group: Default::default(),
long_no_owner: Default::default(),
long_numeric_uid_gid: Default::default(),
quoting_style: Default::default(),
indicator_style: Default::default(),
context: Default::default(),
group_directories_first: Default::default(),
which_files: Default::default(),
ignore_backups: Default::default(),
hide_control_chars: Default::default(),
}
}
}
impl Options<Arg> for Settings {
fn apply(&mut self, arg: Arg) {
match arg {
@@ -401,7 +430,7 @@ impl Options<Arg> for Settings {
#[test]
fn default() {
assert_eq!(
Settings::parse(["ls"]),
Settings::default().parse(["ls"]),
Settings {
format: Format::Columns,
files: Vec::new(),
@@ -433,87 +462,87 @@ fn default() {
#[test]
fn color() {
let s = Settings::parse(["ls", "--color"]);
let s = Settings::default().parse(["ls", "--color"]);
assert!(s.color);
let s = Settings::parse(["ls", "--color=always"]);
let s = Settings::default().parse(["ls", "--color=always"]);
assert!(s.color);
let s = Settings::parse(["ls", "--color=never"]);
let s = Settings::default().parse(["ls", "--color=never"]);
assert!(!s.color);
}
#[test]
fn format() {
let s = Settings::parse(["ls", "-l"]);
let s = Settings::default().parse(["ls", "-l"]);
assert_eq!(s.format, Format::Long);
let s = Settings::parse(["ls", "-m"]);
let s = Settings::default().parse(["ls", "-m"]);
assert_eq!(s.format, Format::Commas);
let s = Settings::parse(["ls", "--format=across"]);
let s = Settings::default().parse(["ls", "--format=across"]);
assert_eq!(s.format, Format::Across);
let s = Settings::parse(["ls", "--format=acr"]);
let s = Settings::default().parse(["ls", "--format=acr"]);
assert_eq!(s.format, Format::Across);
let s = Settings::parse(["ls", "-o"]);
let s = Settings::default().parse(["ls", "-o"]);
assert_eq!(s.format, Format::Long);
assert!(s.long_no_group && !s.long_no_owner && !s.long_numeric_uid_gid);
let s = Settings::parse(["ls", "-g"]);
let s = Settings::default().parse(["ls", "-g"]);
assert_eq!(s.format, Format::Long);
assert!(!s.long_no_group && s.long_no_owner && !s.long_numeric_uid_gid);
let s = Settings::parse(["ls", "-n"]);
let s = Settings::default().parse(["ls", "-n"]);
assert_eq!(s.format, Format::Long);
assert!(!s.long_no_group && !s.long_no_owner && s.long_numeric_uid_gid);
let s = Settings::parse(["ls", "-og"]);
let s = Settings::default().parse(["ls", "-og"]);
assert_eq!(s.format, Format::Long);
assert!(s.long_no_group && s.long_no_owner && !s.long_numeric_uid_gid);
let s = Settings::parse(["ls", "-on"]);
let s = Settings::default().parse(["ls", "-on"]);
assert_eq!(s.format, Format::Long);
assert!(s.long_no_group && !s.long_no_owner && s.long_numeric_uid_gid);
let s = Settings::parse(["ls", "-onCl"]);
let s = Settings::default().parse(["ls", "-onCl"]);
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 = Settings::parse(["ls", "--time=access"]);
let s = Settings::default().parse(["ls", "--time=access"]);
assert_eq!(s.time, Time::Access);
let s = Settings::parse(["ls", "--time=a"]);
let s = Settings::default().parse(["ls", "--time=a"]);
assert_eq!(s.time, Time::Access);
}
#[test]
fn classify() {
let s = Settings::parse(["ls", "--indicator-style=classify"]);
let s = Settings::default().parse(["ls", "--indicator-style=classify"]);
assert_eq!(s.indicator_style, IndicatorStyle::Classify);
let s = Settings::parse(["ls", "--classify"]);
let s = Settings::default().parse(["ls", "--classify"]);
assert_eq!(s.indicator_style, IndicatorStyle::Classify);
let s = Settings::parse(["ls", "--classify=always"]);
let s = Settings::default().parse(["ls", "--classify=always"]);
assert_eq!(s.indicator_style, IndicatorStyle::Classify);
let s = Settings::parse(["ls", "--classify=none"]);
let s = Settings::default().parse(["ls", "--classify=none"]);
assert_eq!(s.indicator_style, IndicatorStyle::None);
let s = Settings::parse(["ls", "-F"]);
let s = Settings::default().parse(["ls", "-F"]);
assert_eq!(s.indicator_style, IndicatorStyle::Classify);
}
#[test]
fn sort() {
let s = Settings::parse(["ls", "--sort=time"]);
let s = Settings::default().parse(["ls", "--sort=time"]);
assert_eq!(s.sort, Sort::Time);
let s = Settings::parse(["ls", "-X"]);
let s = Settings::default().parse(["ls", "-X"]);
assert_eq!(s.sort, Sort::Extension);
}
+12 -12
View File
@@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[derive(Clone, Arguments)]
enum Arg {
@@ -26,7 +26,7 @@ enum Arg {
Template(String),
}
#[derive(Default, Initial)]
#[derive(Default)]
struct Settings {
directory: bool,
dry_run: bool,
@@ -53,35 +53,35 @@ impl Options<Arg> for Settings {
#[test]
fn suffix() {
let s = Settings::parse(["mktemp", "--suffix=hello"]);
let s = Settings::default().parse(["mktemp", "--suffix=hello"]);
assert_eq!(s.suffix.unwrap(), "hello");
let s = Settings::parse(["mktemp", "--suffix="]);
let s = Settings::default().parse(["mktemp", "--suffix="]);
assert_eq!(s.suffix.unwrap(), "");
let s = Settings::parse(["mktemp", "--suffix="]);
let s = Settings::default().parse(["mktemp", "--suffix="]);
assert_eq!(s.suffix.unwrap(), "");
let s = Settings::parse(["mktemp"]);
let s = Settings::default().parse(["mktemp"]);
assert_eq!(s.suffix, None);
}
#[test]
fn tmpdir() {
let s = Settings::parse(["mktemp", "--tmpdir"]);
let s = Settings::default().parse(["mktemp", "--tmpdir"]);
assert_eq!(s.tmp_dir.unwrap(), Path::new("."));
let s = Settings::parse(["mktemp", "--tmpdir="]);
let s = Settings::default().parse(["mktemp", "--tmpdir="]);
assert_eq!(s.tmp_dir.unwrap(), Path::new(""));
let s = Settings::parse(["mktemp", "-p", "foo"]);
let s = Settings::default().parse(["mktemp", "-p", "foo"]);
assert_eq!(s.tmp_dir.unwrap(), Path::new("foo"));
let s = Settings::parse(["mktemp", "-pfoo"]);
let s = Settings::default().parse(["mktemp", "-pfoo"]);
assert_eq!(s.tmp_dir.unwrap(), Path::new("foo"));
let s = Settings::parse(["mktemp", "-p", ""]);
let s = Settings::default().parse(["mktemp", "-p", ""]);
assert_eq!(s.tmp_dir.unwrap(), Path::new(""));
assert!(Settings::try_parse(["mktemp", "-p"]).is_err());
assert!(Settings::default().try_parse(["mktemp", "-p"]).is_err());
}
+4 -4
View File
@@ -1,6 +1,6 @@
use std::{ffi::OsString, path::PathBuf};
use uutils_args::{Arguments, Initial, Options, Value};
use uutils_args::{Arguments, Options, Value};
// This format is way to specific to implement using a library. Basically, any
// deviation should be return `None` to indicate that we're not using the
@@ -100,7 +100,7 @@ where
mode,
follow,
inputs: vec![input.into().into()],
..Settings::initial()
..Settings::default()
})
}
@@ -228,7 +228,7 @@ pub enum Mode {
Lines,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
follow: Option<FollowMode>,
max_unchanged_stats: u32,
@@ -280,7 +280,7 @@ where
{
match parse_deprecated(iter.clone()) {
Some(s) => Ok(s),
None => Settings::try_parse(iter),
None => Settings::default().try_parse(iter),
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ enum Delimiters {
Both,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
repeats_only: bool,
uniques_only: bool,
-55
View File
@@ -1,55 +0,0 @@
use uutils_args::{Arguments, Initial, Options};
#[test]
fn true_default() {
#[derive(Arguments)]
enum Arg {
#[arg("--foo")]
Foo,
}
#[derive(Initial)]
struct Settings {
#[initial(true)]
foo: bool,
}
impl Options<Arg> for Settings {
fn apply(&mut self, Arg::Foo: Arg) {
self.foo = false;
}
}
assert!(Settings::parse(["test"]).foo);
assert!(!Settings::parse(["test", "--foo"]).foo);
}
#[test]
fn env_var_string() {
#[derive(Arguments)]
enum Arg {
#[arg("--foo=MSG")]
Foo(String),
}
#[derive(Initial)]
struct Settings {
#[initial(env = "FOO")]
foo: String,
}
impl Options<Arg> for Settings {
fn apply(&mut self, Arg::Foo(x): Arg) {
self.foo = x;
}
}
std::env::set_var("FOO", "one");
assert_eq!(Settings::parse(["test"]).foo, "one");
std::env::set_var("FOO", "two");
assert_eq!(Settings::parse(["test"]).foo, "two");
std::env::remove_var("FOO");
assert_eq!(Settings::parse(["test"]).foo, "");
}
+59 -50
View File
@@ -1,4 +1,4 @@
use uutils_args::{Arguments, Initial, Options};
use uutils_args::{Arguments, Options};
#[test]
fn one_flag() {
@@ -8,7 +8,7 @@ fn one_flag() {
Foo,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: bool,
}
@@ -21,7 +21,7 @@ fn one_flag() {
}
}
let settings = Settings::parse(["test", "-f"]);
let settings = Settings::default().parse(["test", "-f"]);
assert!(settings.foo);
}
@@ -35,7 +35,7 @@ fn two_flags() {
B,
}
#[derive(Initial, PartialEq, Eq, Debug)]
#[derive(Default, PartialEq, Eq, Debug)]
struct Settings {
a: bool,
b: bool,
@@ -51,16 +51,19 @@ fn two_flags() {
}
assert_eq!(
Settings::parse(["test", "-a"]),
Settings::default().parse(["test", "-a"]),
Settings { a: true, b: false }
);
assert_eq!(Settings::parse(["test"]), Settings { a: false, b: false });
assert_eq!(
Settings::parse(["test", "-b"]),
Settings::default().parse(["test"]),
Settings { a: false, b: false }
);
assert_eq!(
Settings::default().parse(["test", "-b"]),
Settings { a: false, b: true }
);
assert_eq!(
Settings::parse(["test", "-a", "-b"]),
Settings::default().parse(["test", "-a", "-b"]),
Settings { a: true, b: true }
);
}
@@ -73,7 +76,7 @@ fn long_and_short_flag() {
Foo,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: bool,
}
@@ -84,9 +87,9 @@ fn long_and_short_flag() {
}
}
assert!(!Settings::parse(["test"]).foo);
assert!(Settings::parse(["test", "--foo"]).foo);
assert!(Settings::parse(["test", "-f"]).foo);
assert!(!Settings::default().parse(["test"]).foo);
assert!(Settings::default().parse(["test", "--foo"]).foo);
assert!(Settings::default().parse(["test", "-f"]).foo);
}
#[test]
@@ -97,7 +100,7 @@ fn short_alias() {
Foo,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: bool,
}
@@ -108,7 +111,7 @@ fn short_alias() {
}
}
assert!(Settings::parse(["test", "-b"]).foo);
assert!(Settings::default().parse(["test", "-b"]).foo);
}
#[test]
@@ -119,7 +122,7 @@ fn long_alias() {
Foo,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: bool,
}
@@ -130,7 +133,7 @@ fn long_alias() {
}
}
assert!(Settings::parse(["test", "--bar"]).foo);
assert!(Settings::default().parse(["test", "--bar"]).foo);
}
#[test]
@@ -143,7 +146,7 @@ fn short_and_long_alias() {
Bar,
}
#[derive(Initial, PartialEq, Eq, Debug)]
#[derive(Default, PartialEq, Eq, Debug)]
struct Settings {
foo: bool,
bar: bool,
@@ -168,10 +171,10 @@ fn short_and_long_alias() {
bar: true,
};
assert_eq!(Settings::parse(["test", "--bar"]), foo_true);
assert_eq!(Settings::parse(["test", "-b"]), foo_true);
assert_eq!(Settings::parse(["test", "--foo"]), bar_true);
assert_eq!(Settings::parse(["test", "-f"]), bar_true);
assert_eq!(Settings::default().parse(["test", "--bar"]), foo_true);
assert_eq!(Settings::default().parse(["test", "-b"]), foo_true);
assert_eq!(Settings::default().parse(["test", "--foo"]), bar_true);
assert_eq!(Settings::default().parse(["test", "-f"]), bar_true);
}
#[test]
@@ -186,7 +189,7 @@ fn xyz_map_to_abc() {
Z,
}
#[derive(Initial, PartialEq, Eq, Debug)]
#[derive(Default, PartialEq, Eq, Debug)]
struct Settings {
a: bool,
b: bool,
@@ -214,7 +217,7 @@ fn xyz_map_to_abc() {
}
assert_eq!(
Settings::parse(["test", "-x"]),
Settings::default().parse(["test", "-x"]),
Settings {
a: true,
b: true,
@@ -223,7 +226,7 @@ fn xyz_map_to_abc() {
);
assert_eq!(
Settings::parse(["test", "-y"]),
Settings::default().parse(["test", "-y"]),
Settings {
a: false,
b: true,
@@ -232,7 +235,7 @@ fn xyz_map_to_abc() {
);
assert_eq!(
Settings::parse(["test", "-xy"]),
Settings::default().parse(["test", "-xy"]),
Settings {
a: true,
b: true,
@@ -241,7 +244,7 @@ fn xyz_map_to_abc() {
);
assert_eq!(
Settings::parse(["test", "-z"]),
Settings::default().parse(["test", "-z"]),
Settings {
a: true,
b: true,
@@ -260,7 +263,7 @@ fn non_rust_ident() {
Super,
}
#[derive(Initial, PartialEq, Eq, Debug)]
#[derive(Default, PartialEq, Eq, Debug)]
struct Settings {
a: bool,
b: bool,
@@ -276,7 +279,7 @@ fn non_rust_ident() {
}
assert_eq!(
Settings::parse(["test", "--foo-bar", "--super"]),
Settings::default().parse(["test", "--foo-bar", "--super"]),
Settings { a: true, b: true }
)
}
@@ -288,7 +291,7 @@ fn number_flag() {
#[arg("-1")]
One,
}
#[derive(Initial, PartialEq, Eq, Debug)]
#[derive(Default, PartialEq, Eq, Debug)]
struct Settings {
one: bool,
}
@@ -299,7 +302,7 @@ fn number_flag() {
}
}
assert!(Settings::parse(["test", "-1"]).one)
assert!(Settings::default().parse(["test", "-1"]).one)
}
#[test]
@@ -312,7 +315,7 @@ fn false_bool() {
B,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: bool,
}
@@ -326,12 +329,12 @@ fn false_bool() {
}
}
assert!(Settings::parse(["test", "-a"]).foo);
assert!(!Settings::parse(["test", "-b"]).foo);
assert!(!Settings::parse(["test", "-ab"]).foo);
assert!(Settings::parse(["test", "-ba"]).foo);
assert!(!Settings::parse(["test", "-a", "-b"]).foo);
assert!(Settings::parse(["test", "-b", "-a"]).foo);
assert!(Settings::default().parse(["test", "-a"]).foo);
assert!(!Settings::default().parse(["test", "-b"]).foo);
assert!(!Settings::default().parse(["test", "-ab"]).foo);
assert!(Settings::default().parse(["test", "-ba"]).foo);
assert!(!Settings::default().parse(["test", "-a", "-b"]).foo);
assert!(Settings::default().parse(["test", "-b", "-a"]).foo);
}
#[test]
@@ -342,7 +345,7 @@ fn verbosity() {
Verbosity,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
verbosity: u8,
}
@@ -353,9 +356,9 @@ fn verbosity() {
}
}
assert_eq!(Settings::parse(["test", "-v"]).verbosity, 1);
assert_eq!(Settings::parse(["test", "-vv"]).verbosity, 2);
assert_eq!(Settings::parse(["test", "-vvv"]).verbosity, 3);
assert_eq!(Settings::default().parse(["test", "-v"]).verbosity, 1);
assert_eq!(Settings::default().parse(["test", "-vv"]).verbosity, 2);
assert_eq!(Settings::default().parse(["test", "-vvv"]).verbosity, 3);
}
#[test]
@@ -370,7 +373,7 @@ fn infer_long_args() {
Author,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
all: bool,
almost_all: bool,
@@ -387,10 +390,10 @@ fn infer_long_args() {
}
}
assert!(Settings::parse(["test", "--all"]).all);
assert!(Settings::parse(["test", "--alm"]).almost_all);
assert!(Settings::parse(["test", "--au"]).author);
assert!(Settings::try_parse(["test", "--a"]).is_err());
assert!(Settings::default().parse(["test", "--all"]).all);
assert!(Settings::default().parse(["test", "--alm"]).almost_all);
assert!(Settings::default().parse(["test", "--au"]).author);
assert!(Settings::default().try_parse(["test", "--a"]).is_err());
}
#[test]
@@ -413,7 +416,7 @@ fn enum_flag() {
Baz,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
foo: SomeEnum,
}
@@ -428,7 +431,13 @@ fn enum_flag() {
}
}
assert_eq!(Settings::parse(["test"]).foo, SomeEnum::Foo);
assert_eq!(Settings::parse(["test", "--bar"]).foo, SomeEnum::Bar);
assert_eq!(Settings::parse(["test", "--baz"]).foo, SomeEnum::Baz,);
assert_eq!(Settings::default().parse(["test"]).foo, SomeEnum::Foo);
assert_eq!(
Settings::default().parse(["test", "--bar"]).foo,
SomeEnum::Bar
);
assert_eq!(
Settings::default().parse(["test", "--baz"]).foo,
SomeEnum::Baz,
);
}
+75 -52
View File
@@ -1,6 +1,6 @@
use std::ffi::OsStr;
use uutils_args::{Arguments, Initial, Options, Value, ValueResult};
use uutils_args::{Arguments, Options, Value, ValueResult};
#[test]
fn string_option() {
@@ -10,7 +10,7 @@ fn string_option() {
Message(String),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
message: String,
}
@@ -22,7 +22,9 @@ fn string_option() {
}
assert_eq!(
Settings::parse(["test", "--message=hello"]).message,
Settings::default()
.parse(["test", "--message=hello"])
.message,
"hello"
);
}
@@ -46,7 +48,7 @@ fn enum_option() {
Format(Format),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
format: Format,
}
@@ -58,12 +60,14 @@ fn enum_option() {
}
assert_eq!(
Settings::parse(["test", "--format=bar"]).format,
Settings::default().parse(["test", "--format=bar"]).format,
Format::Bar
);
assert_eq!(
Settings::parse(["test", "--format", "baz"]).format,
Settings::default()
.parse(["test", "--format", "baz"])
.format,
Format::Baz
);
}
@@ -85,7 +89,7 @@ fn enum_option_with_fields() {
Indent(Indent),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
indent: Indent,
}
@@ -97,11 +101,11 @@ fn enum_option_with_fields() {
}
assert_eq!(
Settings::parse(["test", "-i=thin"]).indent,
Settings::default().parse(["test", "-i=thin"]).indent,
Indent::Spaces(4)
);
assert_eq!(
Settings::parse(["test", "-i=wide"]).indent,
Settings::default().parse(["test", "-i=wide"]).indent,
Indent::Spaces(8)
);
}
@@ -134,7 +138,7 @@ fn enum_with_complex_from_value() {
Indent(Indent),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
indent: Indent,
}
@@ -145,8 +149,14 @@ fn enum_with_complex_from_value() {
}
}
assert_eq!(Settings::parse(["test", "-i=tabs"]).indent, Indent::Tabs);
assert_eq!(Settings::parse(["test", "-i=4"]).indent, Indent::Spaces(4));
assert_eq!(
Settings::default().parse(["test", "-i=tabs"]).indent,
Indent::Tabs
);
assert_eq!(
Settings::default().parse(["test", "-i=4"]).indent,
Indent::Spaces(4)
);
}
#[test]
@@ -168,9 +178,8 @@ fn color() {
Color(Option<Color>),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
#[initial(Color::Auto)]
color: Color,
}
@@ -181,20 +190,29 @@ fn color() {
}
assert_eq!(
Settings::parse(["test", "--color=yes"]).color,
Settings::default().parse(["test", "--color=yes"]).color,
Color::Always
);
assert_eq!(
Settings::parse(["test", "--color=always"]).color,
Settings::default().parse(["test", "--color=always"]).color,
Color::Always
);
assert_eq!(Settings::parse(["test", "--color=no"]).color, Color::Never);
assert_eq!(
Settings::parse(["test", "--color=never"]).color,
Settings::default().parse(["test", "--color=no"]).color,
Color::Never
);
assert_eq!(Settings::parse(["test", "--color=auto"]).color, Color::Auto);
assert_eq!(Settings::parse(["test", "--color"]).color, Color::Always)
assert_eq!(
Settings::default().parse(["test", "--color=never"]).color,
Color::Never
);
assert_eq!(
Settings::default().parse(["test", "--color=auto"]).color,
Color::Auto
);
assert_eq!(
Settings::default().parse(["test", "--color"]).color,
Color::Always
)
}
#[test]
@@ -209,7 +227,7 @@ fn actions() {
Receive,
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
last_message: String,
send: bool,
@@ -229,7 +247,7 @@ fn actions() {
}
}
let settings = Settings::parse(["test", "-m=Hello", "-m=World", "--send"]);
let settings = Settings::default().parse(["test", "-m=Hello", "-m=World", "--send"]);
assert_eq!(settings.messages, vec!["Hello", "World"]);
assert_eq!(settings.last_message, "World");
assert!(settings.send);
@@ -243,7 +261,7 @@ fn width() {
Width(u64),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
width: Option<u64>,
}
@@ -257,8 +275,8 @@ fn width() {
}
}
assert_eq!(Settings::parse(["test", "-w=0"]).width, None);
assert_eq!(Settings::parse(["test", "-w=1"]).width, Some(1));
assert_eq!(Settings::default().parse(["test", "-w=0"]).width, None);
assert_eq!(Settings::default().parse(["test", "-w=1"]).width, Some(1));
}
#[test]
@@ -287,7 +305,7 @@ fn integers() {
I128(i128),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
n: i128,
}
@@ -309,17 +327,17 @@ fn integers() {
}
}
assert_eq!(Settings::parse(["test", "--u8=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--u16=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--u32=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--u64=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--u128=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--u8=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--u16=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--u32=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--u64=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--u128=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--i8=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--i16=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--i32=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--i64=5"]).n, 5);
assert_eq!(Settings::parse(["test", "--i128=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--i8=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--i16=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--i32=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--i64=5"]).n, 5);
assert_eq!(Settings::default().parse(["test", "--i128=5"]).n, 5);
}
#[test]
@@ -344,7 +362,7 @@ fn ls_classify() {
Classify(When),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
classify: When,
}
@@ -355,17 +373,22 @@ fn ls_classify() {
}
}
assert_eq!(Settings::parse(["test"]).classify, When::Auto);
assert_eq!(Settings::default().parse(["test"]).classify, When::Auto);
assert_eq!(
Settings::parse(["test", "--classify=never"]).classify,
Settings::default()
.parse(["test", "--classify=never"])
.classify,
When::Never,
);
assert_eq!(
Settings::parse(["test", "--classify"]).classify,
Settings::default().parse(["test", "--classify"]).classify,
When::Always,
);
assert_eq!(Settings::parse(["test", "-F"]).classify, When::Always,);
assert!(Settings::try_parse(["test", "-Falways"]).is_err());
assert_eq!(
Settings::default().parse(["test", "-F"]).classify,
When::Always,
);
assert!(Settings::default().try_parse(["test", "-Falways"]).is_err());
}
#[test]
@@ -379,7 +402,7 @@ fn mktemp_tmpdir() {
TmpDir(String),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
tmpdir: Option<String>,
}
@@ -390,16 +413,16 @@ fn mktemp_tmpdir() {
}
}
let settings = Settings::parse(["test", "-p", "X"]);
let settings = Settings::default().parse(["test", "-p", "X"]);
assert_eq!(settings.tmpdir.unwrap(), "X");
let settings = Settings::parse(["test", "--tmpdir=X"]);
let settings = Settings::default().parse(["test", "--tmpdir=X"]);
assert_eq!(settings.tmpdir.unwrap(), "X");
let settings = Settings::parse(["test", "--tmpdir"]);
let settings = Settings::default().parse(["test", "--tmpdir"]);
assert_eq!(settings.tmpdir.unwrap(), "/tmp");
assert!(Settings::try_parse(["test", "-p"]).is_err());
assert!(Settings::default().try_parse(["test", "-p"]).is_err());
}
#[test]
@@ -452,7 +475,7 @@ fn deprecated() {
Plus(isize),
}
#[derive(Initial)]
#[derive(Default)]
struct Settings {
n1: usize,
n2: isize,
@@ -467,8 +490,8 @@ fn deprecated() {
}
}
assert_eq!(Settings::parse(["test", "-10"]).n1, 10usize);
assert!(Settings::try_parse(["test", "--10"]).is_err());
assert_eq!(Settings::parse(["test", "+10"]).n2, 10isize);
assert_eq!(Settings::parse(["test", "+-10"]).n2, -10isize);
assert_eq!(Settings::default().parse(["test", "-10"]).n1, 10usize);
assert!(Settings::default().try_parse(["test", "--10"]).is_err());
assert_eq!(Settings::default().parse(["test", "+10"]).n2, 10isize);
assert_eq!(Settings::default().parse(["test", "+-10"]).n2, -10isize);
}

Some files were not shown because too many files have changed in this diff Show More