Remove deprecated --numbered flag from four commands (#7777)

# Description

Remove `--numbered` from ~~`for`~~, `each`, `par-each`, `reduce` and
`each while`. These all provide indexes (numbering) via the optional
second param to their closures.

EDIT: Closes #6986.

# User-Facing Changes

Every command that had `--numbered` listed as "deprecated" in their help
docs is affected.

# Tests + Formatting

Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
This commit is contained in:
Leon 2023-02-03 08:59:58 +10:00 committed by GitHub
parent 215ed141e7
commit 9945241b77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 202 additions and 541 deletions

View File

@ -34,7 +34,7 @@ impl Command for For {
.required("block", SyntaxShape::Block, "the block to run") .required("block", SyntaxShape::Block, "the block to run")
.switch( .switch(
"numbered", "numbered",
"returned a numbered item ($it.index and $it.item)", "return a numbered item ($it.index and $it.item)",
Some('n'), Some('n'),
) )
.creates_scope() .creates_scope()

View File

@ -9,9 +9,9 @@ pub fn test_examples(cmd: impl Command + 'static) {
#[cfg(test)] #[cfg(test)]
mod test_examples { mod test_examples {
use super::super::{ use super::super::{
Ansi, Date, Echo, From, If, Into, IntoString, Let, LetEnv, Math, MathEuler, MathPi, Ansi, Date, Echo, Enumerate, Flatten, From, Get, If, Into, IntoString, Let, LetEnv, Math,
MathRound, Path, Random, Split, SplitColumn, SplitRow, Str, StrJoin, StrLength, StrReplace, MathEuler, MathPi, MathRound, ParEach, Path, Random, Sort, SortBy, Split, SplitColumn,
Url, Values, Wrap, SplitRow, Str, StrJoin, StrLength, StrReplace, Update, Url, Values, Wrap,
}; };
use crate::{Break, Each, Mut, To}; use crate::{Break, Each, Mut, To};
use itertools::Itertools; use itertools::Itertools;
@ -61,35 +61,42 @@ mod test_examples {
// Base functions that are needed for testing // Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible // Try to keep this working set small to keep tests running as fast as possible
let mut working_set = StateWorkingSet::new(&engine_state); let mut working_set = StateWorkingSet::new(&engine_state);
working_set.add_decl(Box::new(Ansi));
working_set.add_decl(Box::new(Break));
working_set.add_decl(Box::new(Date));
working_set.add_decl(Box::new(Each)); working_set.add_decl(Box::new(Each));
working_set.add_decl(Box::new(Echo));
working_set.add_decl(Box::new(Enumerate));
working_set.add_decl(Box::new(Flatten));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(Get));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(Into));
working_set.add_decl(Box::new(IntoString));
working_set.add_decl(Box::new(Let)); working_set.add_decl(Box::new(Let));
working_set.add_decl(Box::new(LetEnv));
working_set.add_decl(Box::new(Math));
working_set.add_decl(Box::new(MathEuler));
working_set.add_decl(Box::new(MathPi));
working_set.add_decl(Box::new(MathRound));
working_set.add_decl(Box::new(Mut));
working_set.add_decl(Box::new(Path));
working_set.add_decl(Box::new(ParEach));
working_set.add_decl(Box::new(Random));
working_set.add_decl(Box::new(Sort));
working_set.add_decl(Box::new(SortBy));
working_set.add_decl(Box::new(Split));
working_set.add_decl(Box::new(SplitColumn));
working_set.add_decl(Box::new(SplitRow));
working_set.add_decl(Box::new(Str)); working_set.add_decl(Box::new(Str));
working_set.add_decl(Box::new(StrJoin)); working_set.add_decl(Box::new(StrJoin));
working_set.add_decl(Box::new(StrLength)); working_set.add_decl(Box::new(StrLength));
working_set.add_decl(Box::new(StrReplace)); working_set.add_decl(Box::new(StrReplace));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(To)); working_set.add_decl(Box::new(To));
working_set.add_decl(Box::new(Into));
working_set.add_decl(Box::new(IntoString));
working_set.add_decl(Box::new(Random));
working_set.add_decl(Box::new(Split));
working_set.add_decl(Box::new(SplitColumn));
working_set.add_decl(Box::new(SplitRow));
working_set.add_decl(Box::new(Math));
working_set.add_decl(Box::new(Path));
working_set.add_decl(Box::new(Date));
working_set.add_decl(Box::new(Url)); working_set.add_decl(Box::new(Url));
working_set.add_decl(Box::new(Update));
working_set.add_decl(Box::new(Values)); working_set.add_decl(Box::new(Values));
working_set.add_decl(Box::new(Ansi));
working_set.add_decl(Box::new(Wrap)); working_set.add_decl(Box::new(Wrap));
working_set.add_decl(Box::new(LetEnv));
working_set.add_decl(Box::new(Echo));
working_set.add_decl(Box::new(Break));
working_set.add_decl(Box::new(Mut));
working_set.add_decl(Box::new(MathEuler));
working_set.add_decl(Box::new(MathPi));
working_set.add_decl(Box::new(MathRound));
// Adding the command that is being tested to the working set // Adding the command that is being tested to the working set
working_set.add_decl(cmd); working_set.add_decl(cmd);

View File

@ -43,9 +43,14 @@ impl Command for All {
example: "[[status]; [UP] [UP]] | all {|el| $el.status == UP }", example: "[[status]; [UP] [UP]] | all {|el| $el.status == UP }",
result: Some(Value::test_bool(true)), result: Some(Value::test_bool(true)),
}, },
Example {
description: "Check that each item is a string",
example: "[foo bar 2 baz] | all { ($in | describe) == 'string' }",
result: Some(Value::test_bool(false)),
},
Example { Example {
description: "Check that all values are equal to twice their index", description: "Check that all values are equal to twice their index",
example: "[0 2 4 6] | all {|el ind| $el == $ind * 2 }", example: "[0 2 4 6] | enumerate | all {|i| $i.item == $i.index * 2 }",
result: Some(Value::test_bool(true)), result: Some(Value::test_bool(true)),
}, },
Example { Example {
@ -80,7 +85,7 @@ impl Command for All {
let ctrlc = engine_state.ctrlc.clone(); let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone(); let engine_state = engine_state.clone();
for (idx, value) in input.into_interruptible_iter(ctrlc).enumerate() { for value in input.into_interruptible_iter(ctrlc) {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -89,18 +94,6 @@ impl Command for All {
if let Some(var_id) = var_id { if let Some(var_id) = var_id {
stack.add_var(var_id, value.clone()); stack.add_var(var_id, value.clone());
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let eval = eval_block( let eval = eval_block(
&engine_state, &engine_state,

View File

@ -43,9 +43,14 @@ impl Command for Any {
example: "[[status]; [UP] [DOWN] [UP]] | any {|el| $el.status == DOWN }", example: "[[status]; [UP] [DOWN] [UP]] | any {|el| $el.status == DOWN }",
result: Some(Value::test_bool(true)), result: Some(Value::test_bool(true)),
}, },
Example {
description: "Check that any item is a string",
example: "[1 2 3 4] | any { ($in | describe) == 'string' }",
result: Some(Value::test_bool(false)),
},
Example { Example {
description: "Check if any value is equal to twice its own index", description: "Check if any value is equal to twice its own index",
example: "[9 8 7 6] | any {|el ind| $el == $ind * 2 }", example: "[9 8 7 6] | enumerate | any {|i| $i.item == $i.index * 2 }",
result: Some(Value::test_bool(true)), result: Some(Value::test_bool(true)),
}, },
Example { Example {
@ -80,7 +85,7 @@ impl Command for Any {
let ctrlc = engine_state.ctrlc.clone(); let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone(); let engine_state = engine_state.clone();
for (idx, value) in input.into_interruptible_iter(ctrlc).enumerate() { for value in input.into_interruptible_iter(ctrlc) {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -89,18 +94,6 @@ impl Command for Any {
if let Some(var_id) = var_id { if let Some(var_id) = var_id {
stack.add_var(var_id, value.clone()); stack.add_var(var_id, value.clone());
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let eval = eval_block( let eval = eval_block(
&engine_state, &engine_state,

View File

@ -35,21 +35,19 @@ with 'transpose' first."#
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("each") Signature::build("each")
.input_output_types(vec![( .input_output_types(vec![
(
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
)]) ),
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
])
.required( .required(
"closure", "closure",
SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])), SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])),
"the closure to run", "the closure to run",
) )
.switch("keep-empty", "keep empty result cells", Some('k')) .switch("keep-empty", "keep empty result cells", Some('k'))
.switch(
"numbered",
"iterate with an index (deprecated; use a two-parameter closure instead)",
Some('n'),
)
.category(Category::Filters) .category(Category::Filters)
} }
@ -96,7 +94,7 @@ with 'transpose' first."#
}), }),
}, },
Example { Example {
example: r#"[1 2 3] | each {|el ind| if $el == 2 { $"found 2 at ($ind)!"} }"#, example: r#"[1 2 3] | enumerate | each {|e| if $e.item == 2 { $"found 2 at ($e.index)!"} }"#,
description: description:
"Iterate over each element, producing a list showing indexes of any 2s", "Iterate over each element, producing a list showing indexes of any 2s",
result: Some(Value::List { result: Some(Value::List {
@ -106,7 +104,7 @@ with 'transpose' first."#
}, },
Example { Example {
example: r#"[1 2 3] | each --keep-empty {|e| if $e == 2 { "found 2!"} }"#, example: r#"[1 2 3] | each --keep-empty {|e| if $e == 2 { "found 2!"} }"#,
description: "Iterate over each element, keeping all results", description: "Iterate over each element, keeping null results",
result: Some(Value::List { result: Some(Value::List {
vals: stream_test_2, vals: stream_test_2,
span: Span::test_data(), span: Span::test_data(),
@ -124,7 +122,6 @@ with 'transpose' first."#
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let capture_block: Closure = call.req(engine_state, stack, 0)?; let capture_block: Closure = call.req(engine_state, stack, 0)?;
let numbered = call.has_flag("numbered");
let keep_empty = call.has_flag("keep-empty"); let keep_empty = call.has_flag("keep-empty");
let metadata = input.metadata(); let metadata = input.metadata();
@ -144,11 +141,8 @@ with 'transpose' first."#
PipelineData::Value(Value::Range { .. }, ..) PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..) | PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input | PipelineData::ListStream { .. } => Ok(input
// To enumerate over the input (for the index argument),
// it must be converted into an iterator using into_iter().
.into_iter() .into_iter()
.enumerate() .map_while(move |x| {
.map_while(move |(idx, x)| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -156,39 +150,9 @@ with 'transpose' first."#
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
// -n changes the first argument into an {index, item} record.
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let input_span = x.span(); let input_span = x.span();
match eval_block_with_early_return( match eval_block_with_early_return(
@ -214,8 +178,7 @@ with 'transpose' first."#
.. ..
} => Ok(stream } => Ok(stream
.into_iter() .into_iter()
.enumerate() .map_while(move |x| {
.map_while(move |(idx, x)| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -229,26 +192,9 @@ with 'transpose' first."#
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
let input_span = x.span(); let input_span = x.span();
match eval_block_with_early_return( match eval_block_with_early_return(

View File

@ -24,20 +24,18 @@ impl Command for EachWhile {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![( .input_output_types(vec![
(
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
)]) ),
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
])
.required( .required(
"closure", "closure",
SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])), SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])),
"the closure to run", "the closure to run",
) )
.switch(
"numbered",
"iterate with an index (deprecated; use a two-parameter closure instead)",
Some('n'),
)
.category(Category::Filters) .category(Category::Filters)
} }
@ -66,7 +64,7 @@ impl Command for EachWhile {
}), }),
}, },
Example { Example {
example: r#"[1 2 3] | each while {|el ind| if $el < 2 { $"value ($el) at ($ind)!"} }"#, example: r#"[1 2 3] | enumerate | each while {|e| if $e.item < 2 { $"value ($e.item) at ($e.index)!"} }"#,
description: "Iterate over each element, printing the matching value and its index", description: "Iterate over each element, printing the matching value and its index",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::test_string("value 1 at 0!")], vals: vec![Value::test_string("value 1 at 0!")],
@ -84,7 +82,6 @@ impl Command for EachWhile {
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let capture_block: Closure = call.req(engine_state, stack, 0)?; let capture_block: Closure = call.req(engine_state, stack, 0)?;
let numbered = call.has_flag("numbered");
let metadata = input.metadata(); let metadata = input.metadata();
let ctrlc = engine_state.ctrlc.clone(); let ctrlc = engine_state.ctrlc.clone();
@ -102,12 +99,9 @@ impl Command for EachWhile {
PipelineData::Value(Value::Range { .. }, ..) PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..) | PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input | PipelineData::ListStream { .. } => Ok(input
// To enumerate over the input (for the index argument),
// it must be converted into an iterator using into_iter().
// TODO: Could this be changed to .into_interruptible_iter(ctrlc) ? // TODO: Could this be changed to .into_interruptible_iter(ctrlc) ?
.into_iter() .into_iter()
.enumerate() .map_while(move |x| {
.map_while(move |(idx, x)| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -115,38 +109,9 @@ impl Command for EachWhile {
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
match eval_block_with_early_return( match eval_block_with_early_return(
&engine_state, &engine_state,
@ -175,8 +140,7 @@ impl Command for EachWhile {
.. ..
} => Ok(stream } => Ok(stream
.into_iter() .into_iter()
.enumerate() .map_while(move |x| {
.map_while(move |(idx, x)| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -189,26 +153,9 @@ impl Command for EachWhile {
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
match eval_block_with_early_return( match eval_block_with_early_return(
&engine_state, &engine_state,
@ -257,17 +204,7 @@ impl Command for EachWhile {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use nu_test_support::{nu, pipeline};
#[test]
fn uses_optional_index_argument() {
let actual = nu!(
cwd: ".", pipeline(
r#"[7 8 9 10] | each while {|el ind| $el + $ind } | to nuon"#
));
assert_eq!(actual.out, "[7, 9, 11, 13]");
}
#[test] #[test]
fn test_examples() { fn test_examples() {
use crate::test_examples; use crate::test_examples;

View File

@ -72,8 +72,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
// To enumerate over the input (for the index argument), // To enumerate over the input (for the index argument),
// it must be converted into an iterator using into_iter(). // it must be converted into an iterator using into_iter().
.into_iter() .into_iter()
.enumerate() .filter_map(move |x| {
.filter_map(move |(idx, x)| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -84,18 +83,6 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
match eval_block( match eval_block(
&engine_state, &engine_state,
@ -125,8 +112,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
.. ..
} => Ok(stream } => Ok(stream
.into_iter() .into_iter()
.enumerate() .filter_map(move |x| {
.filter_map(move |(idx, x)| {
// see note above about with_env() // see note above about with_env()
stack.with_env(&orig_env_vars, &orig_env_hidden); stack.with_env(&orig_env_vars, &orig_env_hidden);
@ -140,18 +126,6 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
match eval_block( match eval_block(
&engine_state, &engine_state,

View File

@ -64,27 +64,37 @@ impl Command for Insert {
], ],
span: Span::test_data(), span: Span::test_data(),
}), }),
}, Example { },
Example {
description: "Insert a new column into a table, populating all rows",
example: "[[project, lang]; ['Nushell', 'Rust']] | insert type 'shell'",
result: Some(Value::List { vals: vec![Value::Record { cols: vec!["project".into(), "lang".into(), "type".into()],
vals: vec![Value::test_string("Nushell"), Value::test_string("Rust"), Value::test_string("shell")], span: Span::test_data()}], span: Span::test_data()}),
},
Example {
description: "Insert a column with values equal to their row index, plus the value of 'foo' in each row", description: "Insert a column with values equal to their row index, plus the value of 'foo' in each row",
example: "[[foo]; [7] [8] [9]] | insert bar {|el ind| $el.foo + $ind }", example: "[[foo]; [7] [8] [9]] | enumerate | insert bar {|e| $e.item.foo + $e.index } | flatten",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::Record { vals: vec![Value::Record {
cols: vec!["foo".into(), "bar".into()], cols: vec!["index".into(), "foo".into(), "bar".into()],
vals: vec![ vals: vec![
Value::test_int(0),
Value::test_int(7), Value::test_int(7),
Value::test_int(7), Value::test_int(7),
], ],
span: Span::test_data(), span: Span::test_data(),
}, Value::Record { }, Value::Record {
cols: vec!["foo".into(), "bar".into()], cols: vec!["index".into(),"foo".into(), "bar".into()],
vals: vec![ vals: vec![
Value::test_int(1),
Value::test_int(8), Value::test_int(8),
Value::test_int(9), Value::test_int(9),
], ],
span: Span::test_data(), span: Span::test_data(),
}, Value::Record { }, Value::Record {
cols: vec!["foo".into(), "bar".into()], cols: vec!["index".into(), "foo".into(), "bar".into()],
vals: vec![ vals: vec![
Value::test_int(2),
Value::test_int(9), Value::test_int(9),
Value::test_int(11), Value::test_int(11),
], ],
@ -122,9 +132,6 @@ fn insert(
let orig_env_vars = stack.env_vars.clone(); let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone(); let orig_env_hidden = stack.env_hidden.clone();
// enumerate() can't be used here because it converts records into tables
// when combined with into_pipeline_data(). Hence, the index is tracked manually like so.
let mut idx: i64 = 0;
input.map( input.map(
move |mut input| { move |mut input| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
@ -138,13 +145,6 @@ fn insert(
stack.add_var(*var_id, input.clone()) stack.add_var(*var_id, input.clone())
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, Value::Int { val: idx, span });
}
idx += 1;
}
let output = eval_block( let output = eval_block(
&engine_state, &engine_state,

View File

@ -23,20 +23,18 @@ impl Command for ParEach {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("par-each") Signature::build("par-each")
.input_output_types(vec![( .input_output_types(vec![
(
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)), Type::List(Box::new(Type::Any)),
)]) ),
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
])
.required( .required(
"closure", "closure",
SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])), SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])),
"the closure to run", "the closure to run",
) )
.switch(
"numbered",
"iterate with an index (deprecated; use a two-parameter closure instead)",
Some('n'),
)
.category(Category::Filters) .category(Category::Filters)
} }
@ -49,8 +47,29 @@ impl Command for ParEach {
result: None, result: None,
}, },
Example { Example {
example: r#"[1 2 3] | par-each -n { |it| if $it.item == 2 { $"found 2 at ($it.index)!"} }"#, example: r#"[foo bar baz] | par-each {|e| $e + '!' } | sort"#,
description: "Iterate over each element, print the matching value and its index", description: "Output can still be sorted afterward",
result: Some(Value::List {
vals: vec![
Value::test_string("bar!"),
Value::test_string("baz!"),
Value::test_string("foo!"),
],
span: Span::test_data(),
}),
},
Example {
example: r#"1..3 | enumerate | par-each {|p| update item ($p.item * 2)} | sort-by item | get item"#,
description: "Enumerate and sort-by can be used to reconstruct the original order",
result: Some(Value::List {
vals: vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)],
span: Span::test_data(),
}),
},
Example {
example: r#"[1 2 3] | enumerate | par-each { |e| if $e.item == 2 { $"found 2 at ($e.index)!"} }"#,
description:
"Iterate over each element, producing a list showing indexes of any 2s",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::test_string("found 2 at 1!")], vals: vec![Value::test_string("found 2 at 1!")],
span: Span::test_data(), span: Span::test_data(),
@ -68,12 +87,10 @@ impl Command for ParEach {
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let capture_block: Closure = call.req(engine_state, stack, 0)?; let capture_block: Closure = call.req(engine_state, stack, 0)?;
let numbered = call.has_flag("numbered");
let metadata = input.metadata(); let metadata = input.metadata();
let ctrlc = engine_state.ctrlc.clone(); let ctrlc = engine_state.ctrlc.clone();
let block_id = capture_block.block_id; let block_id = capture_block.block_id;
let mut stack = stack.captures_to_stack(&capture_block.captures); let mut stack = stack.captures_to_stack(&capture_block.captures);
let span = call.head;
let redirect_stdout = call.redirect_stdout; let redirect_stdout = call.redirect_stdout;
let redirect_stderr = call.redirect_stderr; let redirect_stderr = call.redirect_stderr;
@ -81,47 +98,17 @@ impl Command for ParEach {
PipelineData::Empty => Ok(PipelineData::Empty), PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
.into_range_iter(ctrlc.clone())? .into_range_iter(ctrlc.clone())?
.enumerate()
.par_bridge() .par_bridge()
.map(move |(idx, x)| { .map(move |x| {
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let mut stack = stack.clone(); let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let val_span = x.span(); let val_span = x.span();
match eval_block_with_early_return( match eval_block_with_early_return(
@ -145,47 +132,17 @@ impl Command for ParEach {
.into_pipeline_data(ctrlc)), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }, ..) => Ok(val PipelineData::Value(Value::List { vals: val, .. }, ..) => Ok(val
.into_iter() .into_iter()
.enumerate()
.par_bridge() .par_bridge()
.map(move |(idx, x)| { .map(move |x| {
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let mut stack = stack.clone(); let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let val_span = x.span(); let val_span = x.span();
match eval_block_with_early_return( match eval_block_with_early_return(
@ -208,47 +165,17 @@ impl Command for ParEach {
.flatten() .flatten()
.into_pipeline_data(ctrlc)), .into_pipeline_data(ctrlc)),
PipelineData::ListStream(stream, ..) => Ok(stream PipelineData::ListStream(stream, ..) => Ok(stream
.enumerate()
.par_bridge() .par_bridge()
.map(move |(idx, x)| { .map(move |x| {
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let mut stack = stack.clone(); let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let val_span = x.span(); let val_span = x.span();
match eval_block_with_early_return( match eval_block_with_early_return(
@ -275,9 +202,8 @@ impl Command for ParEach {
stdout: Some(stream), stdout: Some(stream),
.. ..
} => Ok(stream } => Ok(stream
.enumerate()
.par_bridge() .par_bridge()
.map(move |(idx, x)| { .map(move |x| {
let x = match x { let x = match x {
Ok(x) => x, Ok(x) => x,
Err(err) => return Value::Error { error: err }.into_pipeline_data(), Err(err) => return Value::Error { error: err }.into_pipeline_data(),
@ -289,38 +215,9 @@ impl Command for ParEach {
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x.clone(),
],
span,
},
);
} else {
stack.add_var(*var_id, x.clone()); stack.add_var(*var_id, x.clone());
} }
} }
}
// Optional second index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
match eval_block_with_early_return( match eval_block_with_early_return(
engine_state, engine_state,
@ -366,17 +263,6 @@ impl Command for ParEach {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use nu_test_support::{nu, pipeline};
#[test]
fn uses_optional_index_argument() {
let actual = nu!(
cwd: ".", pipeline(
r#"[7,8,9,10] | par-each {|el ind| $ind } | describe"#
));
assert_eq!(actual.out, "list<int> (stream)");
}
#[test] #[test]
fn test_examples() { fn test_examples() {

View File

@ -16,7 +16,10 @@ impl Command for Reduce {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("reduce") Signature::build("reduce")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Any)]) .input_output_types(vec![
(Type::List(Box::new(Type::Any)), Type::Any),
(Type::Table(vec![]), Type::Any),
])
.named( .named(
"fold", "fold",
SyntaxShape::Any, SyntaxShape::Any,
@ -32,11 +35,6 @@ impl Command for Reduce {
])), ])),
"reducing function", "reducing function",
) )
.switch(
"numbered",
"iterate with an index (deprecated; use a 3-parameter closure instead)",
Some('n'),
)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@ -55,9 +53,10 @@ impl Command for Reduce {
result: Some(Value::test_int(10)), result: Some(Value::test_int(10)),
}, },
Example { Example {
example: "[ 8 7 6 ] | reduce {|it, acc, ind| $acc + $it + $ind }", example:
"[ 8 7 6 ] | enumerate | reduce -f 0 {|it, acc| $acc + $it.item + $it.index }",
description: "Sum values of a list, plus their indexes", description: "Sum values of a list, plus their indexes",
result: Some(Value::test_int(22)), result: Some(Value::test_int(24)),
}, },
Example { Example {
example: "[ 1 2 3 4 ] | reduce -f 10 {|it, acc| $acc + $it }", example: "[ 1 2 3 4 ] | reduce -f 10 {|it, acc| $acc + $it }",
@ -70,7 +69,7 @@ impl Command for Reduce {
result: Some(Value::test_string("ArXhur, KXng Xf Xhe BrXXXns")), result: Some(Value::test_string("ArXhur, KXng Xf Xhe BrXXXns")),
}, },
Example { Example {
example: r#"['foo.gz', 'bar.gz', 'baz.gz'] | reduce -f '' {|str all ind| $"($all)(if $ind != 0 {'; '})($ind + 1)-($str)" }"#, example: r#"['foo.gz', 'bar.gz', 'baz.gz'] | enumerate | reduce -f '' {|str all| $"($all)(if $str.index != 0 {'; '})($str.index + 1)-($str.item)" }"#,
description: description:
"Add ascending numbers to each of the filenames, and join with semicolons.", "Add ascending numbers to each of the filenames, and join with semicolons.",
result: Some(Value::test_string("1-foo.gz; 2-bar.gz; 3-baz.gz")), result: Some(Value::test_string("1-foo.gz; 2-bar.gz; 3-baz.gz")),
@ -88,7 +87,6 @@ impl Command for Reduce {
let span = call.head; let span = call.head;
let fold: Option<Value> = call.get_flag(engine_state, stack, "fold")?; let fold: Option<Value> = call.get_flag(engine_state, stack, "fold")?;
let numbered = call.has_flag("numbered");
let capture_block: Closure = call.req(engine_state, stack, 0)?; let capture_block: Closure = call.req(engine_state, stack, 0)?;
let mut stack = stack.captures_to_stack(&capture_block.captures); let mut stack = stack.captures_to_stack(&capture_block.captures);
let block = engine_state.get_block(capture_block.block_id); let block = engine_state.get_block(capture_block.block_id);
@ -104,10 +102,10 @@ impl Command for Reduce {
// it must be converted into an iterator using into_iter(). // it must be converted into an iterator using into_iter().
let mut input_iter = input.into_iter(); let mut input_iter = input.into_iter();
let (off, start_val) = if let Some(val) = fold { let start_val = if let Some(val) = fold {
(0, val) val
} else if let Some(val) = input_iter.next() { } else if let Some(val) = input_iter.next() {
(1, val) val
} else { } else {
return Err(ShellError::GenericError( return Err(ShellError::GenericError(
"Expected input".to_string(), "Expected input".to_string(),
@ -118,41 +116,11 @@ impl Command for Reduce {
)); ));
}; };
let mut acc = if numbered { let mut acc = start_val;
Value::Record {
cols: vec!["index".to_string(), "item".to_string()],
vals: vec![Value::Int { val: 0, span }, start_val],
span,
}
} else {
start_val
};
let mut input_iter = input_iter let mut input_iter = input_iter.peekable();
.enumerate()
.map(|(idx, x)| {
if numbered {
(
idx,
Value::Record {
cols: vec!["index".to_string(), "item".to_string()],
vals: vec![
Value::Int {
val: idx as i64 + off,
span,
},
x,
],
span,
},
)
} else {
(idx, x)
}
})
.peekable();
while let Some((idx, x)) = input_iter.next() { while let Some(x) = input_iter.next() {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
// a different set of environment variables. // a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop. // Hence, a 'cd' in the first loop won't affect the next loop.
@ -168,41 +136,9 @@ impl Command for Reduce {
// Accumulator argument // Accumulator argument
if let Some(var) = block.signature.get_positional(1) { if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
acc = if numbered {
if let Value::Record { .. } = &acc {
acc
} else {
Value::Record {
cols: vec!["index".to_string(), "item".to_string()],
vals: vec![
Value::Int {
val: idx as i64 + off,
span,
},
acc,
],
span,
}
}
} else {
acc
};
stack.add_var(*var_id, acc); stack.add_var(*var_id, acc);
} }
} }
// Optional third index argument
if let Some(var) = block.signature.get_positional(2) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
acc = eval_block( acc = eval_block(
engine_state, engine_state,

View File

@ -60,7 +60,7 @@ impl Command for Update {
}, },
Example { Example {
description: "Use in closure form for more involved updating logic", description: "Use in closure form for more involved updating logic",
example: "[[count fruit]; [1 'apple']] | update count {|row index| ($row.fruit | str length) + $index }", example: "[[count fruit]; [1 'apple']] | enumerate | update item.count {|e| ($e.item.fruit | str length) + $e.index } | get item",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::Record { vals: vec![Value::Record {
cols: vec!["count".into(), "fruit".into()], cols: vec!["count".into(), "fruit".into()],
@ -105,9 +105,6 @@ fn update(
let orig_env_vars = stack.env_vars.clone(); let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone(); let orig_env_hidden = stack.env_hidden.clone();
// enumerate() can't be used here because it converts records into tables
// when combined with into_pipeline_data(). Hence, the index is tracked manually like so.
let mut idx: i64 = 0;
input.map( input.map(
move |mut input| { move |mut input| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
@ -120,13 +117,6 @@ fn update(
stack.add_var(*var_id, input.clone()) stack.add_var(*var_id, input.clone())
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, Value::Int { val: idx, span });
}
idx += 1;
}
let output = eval_block( let output = eval_block(
&engine_state, &engine_state,

View File

@ -56,14 +56,25 @@ impl Command for Upsert {
description: "Update a record's value", description: "Update a record's value",
example: "{'name': 'nu', 'stars': 5} | upsert name 'Nushell'", example: "{'name': 'nu', 'stars': 5} | upsert name 'Nushell'",
result: Some(Value::Record { cols: vec!["name".into(), "stars".into()], vals: vec![Value::test_string("Nushell"), Value::test_int(5)], span: Span::test_data()}), result: Some(Value::Record { cols: vec!["name".into(), "stars".into()], vals: vec![Value::test_string("Nushell"), Value::test_int(5)], span: Span::test_data()}),
}, Example { },
Example {
description: "Update each row of a table",
example: "[[name lang]; [Nushell ''] [Reedline '']] | upsert lang 'Rust'",
result: Some(Value::List { vals: vec![
Value::Record { cols: vec!["name".into(), "lang".into()], vals: vec![Value::test_string("Nushell"), Value::test_string("Rust")], span: Span::test_data()},
Value::Record { cols: vec!["name".into(), "lang".into()], vals: vec![Value::test_string("Reedline"), Value::test_string("Rust")], span: Span::test_data()}
], span: Span::test_data()}),
},
Example {
description: "Insert a new entry into a single record", description: "Insert a new entry into a single record",
example: "{'name': 'nu', 'stars': 5} | upsert language 'Rust'", example: "{'name': 'nu', 'stars': 5} | upsert language 'Rust'",
result: Some(Value::Record { cols: vec!["name".into(), "stars".into(), "language".into()], vals: vec![Value::test_string("nu"), Value::test_int(5), Value::test_string("Rust")], span: Span::test_data()}), result: Some(Value::Record { cols: vec!["name".into(), "stars".into(), "language".into()], vals: vec![Value::test_string("nu"), Value::test_int(5), Value::test_string("Rust")], span: Span::test_data()}),
}, Example { }, Example {
description: "Use in closure form for more involved updating logic", description: "Use in closure form for more involved updating logic",
example: "[[count fruit]; [1 'apple']] | upsert count {|row index| ($row.fruit | str length) + $index }", example: "[[count fruit]; [1 'apple']] | enumerate | upsert item.count {|e| ($e.item.fruit | str length) + $e.index } | get item",
result: Some(Value::List { vals: vec![Value::Record { cols: vec!["count".into(), "fruit".into()], vals: vec![Value::test_int(5), Value::test_string("apple")], span: Span::test_data()}], span: Span::test_data()}), result: Some(Value::List { vals: vec![
Value::Record { cols: vec!["count".into(), "fruit".into()], vals: vec![Value::test_int(5), Value::test_string("apple")], span: Span::test_data()}],
span: Span::test_data()}),
}, },
Example { Example {
description: "Upsert an int into a list, updating an existing value based on the index", description: "Upsert an int into a list, updating an existing value based on the index",
@ -116,9 +127,6 @@ fn upsert(
let orig_env_vars = stack.env_vars.clone(); let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone(); let orig_env_hidden = stack.env_hidden.clone();
// enumerate() can't be used here because it converts records into tables
// when combined with into_pipeline_data(). Hence, the index is tracked manually like so.
let mut idx: i64 = 0;
input.map( input.map(
move |mut input| { move |mut input| {
// with_env() is used here to ensure that each iteration uses // with_env() is used here to ensure that each iteration uses
@ -131,13 +139,6 @@ fn upsert(
stack.add_var(*var_id, input.clone()) stack.add_var(*var_id, input.clone())
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, Value::Int { val: idx, span });
}
idx += 1;
}
let output = eval_block( let output = eval_block(
&engine_state, &engine_state,

View File

@ -70,8 +70,7 @@ not supported."#
let redirect_stderr = call.redirect_stderr; let redirect_stderr = call.redirect_stderr;
Ok(input Ok(input
.into_iter_strict(span)? .into_iter_strict(span)?
.enumerate() .filter_map(move |value| {
.filter_map(move |(idx, value)| {
stack.with_env(&orig_env_vars, &orig_env_hidden); stack.with_env(&orig_env_vars, &orig_env_hidden);
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
@ -79,18 +78,6 @@ not supported."#
stack.add_var(*var_id, value.clone()); stack.add_var(*var_id, value.clone());
} }
} }
// Optional index argument
if let Some(var) = block.signature.get_positional(1) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Int {
val: idx as i64,
span,
},
);
}
}
let result = eval_block( let result = eval_block(
&engine_state, &engine_state,
&mut stack, &mut stack,
@ -159,6 +146,11 @@ not supported."#
example: "ls | where modified >= (date now) - 2wk", example: "ls | where modified >= (date now) - 2wk",
result: None, result: None,
}, },
Example {
description: "Find files whose filenames don't begin with the correct sequential number",
example: "ls | where type == file | sort-by name -n | enumerate | where {|e| $e.item.name !~ $'^($e.index + 1)' } | each { get item }",
result: None,
},
] ]
} }
} }

View File

@ -109,10 +109,10 @@ fn early_exits_with_0_param_blocks() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn all_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[7 8 9] | all {|el ind| print $ind | true }"# r#"[7 8 9] | enumerate | all {|el| print $el.index | true }"#
)); ));
assert_eq!(actual.out, "012true"); assert_eq!(actual.out, "012true");

View File

@ -85,10 +85,10 @@ fn early_exits_with_0_param_blocks() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn any_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[7 8 9] | any {|el ind| print $ind | false }"# r#"[7 8 9] | enumerate | any {|el| print $el.index | false }"#
)); ));
assert_eq!(actual.out, "012false"); assert_eq!(actual.out, "012false");

View File

@ -73,20 +73,20 @@ fn each_implicit_it_in_block() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn each_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[7 8 9 10] | each {|el ind| $ind } | to nuon"# r#"[7 8 9 10] | enumerate | each {|el| $el.index } | to nuon"#
)); ));
assert_eq!(actual.out, "[0, 1, 2, 3]"); assert_eq!(actual.out, "[0, 1, 2, 3]");
} }
#[test] #[test]
fn each_while_uses_optional_index_argument() { fn each_while_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[7 8 9 10] | each while {|el ind| $ind } | to nuon"# r#"[7 8 9 10] | enumerate | each while {|el| $el.index } | to nuon"#
)); ));
assert_eq!(actual.out, "[0, 1, 2, 3]"); assert_eq!(actual.out, "[0, 1, 2, 3]");

View File

@ -87,11 +87,11 @@ fn insert_past_end_list() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn insert_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[[a]; [7] [6]] | insert b {|el ind| $ind + 1 + $el.a } | to nuon"# r#"[[a]; [7] [6]] | enumerate | insert b {|el| $el.index + 1 + $el.item.a } | flatten | to nuon"#
)); ));
assert_eq!(actual.out, "[[a, b]; [7, 8], [6, 8]]"); assert_eq!(actual.out, "[[index, a, b]; [0, 7, 8], [1, 6, 8]]");
} }

View File

@ -47,12 +47,12 @@ fn reduce_rows_example() {
} }
#[test] #[test]
fn reduce_numbered_example() { fn reduce_enumerate_example() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#" r#"
echo one longest three bar echo one longest three bar | enumerate
| reduce -n { |it, acc| if ($it.item | str length) > ($acc.item | str length) {echo $it} else {echo $acc}} | reduce { |it, acc| if ($it.item | str length) > ($acc.item | str length) {echo $it} else {echo $acc}}
| get index | get index
"# "#
) )
@ -62,12 +62,14 @@ fn reduce_numbered_example() {
} }
#[test] #[test]
fn reduce_numbered_integer_addition_example() { fn reduce_enumerate_integer_addition_example() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#" r#"
echo [1 2 3 4] echo [1 2 3 4]
| reduce -n { |it, acc| $acc.item + $it.item } | enumerate
| reduce { |it, acc| { index: ($it.index) item: ($acc.item + $it.item)} }
| get item
"# "#
) )
); );
@ -121,11 +123,14 @@ fn error_reduce_empty() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn enumerate_reduce_example() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[18 19 20] | reduce -f 0 {|elem accum index| $accum + $index } | to nuon"# r#"
)); [one longest three bar] | enumerate | reduce {|it, acc| if ($it.item | str length) > ($acc.item | str length) { $it } else { $acc }} | get index
"#
)
);
assert_eq!(actual.out, "3"); assert_eq!(actual.out, "1");
} }

View File

@ -135,7 +135,8 @@ mod columns {
transpose bit --ignore-titles transpose bit --ignore-titles
| get bit | get bit
| reverse | reverse
| each --numbered { |it| | enumerate
| each { |it|
$it.item * (2 ** $it.index) $it.item * (2 ** $it.index)
} }
| math sum | math sum

View File

@ -116,11 +116,11 @@ fn update_nonexistent_column() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn update_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[[a]; [7] [6]] | update a {|el ind| $ind + 1 + $el.a } | to nuon"# r#"[[a]; [7] [6]] | enumerate | update item.a {|el| $el.index + 1 + $el.item.a } | flatten | to nuon"#
)); ));
assert_eq!(actual.out, "[[a]; [8], [8]]"); assert_eq!(actual.out, "[[index, a]; [0, 8], [1, 8]]");
} }

View File

@ -69,23 +69,23 @@ fn sets_the_column_from_a_subexpression() {
} }
#[test] #[test]
fn uses_optional_index_argument_inserting() { fn upsert_uses_enumerate_index_inserting() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[[a]; [7] [6]] | upsert b {|el ind| $ind + 1 + $el.a } | to nuon"# r#"[[a]; [7] [6]] | enumerate | upsert b {|el| $el.index + 1 + $el.item.a } | flatten | to nuon"#
)); ));
assert_eq!(actual.out, "[[a, b]; [7, 8], [6, 8]]"); assert_eq!(actual.out, "[[index, a, b]; [0, 7, 8], [1, 6, 8]]");
} }
#[test] #[test]
fn uses_optional_index_argument_updating() { fn upsert_uses_enumerate_index_updating() {
let actual = nu!( let actual = nu!(
cwd: ".", pipeline( cwd: ".", pipeline(
r#"[[a]; [7] [6]] | upsert a {|el ind| $ind + 1 + $el.a } | to nuon"# r#"[[a]; [7] [6]] | enumerate | upsert a {|el| $el.index + 1 + $el.item.a } | flatten | to nuon"#
)); ));
assert_eq!(actual.out, "[[a]; [8], [8]]"); assert_eq!(actual.out, "[[index, a]; [0, 8], [1, 8]]");
} }
#[test] #[test]

View File

@ -82,13 +82,13 @@ fn where_not_in_table() {
} }
#[test] #[test]
fn uses_optional_index_argument() { fn where_uses_enumerate_index() {
let actual = nu!( let actual = nu!(
cwd: ".", cwd: ".",
r#"[7 8 9 10] | where {|el ind| $ind < 2 } | to nuon"# r#"[7 8 9 10] | enumerate | where {|el| $el.index < 2 } | to nuon"#
); );
assert_eq!(actual.out, "[7, 8]"); assert_eq!(actual.out, "[[index, item]; [0, 7], [1, 8]]");
} }
#[cfg(feature = "sqlite")] #[cfg(feature = "sqlite")]

View File

@ -3,7 +3,7 @@ use crate::tests::{run_test, TestResult};
#[test] #[test]
fn better_block_types() -> TestResult { fn better_block_types() -> TestResult {
run_test( run_test(
r#"([1, 2, 3] | each -n { |it| $"($it.index) is ($it.item)" }).1"#, r#"([1, 2, 3] | enumerate | each { |e| $"($e.index) is ($e.item)" }).1"#,
"1 is 2", "1 is 2",
) )
} }
@ -35,7 +35,7 @@ fn row_condition2() -> TestResult {
#[test] #[test]
fn par_each() -> TestResult { fn par_each() -> TestResult {
run_test( run_test(
r#"1..10 | par-each --numbered { |it| ([[index, item]; [$it.index, ($it.item > 5)]]).0 } | where index == 4 | get item.0"#, r#"1..10 | enumerate | par-each { |it| ([[index, item]; [$it.index, ($it.item > 5)]]).0 } | where index == 4 | get item.0"#,
"false", "false",
) )
} }

View File

@ -147,8 +147,8 @@ fn bad_var_name2() -> TestResult {
#[test] #[test]
fn long_flag() -> TestResult { fn long_flag() -> TestResult {
run_test( run_test(
r#"([a, b, c] | each --numbered { |it| if $it.index == 1 { 100 } else { 0 } }).1"#, r#"([a, b, c] | enumerate | each --keep-empty { |e| if $e.index != 1 { 100 }}).1 | to nuon"#,
"100", "null",
) )
} }