diff --git a/shell.nix b/shell.nix index f5c61ac0a8..d528cf8491 100644 --- a/shell.nix +++ b/shell.nix @@ -27,6 +27,4 @@ let in stdenv.mkDerivation { name = "nushell-rust"; buildInputs = nu-deps ++ rust; - RUST_SRC_PATH = "${nightly}/lib/rustlib/src/rust/src"; - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; } diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 41a611f8cf..56a3f10868 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -33,38 +33,52 @@ impl WholeStreamCommand for FromSSV { } } -fn from_ssv_string_to_value( - s: &str, - headerless: bool, - tag: impl Into, -) -> Option> { - let mut lines = s.lines().filter(|l| !l.is_empty()); +fn string_to_table(s: &str, headerless: bool) -> Vec> { + let mut lines = s.lines().filter(|l| !l.trim().is_empty()); let headers = lines - .next()? + .next() + .unwrap() .split_whitespace() .map(|s| s.to_owned()) .collect::>(); let header_row = if headerless { - (0..headers.len()) - .map(|i| format!("Column{}", i + 1)) + (1..=headers.len()) + .map(|i| format!("Column{}", i)) .collect::>() } else { headers }; - let tag = tag.into(); - let rows = lines + lines .map(|l| { - let mut row = TaggedDictBuilder::new(tag); - for (column, value) in header_row.iter().zip(l.split_whitespace()) { - row.insert_tagged( - column.to_owned(), - Value::Primitive(Primitive::String(String::from(value))).tagged(tag), + header_row + .iter() + .zip(l.split_whitespace()) + .map(|(a, b)| (String::from(a), String::from(b))) + .collect() + }) + .collect() +} + +fn from_ssv_string_to_value( + s: &str, + headerless: bool, + tag: impl Into, +) -> Option> { + let tag = tag.into(); + let rows = string_to_table(s, headerless) + .iter() + .map(|row| { + let mut tagged_dict = TaggedDictBuilder::new(tag); + for (col, entry) in row { + tagged_dict.insert_tagged( + col, + Value::Primitive(Primitive::String(String::from(entry))).tagged(tag), ) } - row.into_tagged_value() + tagged_dict.into_tagged_value() }) .collect(); @@ -118,3 +132,48 @@ fn from_ssv( Ok(stream.to_output_stream()) } + +#[cfg(test)] +mod tests { + use super::*; + fn owned(x: &str, y: &str) -> (String, String) { + (String::from(x), String::from(y)) + } + + #[test] + fn it_trims_empty_and_whitespace_only_lines() { + let input = r#" + + a b + + 1 2 + + 3 4 + "#; + let result = string_to_table(input, false); + assert_eq!( + result, + vec![ + vec![owned("a", "1"), owned("b", "2")], + vec![owned("a", "3"), owned("b", "4")] + ] + ); + } + + #[test] + fn it_ignores_headers_when_headerless() { + let input = r#" + a b + 1 2 + 3 4 + "#; + let result = string_to_table(input, true); + assert_eq!( + result, + vec![ + vec![owned("Column1", "1"), owned("Column2", "2")], + vec![owned("Column1", "3"), owned("Column2", "4")] + ] + ); + } +}