From de8e2841a0b5535a2ec7573b3d00ea7bb33916ed Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 3 Jul 2020 01:43:55 -0700 Subject: [PATCH] Numbered `each` (#2100) * Add --numbered to each * Fix example tester and add numbered each --- crates/nu-cli/src/commands/compact.rs | 2 +- crates/nu-cli/src/commands/each.rs | 85 +++++++++++++++++++-------- crates/nu-cli/src/examples.rs | 21 ++++++- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/crates/nu-cli/src/commands/compact.rs b/crates/nu-cli/src/commands/compact.rs index 499606da60..c746e3d5b5 100644 --- a/crates/nu-cli/src/commands/compact.rs +++ b/crates/nu-cli/src/commands/compact.rs @@ -40,7 +40,7 @@ impl WholeStreamCommand for Compact { vec![ Example { description: "Filter out all null entries in a list", - example: "echo [1 2 $null 3 $null $null] | compact target", + example: "echo [1 2 $null 3 $null $null] | compact", result: Some(vec![ UntaggedValue::int(1).into(), UntaggedValue::int(2).into(), diff --git a/crates/nu-cli/src/commands/each.rs b/crates/nu-cli/src/commands/each.rs index 76eb5adf63..e2cd376ada 100644 --- a/crates/nu-cli/src/commands/each.rs +++ b/crates/nu-cli/src/commands/each.rs @@ -7,14 +7,16 @@ use futures::stream::once; use nu_errors::ShellError; use nu_protocol::{ hir::Block, hir::Expression, hir::SpannedExpression, hir::Synthetic, Scope, Signature, - SyntaxShape, UntaggedValue, Value, + SyntaxShape, TaggedDictBuilder, UntaggedValue, Value, }; +use nu_source::Tagged; pub struct Each; #[derive(Deserialize)] pub struct EachArgs { block: Block, + numbered: Tagged, } #[async_trait] @@ -24,11 +26,13 @@ impl WholeStreamCommand for Each { } fn signature(&self) -> Signature { - Signature::build("each").required( - "block", - SyntaxShape::Block, - "the block to run on each row", - ) + Signature::build("each") + .required("block", SyntaxShape::Block, "the block to run on each row") + .switch( + "numbered", + "returned a numbered item ($it.index and $it.item)", + Some('n'), + ) } fn usage(&self) -> &str { @@ -45,6 +49,11 @@ impl WholeStreamCommand for Each { fn examples(&self) -> Vec { vec![ + Example { + description: "Echo the sum of each row", + example: "echo [[1 2] [3 4]] | each { echo $it | math sum }", + result: None, + }, Example { description: "Echo the square of each integer", example: "echo [1 2 3] | each { echo $(= $it * $it) }", @@ -55,12 +64,10 @@ impl WholeStreamCommand for Each { ]), }, Example { - description: "Echo the sum of each row", - example: "echo [[1 2] [3 4]] | each { echo $it | math sum }", - result: Some(vec![ - UntaggedValue::int(3).into(), - UntaggedValue::int(7).into(), - ]), + description: "Number each item and echo a message", + example: + "echo ['bob' 'fred'] | each --numbered { echo `{{$it.index}} is {{$it.item}}` }", + result: Some(vec![Value::from("0 is bob"), Value::from("1 is fred")]), }, ] } @@ -111,21 +118,47 @@ async fn each( let context = Arc::new(Context::from_raw(&raw_args, ®istry)); let (each_args, input): (EachArgs, _) = raw_args.process(®istry).await?; let block = Arc::new(each_args.block); - Ok(input - .then(move |input| { - let block = block.clone(); - let scope = scope.clone(); - let head = head.clone(); - let context = context.clone(); - async { - match process_row(block, scope, head, context, input).await { - Ok(s) => s, - Err(e) => OutputStream::one(Err(e)), + + if each_args.numbered.item { + Ok(input + .enumerate() + .then(move |input| { + let block = block.clone(); + let scope = scope.clone(); + let head = head.clone(); + let context = context.clone(); + + let mut dict = TaggedDictBuilder::new(input.1.tag()); + dict.insert_untagged("index", UntaggedValue::int(input.0)); + dict.insert_value("item", input.1); + + async { + match process_row(block, scope, head, context, dict.into_value()).await { + Ok(s) => s, + Err(e) => OutputStream::one(Err(e)), + } } - } - }) - .flatten() - .to_output_stream()) + }) + .flatten() + .to_output_stream()) + } else { + Ok(input + .then(move |input| { + let block = block.clone(); + let scope = scope.clone(); + let head = head.clone(); + let context = context.clone(); + + async { + match process_row(block, scope, head, context, input).await { + Ok(s) => s, + Err(e) => OutputStream::one(Err(e)), + } + } + }) + .flatten() + .to_output_stream()) + } } #[cfg(test)] diff --git a/crates/nu-cli/src/examples.rs b/crates/nu-cli/src/examples.rs index 8a2f7f8528..bb81029b25 100644 --- a/crates/nu-cli/src/examples.rs +++ b/crates/nu-cli/src/examples.rs @@ -6,7 +6,7 @@ use nu_protocol::hir::ClassifiedBlock; use nu_protocol::{ShellTypeName, Value}; use crate::commands::classified::block::run_block; -use crate::commands::{whole_stream_command, Echo}; +use crate::commands::{whole_stream_command, BuildString, Echo}; use crate::context::Context; use crate::stream::InputStream; use crate::WholeStreamCommand; @@ -14,8 +14,10 @@ use crate::WholeStreamCommand; pub fn test(cmd: impl WholeStreamCommand + 'static) { let examples = cmd.examples(); let mut base_context = Context::basic().expect("could not create basic context"); + base_context.add_commands(vec![ whole_stream_command(Echo {}), + whole_stream_command(BuildString {}), whole_stream_command(cmd), ]); @@ -24,12 +26,27 @@ pub fn test(cmd: impl WholeStreamCommand + 'static) { let block = parse_line(example.example, &mut ctx).expect("failed to parse example"); if let Some(expected) = example.result { let result = block_on(evaluate_block(block, &mut ctx)).expect("failed to run example"); + + let errors = ctx.get_errors(); + + assert!( + errors.is_empty(), + "errors while running command.\ncommand: {}\nerrors: {:?}", + example.example, + errors + ); + + assert!(expected.len() == result.len(), "example command produced unexpected number of results.\ncommand: {}\nexpected number: {}\nactual: {}", + example.example, + expected.len(), + result.len(),); + assert!( expected .iter() .zip(result.iter()) .all(|(e, a)| values_equal(e, a)), - "example command produced unexpected result.\ncommand: {}\nexpected: {:?}\nactual:{:?}", + "example command produced unexpected result.\ncommand: {}\nexpected: {:?}\nactual: {:?}", example.example, expected, result,