forked from extern/nushell
Numbered each
(#2100)
* Add --numbered to each * Fix example tester and add numbered each
This commit is contained in:
parent
5cafead4a4
commit
de8e2841a0
@ -40,7 +40,7 @@ impl WholeStreamCommand for Compact {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Filter out all null entries in a list",
|
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![
|
result: Some(vec![
|
||||||
UntaggedValue::int(1).into(),
|
UntaggedValue::int(1).into(),
|
||||||
UntaggedValue::int(2).into(),
|
UntaggedValue::int(2).into(),
|
||||||
|
@ -7,14 +7,16 @@ use futures::stream::once;
|
|||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
hir::Block, hir::Expression, hir::SpannedExpression, hir::Synthetic, Scope, Signature,
|
hir::Block, hir::Expression, hir::SpannedExpression, hir::Synthetic, Scope, Signature,
|
||||||
SyntaxShape, UntaggedValue, Value,
|
SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,
|
||||||
};
|
};
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct Each;
|
pub struct Each;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EachArgs {
|
pub struct EachArgs {
|
||||||
block: Block,
|
block: Block,
|
||||||
|
numbered: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -24,11 +26,13 @@ impl WholeStreamCommand for Each {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("each").required(
|
Signature::build("each")
|
||||||
"block",
|
.required("block", SyntaxShape::Block, "the block to run on each row")
|
||||||
SyntaxShape::Block,
|
.switch(
|
||||||
"the block to run on each row",
|
"numbered",
|
||||||
)
|
"returned a numbered item ($it.index and $it.item)",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -45,6 +49,11 @@ impl WholeStreamCommand for Each {
|
|||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Echo the sum of each row",
|
||||||
|
example: "echo [[1 2] [3 4]] | each { echo $it | math sum }",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Echo the square of each integer",
|
description: "Echo the square of each integer",
|
||||||
example: "echo [1 2 3] | each { echo $(= $it * $it) }",
|
example: "echo [1 2 3] | each { echo $(= $it * $it) }",
|
||||||
@ -55,12 +64,10 @@ impl WholeStreamCommand for Each {
|
|||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Echo the sum of each row",
|
description: "Number each item and echo a message",
|
||||||
example: "echo [[1 2] [3 4]] | each { echo $it | math sum }",
|
example:
|
||||||
result: Some(vec![
|
"echo ['bob' 'fred'] | each --numbered { echo `{{$it.index}} is {{$it.item}}` }",
|
||||||
UntaggedValue::int(3).into(),
|
result: Some(vec![Value::from("0 is bob"), Value::from("1 is fred")]),
|
||||||
UntaggedValue::int(7).into(),
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -111,21 +118,47 @@ async fn each(
|
|||||||
let context = Arc::new(Context::from_raw(&raw_args, ®istry));
|
let context = Arc::new(Context::from_raw(&raw_args, ®istry));
|
||||||
let (each_args, input): (EachArgs, _) = raw_args.process(®istry).await?;
|
let (each_args, input): (EachArgs, _) = raw_args.process(®istry).await?;
|
||||||
let block = Arc::new(each_args.block);
|
let block = Arc::new(each_args.block);
|
||||||
Ok(input
|
|
||||||
.then(move |input| {
|
if each_args.numbered.item {
|
||||||
let block = block.clone();
|
Ok(input
|
||||||
let scope = scope.clone();
|
.enumerate()
|
||||||
let head = head.clone();
|
.then(move |input| {
|
||||||
let context = context.clone();
|
let block = block.clone();
|
||||||
async {
|
let scope = scope.clone();
|
||||||
match process_row(block, scope, head, context, input).await {
|
let head = head.clone();
|
||||||
Ok(s) => s,
|
let context = context.clone();
|
||||||
Err(e) => OutputStream::one(Err(e)),
|
|
||||||
|
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()
|
||||||
.flatten()
|
.to_output_stream())
|
||||||
.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)]
|
#[cfg(test)]
|
||||||
|
@ -6,7 +6,7 @@ use nu_protocol::hir::ClassifiedBlock;
|
|||||||
use nu_protocol::{ShellTypeName, Value};
|
use nu_protocol::{ShellTypeName, Value};
|
||||||
|
|
||||||
use crate::commands::classified::block::run_block;
|
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::context::Context;
|
||||||
use crate::stream::InputStream;
|
use crate::stream::InputStream;
|
||||||
use crate::WholeStreamCommand;
|
use crate::WholeStreamCommand;
|
||||||
@ -14,8 +14,10 @@ use crate::WholeStreamCommand;
|
|||||||
pub fn test(cmd: impl WholeStreamCommand + 'static) {
|
pub fn test(cmd: impl WholeStreamCommand + 'static) {
|
||||||
let examples = cmd.examples();
|
let examples = cmd.examples();
|
||||||
let mut base_context = Context::basic().expect("could not create basic context");
|
let mut base_context = Context::basic().expect("could not create basic context");
|
||||||
|
|
||||||
base_context.add_commands(vec![
|
base_context.add_commands(vec![
|
||||||
whole_stream_command(Echo {}),
|
whole_stream_command(Echo {}),
|
||||||
|
whole_stream_command(BuildString {}),
|
||||||
whole_stream_command(cmd),
|
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");
|
let block = parse_line(example.example, &mut ctx).expect("failed to parse example");
|
||||||
if let Some(expected) = example.result {
|
if let Some(expected) = example.result {
|
||||||
let result = block_on(evaluate_block(block, &mut ctx)).expect("failed to run example");
|
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!(
|
assert!(
|
||||||
expected
|
expected
|
||||||
.iter()
|
.iter()
|
||||||
.zip(result.iter())
|
.zip(result.iter())
|
||||||
.all(|(e, a)| values_equal(e, a)),
|
.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,
|
example.example,
|
||||||
expected,
|
expected,
|
||||||
result,
|
result,
|
||||||
|
Loading…
Reference in New Issue
Block a user