Separate the matched flags from the free strings

Originally, both the matched flags and the list of free strings were returned from the parsing function and then passed around to every type that had a ‘deduce’ method. This worked, but the list of free strings was carried around with it, never used.

Now, only the flags are passed around. They’re in a new struct which has the methods the Matches had.

Both of Matches’s fields are now just data, and all of the methods on MatchedFlags don’t ignore any fields, so it’s more cohesive, at least I think that’s the word.

Building up the MatchedFlags is a bit more annoying though because the vector is now hidden behind a field.
This commit is contained in:
Benjamin Sago 2017-08-05 19:11:00 +01:00
parent 0456e7cfbd
commit 9872eba821
6 changed files with 131 additions and 94 deletions

View File

@ -1,4 +1,4 @@
use options::parser::Matches; use options::parser::MatchedFlags;
use options::{flags, Misfire}; use options::{flags, Misfire};
use fs::dir_action::{DirAction, RecurseOptions}; use fs::dir_action::{DirAction, RecurseOptions};
@ -7,7 +7,7 @@ use fs::dir_action::{DirAction, RecurseOptions};
impl DirAction { impl DirAction {
/// Determine which action to perform when trying to list a directory. /// Determine which action to perform when trying to list a directory.
pub fn deduce(matches: &Matches) -> Result<DirAction, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<DirAction, Misfire> {
let recurse = matches.has(&flags::RECURSE); let recurse = matches.has(&flags::RECURSE);
let list = matches.has(&flags::LIST_DIRS); let list = matches.has(&flags::LIST_DIRS);
let tree = matches.has(&flags::TREE); let tree = matches.has(&flags::TREE);
@ -36,7 +36,7 @@ impl DirAction {
impl RecurseOptions { impl RecurseOptions {
/// Determine which files should be recursed into. /// Determine which files should be recursed into.
pub fn deduce(matches: &Matches, tree: bool) -> Result<RecurseOptions, Misfire> { pub fn deduce(matches: &MatchedFlags, tree: bool) -> Result<RecurseOptions, Misfire> {
let max_depth = if let Some(level) = matches.get(&flags::LEVEL) { let max_depth = if let Some(level) = matches.get(&flags::LEVEL) {
match level.to_string_lossy().parse() { match level.to_string_lossy().parse() {
Ok(l) => Some(l), Ok(l) => Some(l),
@ -75,7 +75,7 @@ mod test {
let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>(); let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
let results = Args(TEST_ARGS).parse(bits.iter()); let results = Args(TEST_ARGS).parse(bits.iter());
assert_eq!($type::deduce(results.as_ref().unwrap()), $result); assert_eq!($type::deduce(&results.unwrap().flags), $result);
} }
}; };
} }

View File

@ -4,14 +4,14 @@ use fs::DotFilter;
use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns}; use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns};
use options::{flags, Misfire}; use options::{flags, Misfire};
use options::parser::Matches; use options::parser::MatchedFlags;
impl FileFilter { impl FileFilter {
/// Determines the set of file filter options to use, based on the users /// Determines the set of file filter options to use, based on the users
/// command-line arguments. /// command-line arguments.
pub fn deduce(matches: &Matches) -> Result<FileFilter, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<FileFilter, Misfire> {
Ok(FileFilter { Ok(FileFilter {
list_dirs_first: matches.has(&flags::DIRS_FIRST), list_dirs_first: matches.has(&flags::DIRS_FIRST),
reverse: matches.has(&flags::REVERSE), reverse: matches.has(&flags::REVERSE),
@ -39,7 +39,7 @@ impl SortField {
/// Determine the sort field to use, based on the presence of a “sort” /// Determine the sort field to use, based on the presence of a “sort”
/// argument. This will return `Err` if the option is there, but does not /// argument. This will return `Err` if the option is there, but does not
/// correspond to a valid field. /// correspond to a valid field.
fn deduce(matches: &Matches) -> Result<SortField, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<SortField, Misfire> {
let word = match matches.get(&flags::SORT) { let word = match matches.get(&flags::SORT) {
Some(w) => w, Some(w) => w,
None => return Ok(SortField::default()), None => return Ok(SortField::default()),
@ -86,7 +86,7 @@ impl SortField {
impl DotFilter { impl DotFilter {
pub fn deduce(matches: &Matches) -> Result<DotFilter, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<DotFilter, Misfire> {
match matches.count(&flags::ALL) { match matches.count(&flags::ALL) {
0 => Ok(DotFilter::JustFiles), 0 => Ok(DotFilter::JustFiles),
1 => Ok(DotFilter::Dotfiles), 1 => Ok(DotFilter::Dotfiles),
@ -101,7 +101,7 @@ impl IgnorePatterns {
/// Determines the set of file filter options to use, based on the users /// Determines the set of file filter options to use, based on the users
/// command-line arguments. /// command-line arguments.
pub fn deduce(matches: &Matches) -> Result<IgnorePatterns, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<IgnorePatterns, Misfire> {
let patterns = match matches.get(&flags::IGNORE_GLOB) { let patterns = match matches.get(&flags::IGNORE_GLOB) {
None => Ok(Vec::new()), None => Ok(Vec::new()),
Some(is) => is.to_string_lossy().split('|').map(|a| glob::Pattern::new(a)).collect(), Some(is) => is.to_string_lossy().split('|').map(|a| glob::Pattern::new(a)).collect(),
@ -139,7 +139,7 @@ mod test {
let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>(); let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
let results = Args(TEST_ARGS).parse(bits.iter()); let results = Args(TEST_ARGS).parse(bits.iter());
assert_eq!($type::deduce(results.as_ref().unwrap()), $result); assert_eq!($type::deduce(&results.unwrap().flags), $result);
} }
}; };
} }

View File

@ -1,7 +1,7 @@
use std::fmt; use std::fmt;
use options::flags; use options::flags;
use options::parser::Matches; use options::parser::MatchedFlags;
use fs::feature::xattr; use fs::feature::xattr;
@ -72,7 +72,7 @@ impl HelpString {
/// Determines how to show help, if at all, based on the users /// Determines how to show help, if at all, based on the users
/// command-line arguments. This one works backwards from the other /// command-line arguments. This one works backwards from the other
/// deduce functions, returning Err if help needs to be shown. /// deduce functions, returning Err if help needs to be shown.
pub fn deduce(matches: &Matches) -> Result<(), HelpString> { pub fn deduce(matches: &MatchedFlags) -> Result<(), HelpString> {
if matches.has(&flags::HELP) { if matches.has(&flags::HELP) {
let only_long = matches.has(&flags::LONG); let only_long = matches.has(&flags::LONG);
let git = cfg!(feature="git"); let git = cfg!(feature="git");

View File

@ -88,7 +88,7 @@ pub use self::misfire::Misfire;
mod parser; mod parser;
mod flags; mod flags;
use self::parser::Matches; use self::parser::MatchedFlags;
/// These **options** represent a parsed, error-checked versions of the /// These **options** represent a parsed, error-checked versions of the
@ -113,20 +113,21 @@ impl Options {
#[allow(unused_results)] #[allow(unused_results)]
pub fn getopts<'args, I>(args: I) -> Result<(Options, Vec<&'args OsStr>), Misfire> pub fn getopts<'args, I>(args: I) -> Result<(Options, Vec<&'args OsStr>), Misfire>
where I: IntoIterator<Item=&'args OsString> { where I: IntoIterator<Item=&'args OsString> {
use options::parser::Matches;
let matches = match flags::ALL_ARGS.parse(args) { let Matches { flags, frees } = match flags::ALL_ARGS.parse(args) {
Ok(m) => m, Ok(m) => m,
Err(e) => return Err(Misfire::InvalidOptions(e)), Err(e) => return Err(Misfire::InvalidOptions(e)),
}; };
HelpString::deduce(&matches).map_err(Misfire::Help)?; HelpString::deduce(&flags).map_err(Misfire::Help)?;
if matches.has(&flags::VERSION) { if flags.has(&flags::VERSION) {
return Err(Misfire::Version); return Err(Misfire::Version);
} }
let options = Options::deduce(&matches)?; let options = Options::deduce(&flags)?;
Ok((options, matches.frees)) Ok((options, frees))
} }
/// Whether the View specified in this set of options includes a Git /// Whether the View specified in this set of options includes a Git
@ -142,7 +143,7 @@ impl Options {
/// Determines the complete set of options based on the given command-line /// Determines the complete set of options based on the given command-line
/// arguments, after theyve been parsed. /// arguments, after theyve been parsed.
fn deduce(matches: &Matches) -> Result<Options, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<Options, Misfire> {
let dir_action = DirAction::deduce(matches)?; let dir_action = DirAction::deduce(matches)?;
let filter = FileFilter::deduce(matches)?; let filter = FileFilter::deduce(matches)?;
let view = View::deduce(matches)?; let view = View::deduce(matches)?;

View File

@ -130,7 +130,7 @@ impl Args {
// The results that get built up. // The results that get built up.
let mut results = Matches { let mut results = Matches {
flags: Vec::new(), flags: MatchedFlags { flags: Vec::new() },
frees: Vec::new(), frees: Vec::new(),
}; };
@ -163,7 +163,7 @@ impl Args {
let arg = self.lookup_long(before)?; let arg = self.lookup_long(before)?;
let flag = Flag::Long(arg.long); let flag = Flag::Long(arg.long);
match arg.takes_value { match arg.takes_value {
Necessary => results.flags.push((flag, Some(after))), Necessary => results.flags.flags.push((flag, Some(after))),
Forbidden => return Err(ParseError::ForbiddenValue { flag }) Forbidden => return Err(ParseError::ForbiddenValue { flag })
} }
} }
@ -174,10 +174,10 @@ impl Args {
let arg = self.lookup_long(long_arg_name)?; let arg = self.lookup_long(long_arg_name)?;
let flag = Flag::Long(arg.long); let flag = Flag::Long(arg.long);
match arg.takes_value { match arg.takes_value {
Forbidden => results.flags.push((flag, None)), Forbidden => results.flags.flags.push((flag, None)),
Necessary => { Necessary => {
if let Some(next_arg) = inputs.next() { if let Some(next_arg) = inputs.next() {
results.flags.push((flag, Some(next_arg))); results.flags.flags.push((flag, Some(next_arg)));
} }
else { else {
return Err(ParseError::NeedsValue { flag }) return Err(ParseError::NeedsValue { flag })
@ -212,7 +212,7 @@ impl Args {
let arg = self.lookup_short(*byte)?; let arg = self.lookup_short(*byte)?;
let flag = Flag::Short(*byte); let flag = Flag::Short(*byte);
match arg.takes_value { match arg.takes_value {
Forbidden => results.flags.push((flag, None)), Forbidden => results.flags.flags.push((flag, None)),
Necessary => return Err(ParseError::NeedsValue { flag }) Necessary => return Err(ParseError::NeedsValue { flag })
} }
} }
@ -221,7 +221,7 @@ impl Args {
let arg = self.lookup_short(*arg_with_value)?; let arg = self.lookup_short(*arg_with_value)?;
let flag = Flag::Short(arg.short.unwrap()); let flag = Flag::Short(arg.short.unwrap());
match arg.takes_value { match arg.takes_value {
Necessary => results.flags.push((flag, Some(after))), Necessary => results.flags.flags.push((flag, Some(after))),
Forbidden => return Err(ParseError::ForbiddenValue { flag }) Forbidden => return Err(ParseError::ForbiddenValue { flag })
} }
} }
@ -243,15 +243,15 @@ impl Args {
let arg = self.lookup_short(*byte)?; let arg = self.lookup_short(*byte)?;
let flag = Flag::Short(*byte); let flag = Flag::Short(*byte);
match arg.takes_value { match arg.takes_value {
Forbidden => results.flags.push((flag, None)), Forbidden => results.flags.flags.push((flag, None)),
Necessary => { Necessary => {
if index < bytes.len() - 1 { if index < bytes.len() - 1 {
let remnants = &bytes[index+1 ..]; let remnants = &bytes[index+1 ..];
results.flags.push((flag, Some(OsStr::from_bytes(remnants)))); results.flags.flags.push((flag, Some(OsStr::from_bytes(remnants))));
break; break;
} }
else if let Some(next_arg) = inputs.next() { else if let Some(next_arg) = inputs.next() {
results.flags.push((flag, Some(next_arg))); results.flags.flags.push((flag, Some(next_arg)));
} }
else { else {
return Err(ParseError::NeedsValue { flag }) return Err(ParseError::NeedsValue { flag })
@ -287,20 +287,31 @@ impl Args {
} }
/// The **matches** are the result of parsing /// The **matches** are the result of parsing the users command-line strings.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub struct Matches<'args> { pub struct Matches<'args> {
/// The flags that were /// The flags that were parsed from the users input.
/// Long and short arguments need to be kept in the same vector, because pub flags: MatchedFlags<'args>,
/// we usually want the one nearest the end to count.
pub flags: Vec<(Flag, Option<&'args OsStr>)>,
/// The strings that werent matched as arguments. /// All the strings that werent matched as arguments, as well as anything
/// after the special "--" string.
pub frees: Vec<&'args OsStr>, pub frees: Vec<&'args OsStr>,
} }
impl<'a> Matches<'a> { #[derive(PartialEq, Debug)]
pub struct MatchedFlags<'args> {
/// The individual flags from the users input, in the order they were
/// originally given.
///
/// Long and short arguments need to be kept in the same vector because
/// we usually want the one nearest the end to count, and to know this,
/// we need to know where they are in relation to one another.
flags: Vec<(Flag, Option<&'args OsStr>)>,
}
impl<'a> MatchedFlags<'a> {
/// Whether the given argument was specified. /// Whether the given argument was specified.
pub fn has(&self, arg: &Arg) -> bool { pub fn has(&self, arg: &Arg) -> bool {
@ -424,12 +435,39 @@ mod parse_test {
use super::*; use super::*;
macro_rules! test { macro_rules! test {
($name:ident: $inputs:expr => $result:expr) => { ($name:ident: $inputs:expr => frees: $frees:expr, flags: $flags:expr) => {
#[test] #[test]
fn $name() { fn $name() {
// Annoyingly the input &strs need to be converted to OsStrings
let inputs: Vec<OsString> = $inputs.as_ref().into_iter().map(|&o| os(o)).collect();
// Same with the frees
let frees: Vec<OsString> = $frees.as_ref().into_iter().map(|&o| os(o)).collect();
let frees: Vec<&OsStr> = frees.iter().map(|os| os.as_os_str()).collect();
// And again for the flags
let flags: Vec<(Flag, Option<&OsStr>)> = $flags
.as_ref()
.into_iter()
.map(|&(ref f, ref os): &(Flag, Option<&'static str>)| (f.clone(), os.map(OsStr::new)))
.collect();
let got = Args(TEST_ARGS).parse(inputs.iter());
let expected = Ok(Matches { frees, flags: MatchedFlags { flags } });
assert_eq!(got, expected);
}
};
($name:ident: $inputs:expr => error $error:expr) => {
#[test]
fn $name() {
use self::ParseError::*;
let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>(); let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
let results = Args(TEST_ARGS).parse(bits.iter()); let got = Args(TEST_ARGS).parse(bits.iter());
assert_eq!(results, $result);
assert_eq!(got, Err($error));
} }
}; };
} }
@ -442,52 +480,52 @@ mod parse_test {
// Just filenames // Just filenames
test!(empty: [] => Ok(Matches { frees: vec![], flags: vec![] })); test!(empty: [] => frees: [], flags: []);
test!(one_arg: ["exa"] => Ok(Matches { frees: vec![ &os("exa") ], flags: vec![] })); test!(one_arg: ["exa"] => frees: [ "exa" ], flags: []);
// Dashes and double dashes // Dashes and double dashes
test!(one_dash: ["-"] => Ok(Matches { frees: vec![ &os("-") ], flags: vec![] })); test!(one_dash: ["-"] => frees: [ "-" ], flags: []);
test!(two_dashes: ["--"] => Ok(Matches { frees: vec![], flags: vec![] })); test!(two_dashes: ["--"] => frees: [], flags: []);
test!(two_file: ["--", "file"] => Ok(Matches { frees: vec![ &os("file") ], flags: vec![] })); test!(two_file: ["--", "file"] => frees: [ "file" ], flags: []);
test!(two_arg_l: ["--", "--long"] => Ok(Matches { frees: vec![ &os("--long") ], flags: vec![] })); test!(two_arg_l: ["--", "--long"] => frees: [ "--long" ], flags: []);
test!(two_arg_s: ["--", "-l"] => Ok(Matches { frees: vec![ &os("-l") ], flags: vec![] })); test!(two_arg_s: ["--", "-l"] => frees: [ "-l" ], flags: []);
// Long args // Long args
test!(long: ["--long"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("long"), None) ] })); test!(long: ["--long"] => frees: [], flags: [ (Flag::Long("long"), None) ]);
test!(long_then: ["--long", "4"] => Ok(Matches { frees: vec![ &os("4") ], flags: vec![ (Flag::Long("long"), None) ] })); test!(long_then: ["--long", "4"] => frees: [ "4" ], flags: [ (Flag::Long("long"), None) ]);
test!(long_two: ["--long", "--verbose"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("long"), None), (Flag::Long("verbose"), None) ] })); test!(long_two: ["--long", "--verbose"] => frees: [], flags: [ (Flag::Long("long"), None), (Flag::Long("verbose"), None) ]);
// Long args with values // Long args with values
test!(bad_equals: ["--long=equals"] => Err(ParseError::ForbiddenValue { flag: Flag::Long("long") })); test!(bad_equals: ["--long=equals"] => error ForbiddenValue { flag: Flag::Long("long") });
test!(no_arg: ["--count"] => Err(ParseError::NeedsValue { flag: Flag::Long("count") })); test!(no_arg: ["--count"] => error NeedsValue { flag: Flag::Long("count") });
test!(arg_equals: ["--count=4"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(&*os("4"))) ] })); test!(arg_equals: ["--count=4"] => frees: [], flags: [ (Flag::Long("count"), Some("4")) ]);
test!(arg_then: ["--count", "4"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Long("count"), Some(&*os("4"))) ] })); test!(arg_then: ["--count", "4"] => frees: [], flags: [ (Flag::Long("count"), Some("4")) ]);
// Short args // Short args
test!(short: ["-l"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None) ] })); test!(short: ["-l"] => frees: [], flags: [ (Flag::Short(b'l'), None) ]);
test!(short_then: ["-l", "4"] => Ok(Matches { frees: vec![ &*os("4") ], flags: vec![ (Flag::Short(b'l'), None) ] })); test!(short_then: ["-l", "4"] => frees: [ "4" ], flags: [ (Flag::Short(b'l'), None) ]);
test!(short_two: ["-lv"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'v'), None) ] })); test!(short_two: ["-lv"] => frees: [], flags: [ (Flag::Short(b'l'), None), (Flag::Short(b'v'), None) ]);
test!(mixed: ["-v", "--long"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'v'), None), (Flag::Long("long"), None) ] })); test!(mixed: ["-v", "--long"] => frees: [], flags: [ (Flag::Short(b'v'), None), (Flag::Long("long"), None) ]);
// Short args with values // Short args with values
test!(bad_short: ["-l=equals"] => Err(ParseError::ForbiddenValue { flag: Flag::Short(b'l') })); test!(bad_short: ["-l=equals"] => error ForbiddenValue { flag: Flag::Short(b'l') });
test!(short_none: ["-c"] => Err(ParseError::NeedsValue { flag: Flag::Short(b'c') })); test!(short_none: ["-c"] => error NeedsValue { flag: Flag::Short(b'c') });
test!(short_arg_eq: ["-c=4"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(&*os("4"))) ] })); test!(short_arg_eq: ["-c=4"] => frees: [], flags: [(Flag::Short(b'c'), Some("4")) ]);
test!(short_arg_then: ["-c", "4"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'c'), Some(&*os("4"))) ] })); test!(short_arg_then: ["-c", "4"] => frees: [], flags: [(Flag::Short(b'c'), Some("4")) ]);
test!(short_two_together: ["-lctwo"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(&*os("two"))) ] })); test!(short_two_together: ["-lctwo"] => frees: [], flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some("two")) ]);
test!(short_two_equals: ["-lc=two"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(&*os("two"))) ] })); test!(short_two_equals: ["-lc=two"] => frees: [], flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some("two")) ]);
test!(short_two_next: ["-lc", "two"] => Ok(Matches { frees: vec![], flags: vec![ (Flag::Short(b'l'), None), (Flag::Short(b'c'), Some(&*os("two"))) ] })); test!(short_two_next: ["-lc", "two"] => frees: [], flags: [(Flag::Short(b'l'), None), (Flag::Short(b'c'), Some("two")) ]);
// Unknown args // Unknown args
test!(unknown_long: ["--quiet"] => Err(ParseError::UnknownArgument { attempt: os("quiet") })); test!(unknown_long: ["--quiet"] => error UnknownArgument { attempt: os("quiet") });
test!(unknown_long_eq: ["--quiet=shhh"] => Err(ParseError::UnknownArgument { attempt: os("quiet") })); test!(unknown_long_eq: ["--quiet=shhh"] => error UnknownArgument { attempt: os("quiet") });
test!(unknown_short: ["-q"] => Err(ParseError::UnknownShortArgument { attempt: b'q' })); test!(unknown_short: ["-q"] => error UnknownShortArgument { attempt: b'q' });
test!(unknown_short_2nd: ["-lq"] => Err(ParseError::UnknownShortArgument { attempt: b'q' })); test!(unknown_short_2nd: ["-lq"] => error UnknownShortArgument { attempt: b'q' });
test!(unknown_short_eq: ["-q=shhh"] => Err(ParseError::UnknownShortArgument { attempt: b'q' })); test!(unknown_short_eq: ["-q=shhh"] => error UnknownShortArgument { attempt: b'q' });
test!(unknown_short_2nd_eq: ["-lq=shhh"] => Err(ParseError::UnknownShortArgument { attempt: b'q' })); test!(unknown_short_2nd_eq: ["-lq=shhh"] => error UnknownShortArgument { attempt: b'q' });
} }
@ -499,9 +537,8 @@ mod matches_test {
($name:ident: $input:expr, has $param:expr => $result:expr) => { ($name:ident: $input:expr, has $param:expr => $result:expr) => {
#[test] #[test]
fn $name() { fn $name() {
let frees = Vec::new(); let flags = MatchedFlags { flags: $input.to_vec() };
let flags = $input.to_vec(); assert_eq!(flags.has(&$param), $result);
assert_eq!(Matches { frees, flags }.has(&$param), $result);
} }
}; };
} }
@ -521,9 +558,8 @@ mod matches_test {
#[test] #[test]
fn only_count() { fn only_count() {
let everything = os("everything"); let everything = os("everything");
let frees = Vec::new(); let flags = MatchedFlags { flags: vec![ (Flag::Short(b'c'), Some(&*everything)) ] };
let flags = vec![ (Flag::Short(b'c'), Some(&*everything)) ]; assert_eq!(flags.get(&COUNT), Some(&*everything));
assert_eq!(Matches { frees, flags }.get(&COUNT), Some(&*everything));
} }
#[test] #[test]
@ -531,18 +567,18 @@ mod matches_test {
let everything = os("everything"); let everything = os("everything");
let nothing = os("nothing"); let nothing = os("nothing");
let frees = Vec::new(); let flags = MatchedFlags {
let flags = vec![ (Flag::Short(b'c'), Some(&*everything)), flags: vec![ (Flag::Short(b'c'), Some(&*everything)),
(Flag::Short(b'c'), Some(&*nothing)) ]; (Flag::Short(b'c'), Some(&*nothing)) ]
};
assert_eq!(Matches { frees, flags }.get(&COUNT), Some(&*nothing)); assert_eq!(flags.get(&COUNT), Some(&*nothing));
} }
#[test] #[test]
fn no_count() { fn no_count() {
let frees = Vec::new(); let flags = MatchedFlags { flags: Vec::new() };
let flags = Vec::new();
assert!(!Matches { frees, flags }.has(&COUNT)); assert!(!flags.has(&COUNT));
} }
} }

View File

@ -7,7 +7,7 @@ use output::file_name::{Classify, FileStyle};
use output::time::TimeFormat; use output::time::TimeFormat;
use options::{flags, Misfire}; use options::{flags, Misfire};
use options::parser::Matches; use options::parser::MatchedFlags;
use fs::feature::xattr; use fs::feature::xattr;
use info::filetype::FileExtensions; use info::filetype::FileExtensions;
@ -16,7 +16,7 @@ use info::filetype::FileExtensions;
impl View { impl View {
/// Determine which view to use and all of that views arguments. /// Determine which view to use and all of that views arguments.
pub fn deduce(matches: &Matches) -> Result<View, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<View, Misfire> {
let mode = Mode::deduce(matches)?; let mode = Mode::deduce(matches)?;
let colours = Colours::deduce(matches)?; let colours = Colours::deduce(matches)?;
let style = FileStyle::deduce(matches); let style = FileStyle::deduce(matches);
@ -28,7 +28,7 @@ impl View {
impl Mode { impl Mode {
/// Determine the mode from the command-line arguments. /// Determine the mode from the command-line arguments.
pub fn deduce(matches: &Matches) -> Result<Mode, Misfire> { pub fn deduce(matches: &MatchedFlags) -> Result<Mode, Misfire> {
use options::misfire::Misfire::*; use options::misfire::Misfire::*;
let long = || { let long = || {
@ -182,7 +182,7 @@ impl TerminalWidth {
impl TableOptions { impl TableOptions {
fn deduce(matches: &Matches) -> Result<Self, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
Ok(TableOptions { Ok(TableOptions {
env: Environment::load_all(), env: Environment::load_all(),
time_format: TimeFormat::deduce(matches)?, time_format: TimeFormat::deduce(matches)?,
@ -208,7 +208,7 @@ impl SizeFormat {
/// strings of digits in your head. Changing the format to anything else /// strings of digits in your head. Changing the format to anything else
/// involves the `--binary` or `--bytes` flags, and these conflict with /// involves the `--binary` or `--bytes` flags, and these conflict with
/// each other. /// each other.
fn deduce(matches: &Matches) -> Result<SizeFormat, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<SizeFormat, Misfire> {
let binary = matches.has(&flags::BINARY); let binary = matches.has(&flags::BINARY);
let bytes = matches.has(&flags::BYTES); let bytes = matches.has(&flags::BYTES);
@ -225,7 +225,7 @@ impl SizeFormat {
impl TimeFormat { impl TimeFormat {
/// Determine how time should be formatted in timestamp columns. /// Determine how time should be formatted in timestamp columns.
fn deduce(matches: &Matches) -> Result<TimeFormat, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<TimeFormat, Misfire> {
pub use output::time::{DefaultFormat, ISOFormat}; pub use output::time::{DefaultFormat, ISOFormat};
const STYLES: &[&str] = &["default", "long-iso", "full-iso", "iso"]; const STYLES: &[&str] = &["default", "long-iso", "full-iso", "iso"];
@ -267,7 +267,7 @@ impl TimeTypes {
/// Its valid to show more than one column by passing in more than one /// Its valid to show more than one column by passing in more than one
/// option, but passing *no* options means that the user just wants to /// option, but passing *no* options means that the user just wants to
/// see the default set. /// see the default set.
fn deduce(matches: &Matches) -> Result<TimeTypes, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<TimeTypes, Misfire> {
let possible_word = matches.get(&flags::TIME); let possible_word = matches.get(&flags::TIME);
let modified = matches.has(&flags::MODIFIED); let modified = matches.has(&flags::MODIFIED);
let created = matches.has(&flags::CREATED); let created = matches.has(&flags::CREATED);
@ -335,7 +335,7 @@ impl Default for TerminalColours {
impl TerminalColours { impl TerminalColours {
/// Determine which terminal colour conditions to use. /// Determine which terminal colour conditions to use.
fn deduce(matches: &Matches) -> Result<TerminalColours, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<TerminalColours, Misfire> {
const COLOURS: &[&str] = &["always", "auto", "never"]; const COLOURS: &[&str] = &["always", "auto", "never"];
let word = match matches.get(&flags::COLOR).or_else(|| matches.get(&flags::COLOUR)) { let word = match matches.get(&flags::COLOR).or_else(|| matches.get(&flags::COLOUR)) {
@ -360,7 +360,7 @@ impl TerminalColours {
impl Colours { impl Colours {
fn deduce(matches: &Matches) -> Result<Colours, Misfire> { fn deduce(matches: &MatchedFlags) -> Result<Colours, Misfire> {
use self::TerminalColours::*; use self::TerminalColours::*;
let tc = TerminalColours::deduce(matches)?; let tc = TerminalColours::deduce(matches)?;
@ -377,7 +377,7 @@ impl Colours {
impl FileStyle { impl FileStyle {
fn deduce(matches: &Matches) -> FileStyle { fn deduce(matches: &MatchedFlags) -> FileStyle {
let classify = Classify::deduce(matches); let classify = Classify::deduce(matches);
let exts = FileExtensions; let exts = FileExtensions;
FileStyle { classify, exts } FileStyle { classify, exts }
@ -385,7 +385,7 @@ impl FileStyle {
} }
impl Classify { impl Classify {
fn deduce(matches: &Matches) -> Classify { fn deduce(matches: &MatchedFlags) -> Classify {
if matches.has(&flags::CLASSIFY) { Classify::AddFileIndicators } if matches.has(&flags::CLASSIFY) { Classify::AddFileIndicators }
else { Classify::JustFilenames } else { Classify::JustFilenames }
} }
@ -428,7 +428,7 @@ mod test {
let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>(); let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
let results = Args(TEST_ARGS).parse(bits.iter()); let results = Args(TEST_ARGS).parse(bits.iter());
assert_eq!($type::deduce(results.as_ref().unwrap()), $result); assert_eq!($type::deduce(&results.unwrap().flags), $result);
} }
}; };
} }