diff --git a/crates/nu-command/src/commands.rs b/crates/nu-command/src/commands.rs index e55e1be02..972d5d087 100644 --- a/crates/nu-command/src/commands.rs +++ b/crates/nu-command/src/commands.rs @@ -163,7 +163,7 @@ pub(crate) use def::Def; pub(crate) use default::Default; pub(crate) use describe::Describe; pub(crate) use do_::Do; -pub(crate) use drop::Drop; +pub(crate) use drop::{Drop, DropColumn}; pub(crate) use du::Du; pub(crate) use each::Each; pub(crate) use each::EachGroup; diff --git a/crates/nu-command/src/commands/default_context.rs b/crates/nu-command/src/commands/default_context.rs index 045defc02..e85429511 100644 --- a/crates/nu-command/src/commands/default_context.rs +++ b/crates/nu-command/src/commands/default_context.rs @@ -114,6 +114,7 @@ pub fn create_default_context(interactive: bool) -> Result>, +} + +#[async_trait] +impl WholeStreamCommand for SubCommand { + fn name(&self) -> &str { + "drop column" + } + + fn signature(&self) -> Signature { + Signature::build("drop column").optional( + "columns", + SyntaxShape::Number, + "starting from the end, the number of columns to remove", + ) + } + + fn usage(&self) -> &str { + "Remove the last number of columns. If you want to remove columns by name, try 'reject'." + } + + async fn run(&self, args: CommandArgs) -> Result { + drop(args).await + } + + fn examples(&self) -> Vec { + use nu_protocol::{row, Value}; + + vec![Example { + description: "Remove the last column of a table", + example: "echo [[lib, extension]; [nu-lib, rs] [nu-core, rb]] | drop column", + result: Some(vec![ + row! { "lib".into() => Value::from("nu-lib") }, + row! { "lib".into() => Value::from("nu-core") }, + ]), + }] + } +} + +async fn drop(args: CommandArgs) -> Result { + let (Arguments { columns }, input) = args.process().await?; + + let to_drop = if let Some(quantity) = columns { + *quantity as usize + } else { + 1 + }; + + Ok(input + .map(move |item| { + let headers = item.data_descriptors(); + + let descs = match headers.len() { + 0 => &headers[..], + n if to_drop > n => &[], + n => &headers[..n - to_drop], + }; + + select_fields(&item, descs, item.tag()) + }) + .map(ReturnSuccess::value) + .to_output_stream()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn examples_work_as_expected() -> Result<(), ShellError> { + use crate::examples::test as test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/commands/drop.rs b/crates/nu-command/src/commands/drop/command.rs similarity index 82% rename from crates/nu-command/src/commands/drop.rs rename to crates/nu-command/src/commands/drop/command.rs index 684b3e268..289899a74 100644 --- a/crates/nu-command/src/commands/drop.rs +++ b/crates/nu-command/src/commands/drop/command.rs @@ -4,15 +4,15 @@ use nu_errors::ShellError; use nu_protocol::{Signature, SyntaxShape, UntaggedValue}; use nu_source::Tagged; -pub struct Drop; +pub struct Command; #[derive(Deserialize)] -pub struct DropArgs { +pub struct Arguments { rows: Option>, } #[async_trait] -impl WholeStreamCommand for Drop { +impl WholeStreamCommand for Command { fn name(&self) -> &str { "drop" } @@ -26,7 +26,7 @@ impl WholeStreamCommand for Drop { } fn usage(&self) -> &str { - "Remove the last number of rows. If you want to remove columns, try 'reject'." + "Remove the last number of rows. If you want to remove columns, try 'drop column'." } async fn run(&self, args: CommandArgs) -> Result { @@ -53,7 +53,7 @@ impl WholeStreamCommand for Drop { } async fn drop(args: CommandArgs) -> Result { - let (DropArgs { rows }, input) = args.process().await?; + let (Arguments { rows }, input) = args.process().await?; let v: Vec<_> = input.into_vec().await; let rows_to_drop = if let Some(quantity) = rows { @@ -76,16 +76,3 @@ async fn drop(args: CommandArgs) -> Result { futures::stream::iter(iter).to_output_stream() }) } - -#[cfg(test)] -mod tests { - use super::Drop; - use super::ShellError; - - #[test] - fn examples_work_as_expected() -> Result<(), ShellError> { - use crate::examples::test as test_examples; - - test_examples(Drop {}) - } -} diff --git a/crates/nu-command/src/commands/drop/mod.rs b/crates/nu-command/src/commands/drop/mod.rs new file mode 100644 index 000000000..428affff8 --- /dev/null +++ b/crates/nu-command/src/commands/drop/mod.rs @@ -0,0 +1,5 @@ +mod column; +mod command; + +pub use column::SubCommand as DropColumn; +pub use command::Command as Drop; diff --git a/crates/nu-command/tests/commands/drop.rs b/crates/nu-command/tests/commands/drop.rs index ec91f7efb..1ce67368e 100644 --- a/crates/nu-command/tests/commands/drop.rs +++ b/crates/nu-command/tests/commands/drop.rs @@ -1,23 +1,68 @@ use nu_test_support::{nu, pipeline}; #[test] -fn drop_rows() { +fn columns() { let actual = nu!( - cwd: "tests/fixtures/formats", - r#"echo '[{"foo": 3}, {"foo": 8}, {"foo": 4}]' | from json | drop 2 | get foo | math sum "# + cwd: ".", pipeline(r#" + echo [ + [arepas, color]; + + [3, white] + [8, yellow] + [4, white] + ] + | drop column + | get + | count + "#) + ); + + assert_eq!(actual.out, "1"); +} + +#[test] +fn more_columns_than_table_has() { + let actual = nu!( + cwd: ".", pipeline(r#" + echo [ + [arepas, color]; + + [3, white] + [8, yellow] + [4, white] + ] + | drop column 3 + | get + | empty? + "#) + ); + + assert_eq!(actual.out, "true"); +} + +#[test] +fn rows() { + let actual = nu!( + cwd: ".", pipeline(r#" + echo [ + [arepas]; + + [3] + [8] + [4] + ] + | drop 2 + | get arepas + | math sum + "#) ); assert_eq!(actual.out, "3"); } #[test] -fn drop_more_rows_than_table_has() { - let actual = nu!( - cwd: ".", pipeline( - r#" - date | drop 50 | count - "# - )); +fn more_rows_than_table_has() { + let actual = nu!(cwd: ".", "date | drop 50 | count"); assert_eq!(actual.out, "0"); }