From 6488f168fb41029ecb5c7437baaab41c82fba8b3 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Thu, 24 Mar 2016 22:40:08 -0400 Subject: [PATCH 1/7] sort: refactor settings into dedicated struct --- src/sort/sort.rs | 57 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/sort/sort.rs b/src/sort/sort.rs index 7a344f160..feef4833a 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -29,7 +29,30 @@ static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static DECIMAL_PT: char = '.'; static THOUSANDS_SEP: char = ','; +enum SortMode { + Numeric, + HumanReadable, + Default, +} + +struct Settings { + mode: SortMode, + reverse: bool, + outfile: Option, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + mode: SortMode::Default, + reverse: false, + outfile: None, + } + } +} + pub fn uumain(args: Vec) -> i32 { + let mut settings: Settings = Default::default(); let mut opts = getopts::Options::new(); opts.optflag("n", "numeric-sort", "compare according to string numerical value"); @@ -63,10 +86,16 @@ With no FILE, or when FILE is -, read standard input.", NAME, VERSION); return 0; } - let numeric = matches.opt_present("numeric-sort"); - let human_readable = matches.opt_present("human-readable-sort"); - let reverse = matches.opt_present("reverse"); - let outfile = matches.opt_str("output"); + settings.mode = if matches.opt_present("numeric-sort") { + SortMode::Numeric + } else if matches.opt_present("human-readable-sort") { + SortMode::HumanReadable + } else { + SortMode::Default + }; + + settings.reverse = matches.opt_present("reverse"); + settings.outfile = matches.opt_str("output"); let mut files = matches.free; if files.is_empty() { @@ -74,12 +103,12 @@ With no FILE, or when FILE is -, read standard input.", NAME, VERSION); files.push("-".to_owned()); } - exec(files, numeric, human_readable, reverse, outfile); + exec(files, &settings); 0 } -fn exec(files: Vec, numeric: bool, human_readable: bool, reverse: bool, outfile: Option) { +fn exec(files: Vec, settings: &Settings) { for path in &files { let (reader, _) = match open(path) { Some(x) => x, @@ -98,19 +127,17 @@ fn exec(files: Vec, numeric: bool, human_readable: bool, reverse: bool, } } - if numeric { - lines.sort_by(numeric_compare); - } else if human_readable { - lines.sort_by(human_readable_size_compare); - } else { - lines.sort(); + match settings.mode { + SortMode::Numeric => lines.sort_by(numeric_compare), + SortMode::HumanReadable => lines.sort_by(human_readable_size_compare), + SortMode::Default => lines.sort() } let iter = lines.iter(); - if reverse { - print_sorted(iter.rev(), &outfile); + if settings.reverse { + print_sorted(iter.rev(), &settings.outfile); } else { - print_sorted(iter, &outfile) + print_sorted(iter, &settings.outfile) }; } } From 678a3d1451ad95ae0f16bf1b957a72856049d665 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Thu, 24 Mar 2016 22:45:27 -0400 Subject: [PATCH 2/7] sort: fix flag for human numeric sort --- src/sort/sort.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sort/sort.rs b/src/sort/sort.rs index feef4833a..74cfcdeaf 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -31,7 +31,7 @@ static THOUSANDS_SEP: char = ','; enum SortMode { Numeric, - HumanReadable, + HumanNumeric, Default, } @@ -56,7 +56,7 @@ pub fn uumain(args: Vec) -> i32 { let mut opts = getopts::Options::new(); opts.optflag("n", "numeric-sort", "compare according to string numerical value"); - opts.optflag("H", "human-readable-sort", "compare according to human readable sizes, eg 1M > 100k"); + opts.optflag("h", "human-numeric-sort", "compare according to human readable sizes, eg 1M > 100k"); opts.optflag("r", "reverse", "reverse the output"); opts.optflag("h", "help", "display this help and exit"); opts.optflag("", "version", "output version information and exit"); @@ -88,8 +88,8 @@ With no FILE, or when FILE is -, read standard input.", NAME, VERSION); settings.mode = if matches.opt_present("numeric-sort") { SortMode::Numeric - } else if matches.opt_present("human-readable-sort") { - SortMode::HumanReadable + } else if matches.opt_present("human-numeric-sort") { + SortMode::HumanNumeric } else { SortMode::Default }; @@ -129,7 +129,7 @@ fn exec(files: Vec, settings: &Settings) { match settings.mode { SortMode::Numeric => lines.sort_by(numeric_compare), - SortMode::HumanReadable => lines.sort_by(human_readable_size_compare), + SortMode::HumanNumeric => lines.sort_by(human_numeric_size_compare), SortMode::Default => lines.sort() } @@ -174,7 +174,7 @@ fn numeric_compare(a: &String, b: &String) -> Ordering { } } -fn human_readable_convert(a: &String) -> f64 { +fn human_numeric_convert(a: &String) -> f64 { let int_iter = a.chars(); let suffix_iter = a.chars(); let int_str: String = int_iter.take_while(|c| c.is_numeric()).collect(); @@ -196,9 +196,9 @@ fn human_readable_convert(a: &String) -> f64 { /// Compare two strings as if they are human readable sizes. /// AKA 1M > 100k -fn human_readable_size_compare(a: &String, b: &String) -> Ordering { - let fa = human_readable_convert(a); - let fb = human_readable_convert(b); +fn human_numeric_size_compare(a: &String, b: &String) -> Ordering { + let fa = human_numeric_convert(a); + let fb = human_numeric_convert(b); if fa > fb { Ordering::Greater } From cc635650513bfa4f309f391eb1677ade735ef6c5 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 25 Mar 2016 00:34:20 -0400 Subject: [PATCH 3/7] sort: add month sort --- src/sort/sort.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/sort/sort.rs b/src/sort/sort.rs index 74cfcdeaf..183b4d360 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -32,6 +32,7 @@ static THOUSANDS_SEP: char = ','; enum SortMode { Numeric, HumanNumeric, + Month, Default, } @@ -57,6 +58,7 @@ pub fn uumain(args: Vec) -> i32 { opts.optflag("n", "numeric-sort", "compare according to string numerical value"); opts.optflag("h", "human-numeric-sort", "compare according to human readable sizes, eg 1M > 100k"); + opts.optflag("M", "month-sort", "compare according to month name abbreviation"); opts.optflag("r", "reverse", "reverse the output"); opts.optflag("h", "help", "display this help and exit"); opts.optflag("", "version", "output version information and exit"); @@ -90,6 +92,8 @@ With no FILE, or when FILE is -, read standard input.", NAME, VERSION); SortMode::Numeric } else if matches.opt_present("human-numeric-sort") { SortMode::HumanNumeric + } else if matches.opt_present("month-sort") { + SortMode::Month } else { SortMode::Default }; @@ -130,6 +134,7 @@ fn exec(files: Vec, settings: &Settings) { match settings.mode { SortMode::Numeric => lines.sort_by(numeric_compare), SortMode::HumanNumeric => lines.sort_by(human_numeric_size_compare), + SortMode::Month => lines.sort_by(month_compare), SortMode::Default => lines.sort() } @@ -208,7 +213,46 @@ fn human_numeric_size_compare(a: &String, b: &String) -> Ordering { else { Ordering::Equal } +} +#[derive(Eq, Ord, PartialEq, PartialOrd)] +enum Month { + Unknown = 0, + January = 1, + February = 2, + March = 3, + April = 4, + May = 5, + June = 6, + July = 7, + August = 8, + September = 9, + October = 10, + November = 11, + December = 12, +} + +/// Parse the beginning string into a Month, returning Month::Unknown on errors. +fn month_parse(line: &String) -> Month { + match line.split_whitespace().next().unwrap().to_uppercase().as_ref() { + "JAN" => Month::January, + "FEB" => Month::February, + "MAR" => Month::March, + "APR" => Month::April, + "MAY" => Month::May, + "JUN" => Month::June, + "JUL" => Month::July, + "AUG" => Month::August, + "SEP" => Month::September, + "OCT" => Month::October, + "NOV" => Month::November, + "DEC" => Month::December, + _ => Month::Unknown, + } +} + +fn month_compare(a: &String, b: &String) -> Ordering { + month_parse(a).cmp(&month_parse(b)) } fn print_sorted>(iter: T, outfile: &Option) where S: std::fmt::Display { From 2cdccb10bb91651e364e7d7e798f683fee620e9f Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 25 Mar 2016 00:40:12 -0400 Subject: [PATCH 4/7] sort: fix whitespace and spelling --- src/sort/sort.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sort/sort.rs b/src/sort/sort.rs index 183b4d360..02a4d2132 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -148,11 +148,11 @@ fn exec(files: Vec, settings: &Settings) { } /// Parse the beginning string into an f64, returning -inf instead of NaN on errors. -fn permissive_f64_parse(a: &str) -> f64{ - //Maybe should be split on non-digit, but then 10e100 won't parse properly. - //On the flip side, this will give NEG_INFINITY for "1,234", which might be OK - //because there's no way to handle both CSV and thousands separators without a new flag. - //GNU sort treats "1,234" as "1" in numeric, so maybe it's fine. +fn permissive_f64_parse(a: &str) -> f64 { + // Maybe should be split on non-digit, but then 10e100 won't parse properly. + // On the flip side, this will give NEG_INFINITY for "1,234", which might be OK + // because there's no way to handle both CSV and thousands separators without a new flag. + // GNU sort treats "1,234" as "1" in numeric, so maybe it's fine. let sa: &str = a.split_whitespace().next().unwrap(); match sa.parse::() { Ok(a) => a, @@ -160,14 +160,14 @@ fn permissive_f64_parse(a: &str) -> f64{ } } -/// Compares two floating point numbers, with errors being assumned to be -inf. +/// Compares two floating point numbers, with errors being assumed to be -inf. /// Stops coercing at the first whitespace char, so 1e2 will parse as 100 but /// 1,000 will parse as -inf. fn numeric_compare(a: &String, b: &String) -> Ordering { let fa = permissive_f64_parse(a); let fb = permissive_f64_parse(b); - //f64::cmp isn't implemented because NaN messes with it - //but we sidestep that with permissive_f64_parse so just fake it + // f64::cmp isn't implemented because NaN messes with it + // but we sidestep that with permissive_f64_parse so just fake it if fa > fb { Ordering::Greater } From 55c0b1786fabf0c3242cbfe8e13f5bd3eda483c1 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 25 Mar 2016 00:47:17 -0400 Subject: [PATCH 5/7] tests/sort: add tests for month sort --- tests/fixtures/sort/month1.ans | 7 +++++++ tests/fixtures/sort/month1.txt | 7 +++++++ tests/sort.rs | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 tests/fixtures/sort/month1.ans create mode 100644 tests/fixtures/sort/month1.txt diff --git a/tests/fixtures/sort/month1.ans b/tests/fixtures/sort/month1.ans new file mode 100644 index 000000000..f3c462bc3 --- /dev/null +++ b/tests/fixtures/sort/month1.ans @@ -0,0 +1,7 @@ +N/A Ut enim ad minim veniam, quis +Jan Lorem ipsum dolor sit amet +mar laboris nisi ut aliquip ex ea +May sed do eiusmod tempor incididunt +JUN nostrud exercitation ullamco +Oct ut labore et dolore magna aliqua +Dec consectetur adipiscing elit diff --git a/tests/fixtures/sort/month1.txt b/tests/fixtures/sort/month1.txt new file mode 100644 index 000000000..da4a02a71 --- /dev/null +++ b/tests/fixtures/sort/month1.txt @@ -0,0 +1,7 @@ +Jan Lorem ipsum dolor sit amet +Dec consectetur adipiscing elit +May sed do eiusmod tempor incididunt +Oct ut labore et dolore magna aliqua +N/A Ut enim ad minim veniam, quis +JUN nostrud exercitation ullamco +mar laboris nisi ut aliquip ex ea diff --git a/tests/sort.rs b/tests/sort.rs index 3ebb87f6c..25f47163c 100644 --- a/tests/sort.rs +++ b/tests/sort.rs @@ -41,6 +41,11 @@ fn human1() { test_helper(&String::from("human1"), &String::from("-H")); } +#[test] +fn month1() { + test_helper(&String::from("month1"), &String::from("-M")); +} + fn numeric_helper(test_num: isize) { test_helper(&format!("numeric{}", test_num), &String::from("-n")) } From faedb2dd2e4517a91ef9f2162432022c8987eb0b Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 25 Mar 2016 00:47:46 -0400 Subject: [PATCH 6/7] tests/sort: fix flag for human numeric test --- tests/sort.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sort.rs b/tests/sort.rs index 25f47163c..ef6bdc4b1 100644 --- a/tests/sort.rs +++ b/tests/sort.rs @@ -38,7 +38,7 @@ fn numeric6() { #[test] fn human1() { - test_helper(&String::from("human1"), &String::from("-H")); + test_helper(&String::from("human1"), &String::from("-h")); } #[test] From 491320747bea420083cd4475cdd3ef836af77663 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Fri, 25 Mar 2016 00:50:51 -0400 Subject: [PATCH 7/7] sort: remove explicit enum values --- src/sort/sort.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sort/sort.rs b/src/sort/sort.rs index 02a4d2132..cc217ae80 100644 --- a/src/sort/sort.rs +++ b/src/sort/sort.rs @@ -217,19 +217,19 @@ fn human_numeric_size_compare(a: &String, b: &String) -> Ordering { #[derive(Eq, Ord, PartialEq, PartialOrd)] enum Month { - Unknown = 0, - January = 1, - February = 2, - March = 3, - April = 4, - May = 5, - June = 6, - July = 7, - August = 8, - September = 9, - October = 10, - November = 11, - December = 12, + Unknown, + January, + February, + March, + April, + May, + June, + July, + August, + September, + October, + November, + December, } /// Parse the beginning string into a Month, returning Month::Unknown on errors.