Add a couple more tests to for

This commit is contained in:
JT 2021-10-10 05:58:33 +13:00
parent b28f876095
commit 8df9ea6c68
2 changed files with 87 additions and 55 deletions

View file

@ -1,7 +1,7 @@
use nu_engine::{eval_block, eval_expression}; use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, IntoValueStream, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, Signature, Span, SyntaxShape, Value};
pub struct For; pub struct For;
@ -23,10 +23,7 @@ impl Command for For {
) )
.required( .required(
"range", "range",
SyntaxShape::Keyword( SyntaxShape::Keyword(b"in".to_vec(), Box::new(SyntaxShape::Any)),
b"in".to_vec(),
Box::new(SyntaxShape::List(Box::new(SyntaxShape::Int))),
),
"range of the loop", "range of the loop",
) )
.required( .required(
@ -55,42 +52,22 @@ impl Command for For {
let block = call.positional[2] let block = call.positional[2]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
let context = context.clone(); let context = context.clone();
match values { Ok(values.map(call.head, move |x| {
Value::Stream { stream, .. } => Ok(Value::Stream { let engine_state = context.engine_state.borrow();
stream: stream let block = engine_state.get_block(block);
.map(move |x| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block);
let state = context.enter_scope(); let state = context.enter_scope();
state.add_var(var_id, x);
//FIXME: DON'T UNWRAP state.add_var(var_id, x);
eval_block(&state, block, Value::nothing()).unwrap()
})
.into_value_stream(),
span: call.head,
}),
Value::List { vals: val, .. } => Ok(Value::List {
vals: val
.into_iter()
.map(move |x| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block);
let state = context.enter_scope(); match eval_block(&state, block, Value::nothing()) {
state.add_var(var_id, x); Ok(value) => value,
Err(error) => Value::Error { error },
//FIXME: DON'T UNWRAP }
eval_block(&state, block, Value::nothing()).unwrap() }))
})
.collect(),
span: call.head,
}),
_ => Ok(Value::nothing()),
}
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -120,23 +97,36 @@ impl Command for For {
span: Span::unknown(), span: Span::unknown(),
}), }),
}, },
Example { // FIXME? Numbered `for` is kinda strange, but was supported in previous nushell
description: "Number each item and echo a message", // Example {
example: "for $it in ['bob' 'fred'] --numbered { $\"($it.index) is ($it.item)\" }", // description: "Number each item and echo a message",
result: Some(Value::List { // example: "for $it in ['bob' 'fred'] --numbered { $\"($it.index) is ($it.item)\" }",
vals: vec![ // result: Some(Value::List {
Value::String { // vals: vec![
val: "0 is bob".into(), // Value::String {
span, // val: "0 is bob".into(),
}, // span,
Value::String { // },
val: "0 is fred".into(), // Value::String {
span, // val: "0 is fred".into(),
}, // span,
], // },
span: Span::unknown(), // ],
}), // span: Span::unknown(),
}, // }),
// },
] ]
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(For {})
}
}

View file

@ -379,6 +379,10 @@ impl Value {
stream: stream.map(f).into_value_stream(), stream: stream.map(f).into_value_stream(),
span, span,
}, },
Value::Range { val, .. } => Value::Stream {
stream: val.into_iter().map(f).into_value_stream(),
span,
},
v => { v => {
if v.as_string().is_ok() { if v.as_string().is_ok() {
Value::List { Value::List {
@ -413,6 +417,10 @@ impl Value {
stream: stream.map(f).flatten().into_value_stream(), stream: stream.map(f).flatten().into_value_stream(),
span, span,
}, },
Value::Range { val, .. } => Value::Stream {
stream: val.into_iter().map(f).flatten().into_value_stream(),
span,
},
v => { v => {
if v.as_string().is_ok() { if v.as_string().is_ok() {
Value::List { Value::List {
@ -482,8 +490,42 @@ impl PartialEq for Value {
stream: stream_rhs, .. stream: stream_rhs, ..
}, },
) => { ) => {
let vals_lhs = stream_lhs.clone().collect_string(); let vals_lhs: Vec<Value> = stream_lhs.clone().collect();
let vals_rhs = stream_rhs.clone().collect_string(); let vals_rhs: Vec<Value> = stream_rhs.clone().collect();
vals_lhs == vals_rhs
}
// Note: This may look a bit strange, but a Stream is still just a List,
// it just happens to be in an iterator form instead of a concrete form. If the contained
// values are the same then it should be treated as equal
(
Value::Stream {
stream: stream_lhs, ..
},
Value::List {
vals: stream_rhs, ..
},
) => {
let vals_lhs: Vec<Value> = stream_lhs.clone().collect();
let vals_rhs: Vec<Value> =
stream_rhs.clone().into_iter().into_value_stream().collect();
vals_lhs == vals_rhs
}
// Note: This may look a bit strange, but a Stream is still just a List,
// it just happens to be in an iterator form instead of a concrete form. If the contained
// values are the same then it should be treated as equal
(
Value::List {
vals: stream_lhs, ..
},
Value::Stream {
stream: stream_rhs, ..
},
) => {
let vals_lhs: Vec<Value> =
stream_lhs.clone().into_iter().into_value_stream().collect();
let vals_rhs: Vec<Value> = stream_rhs.clone().collect();
vals_lhs == vals_rhs vals_lhs == vals_rhs
} }