mirror of
https://github.com/nushell/nushell.git
synced 2025-03-27 08:07:25 +01:00
Math commands can work with bounded ranges and produce list of numbers (#15319)
No associated issue, but follows up #15135. See also discussion on [discord](https://discord.com/channels/601130461678272522/1349139634281513093/1349139639356624966) with @sholderbach # Description ### Math commands `range -> list<number>` This enables the following math commands: - abs - ceil - floor - log - round to work with ranges. When a range is given, the command will apply the command on each item of the range, thus producing a list of number as output. Example  The commands still do not work work with unbounded ranges:  And I left out the "mode" command because I think it does not make sense to use it on ranges... ### Math commands `range -> number` This was the topic of my previous PR, but for whatever reason I didn't do `math variance` and `math stddev`. I had to use `input.try_expand_range` to convert the range into a list before computing the variance/stddev.  And same, does not work in infinite ranges:  ### Also done: - find link in documentation # User-Facing Changes - Command signatures changes - ability to use some commands with unbounded ranges - ability to use variance and stddev with bounded ranges # Tests + Formatting Cargo fmt and clippy OK Tests OK # After Submitting I guess nothing, or maybe release notes?
This commit is contained in:
parent
dfba62da00
commit
2ea2a904e8
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MathAbs;
|
||||
@ -21,6 +23,7 @@ impl Command for MathAbs {
|
||||
Type::List(Box::new(Type::Duration)),
|
||||
Type::List(Box::new(Type::Duration)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Math)
|
||||
@ -46,6 +49,19 @@ impl Command for MathAbs {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(move |value| abs_helper(value, head), engine_state.signals())
|
||||
}
|
||||
|
||||
@ -56,6 +72,19 @@ impl Command for MathAbs {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| abs_helper(value, head),
|
||||
working_set.permanent().signals(),
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MathCeil;
|
||||
@ -16,6 +18,7 @@ impl Command for MathCeil {
|
||||
Type::List(Box::new(Type::Number)),
|
||||
Type::List(Box::new(Type::Int)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Math)
|
||||
@ -45,6 +48,19 @@ impl Command for MathCeil {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(move |value| operate(value, head), engine_state.signals())
|
||||
}
|
||||
|
||||
@ -59,6 +75,19 @@ impl Command for MathCeil {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| operate(value, head),
|
||||
working_set.permanent().signals(),
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MathFloor;
|
||||
@ -16,6 +18,7 @@ impl Command for MathFloor {
|
||||
Type::List(Box::new(Type::Number)),
|
||||
Type::List(Box::new(Type::Int)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Math)
|
||||
@ -45,6 +48,19 @@ impl Command for MathFloor {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(move |value| operate(value, head), engine_state.signals())
|
||||
}
|
||||
|
||||
@ -59,6 +75,19 @@ impl Command for MathFloor {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| operate(value, head),
|
||||
working_set.permanent().signals(),
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
use nu_protocol::Signals;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -22,6 +24,7 @@ impl Command for MathLog {
|
||||
Type::List(Box::new(Type::Number)),
|
||||
Type::List(Box::new(Type::Float)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Math)
|
||||
@ -46,7 +49,21 @@ impl Command for MathLog {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let base: Spanned<f64> = call.req(engine_state, stack, 0)?;
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
log(base, call.head, input, engine_state.signals())
|
||||
}
|
||||
|
||||
@ -56,7 +73,21 @@ impl Command for MathLog {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let base: Spanned<f64> = call.req_const(working_set, 0)?;
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
log(base, call.head, input, working_set.permanent().signals())
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ impl Command for MathMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode(values: &[Value], _span: Span, head: Span) -> Result<Value, ShellError> {
|
||||
pub fn mode(values: &[Value], span: Span, head: Span) -> Result<Value, ShellError> {
|
||||
//In e-q, Value doesn't implement Hash or Eq, so we have to get the values inside
|
||||
// But f64 doesn't implement Hash, so we get the binary representation to use as
|
||||
// key in the HashMap
|
||||
@ -130,11 +130,11 @@ pub fn mode(values: &[Value], _span: Span, head: Span) -> Result<Value, ShellErr
|
||||
NumberTypes::Filesize,
|
||||
)),
|
||||
Value::Error { error, .. } => Err(*error.clone()),
|
||||
other => Err(ShellError::UnsupportedInput {
|
||||
_ => Err(ShellError::UnsupportedInput {
|
||||
msg: "Unable to give a result with this input".to_string(),
|
||||
input: "value originates from here".into(),
|
||||
msg_span: head,
|
||||
input_span: other.span(),
|
||||
input_span: span,
|
||||
}),
|
||||
})
|
||||
.collect::<Result<Vec<HashableType>, ShellError>>()?;
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MathRound;
|
||||
@ -16,6 +18,7 @@ impl Command for MathRound {
|
||||
Type::List(Box::new(Type::Number)),
|
||||
Type::List(Box::new(Type::Number)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.named(
|
||||
@ -52,6 +55,19 @@ impl Command for MathRound {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| operate(value, head, precision_param),
|
||||
engine_state.signals(),
|
||||
@ -70,6 +86,19 @@ impl Command for MathRound {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| operate(value, head, precision_param),
|
||||
working_set.permanent().signals(),
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::math::utils::ensure_bounded;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MathSqrt;
|
||||
@ -16,6 +18,7 @@ impl Command for MathSqrt {
|
||||
Type::List(Box::new(Type::Number)),
|
||||
Type::List(Box::new(Type::Float)),
|
||||
),
|
||||
(Type::Range, Type::List(Box::new(Type::Number))),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Math)
|
||||
@ -45,6 +48,19 @@ impl Command for MathSqrt {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(move |value| operate(value, head), engine_state.signals())
|
||||
}
|
||||
|
||||
@ -59,6 +75,19 @@ impl Command for MathSqrt {
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
if let PipelineData::Value(
|
||||
Value::Range {
|
||||
ref val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) = input
|
||||
{
|
||||
match &**val {
|
||||
Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?,
|
||||
}
|
||||
}
|
||||
input.map(
|
||||
move |value| operate(value, head),
|
||||
working_set.permanent().signals(),
|
||||
|
@ -14,6 +14,7 @@ impl Command for MathStddev {
|
||||
Signature::build("math stddev")
|
||||
.input_output_types(vec![
|
||||
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||
(Type::Range, Type::Number),
|
||||
(Type::table(), Type::record()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
@ -53,6 +54,18 @@ impl Command for MathStddev {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let sample = call.has_flag(engine_state, stack, "sample")?;
|
||||
let name = call.head;
|
||||
let span = input.span().unwrap_or(name);
|
||||
let input: PipelineData = match input.try_expand_range() {
|
||||
Err(_) => {
|
||||
return Err(ShellError::IncorrectValue {
|
||||
msg: "Range must be bounded".to_string(),
|
||||
val_span: span,
|
||||
call_span: name,
|
||||
});
|
||||
}
|
||||
Ok(val) => val,
|
||||
};
|
||||
run_with_function(call, input, compute_stddev(sample))
|
||||
}
|
||||
|
||||
@ -63,6 +76,18 @@ impl Command for MathStddev {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let sample = call.has_flag_const(working_set, "sample")?;
|
||||
let name = call.head;
|
||||
let span = input.span().unwrap_or(name);
|
||||
let input: PipelineData = match input.try_expand_range() {
|
||||
Err(_) => {
|
||||
return Err(ShellError::IncorrectValue {
|
||||
msg: "Range must be bounded".to_string(),
|
||||
val_span: span,
|
||||
call_span: name,
|
||||
});
|
||||
}
|
||||
Ok(val) => val,
|
||||
};
|
||||
run_with_function(call, input, compute_stddev(sample))
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ impl Command for MathVariance {
|
||||
Signature::build("math variance")
|
||||
.input_output_types(vec![
|
||||
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||
(Type::Range, Type::Number),
|
||||
(Type::table(), Type::record()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
@ -45,6 +46,18 @@ impl Command for MathVariance {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let sample = call.has_flag(engine_state, stack, "sample")?;
|
||||
let name = call.head;
|
||||
let span = input.span().unwrap_or(name);
|
||||
let input: PipelineData = match input.try_expand_range() {
|
||||
Err(_) => {
|
||||
return Err(ShellError::IncorrectValue {
|
||||
msg: "Range must be bounded".to_string(),
|
||||
val_span: span,
|
||||
call_span: name,
|
||||
});
|
||||
}
|
||||
Ok(val) => val,
|
||||
};
|
||||
run_with_function(call, input, compute_variance(sample))
|
||||
}
|
||||
|
||||
@ -55,6 +68,18 @@ impl Command for MathVariance {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let sample = call.has_flag_const(working_set, "sample")?;
|
||||
let name = call.head;
|
||||
let span = input.span().unwrap_or(name);
|
||||
let input: PipelineData = match input.try_expand_range() {
|
||||
Err(_) => {
|
||||
return Err(ShellError::IncorrectValue {
|
||||
msg: "Range must be bounded".to_string(),
|
||||
val_span: span,
|
||||
call_span: name,
|
||||
});
|
||||
}
|
||||
Ok(val) => val,
|
||||
};
|
||||
run_with_function(call, input, compute_variance(sample))
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,16 @@ fn const_abs() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_abs_range() {
|
||||
let actual = nu!("0..5 | math abs");
|
||||
fn can_abs_range_into_list() {
|
||||
let actual = nu!("-1.5..-10.5 | math abs");
|
||||
let expected = nu!("1.5..10.5");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_abs_infinite_range() {
|
||||
let actual = nu!("0.. | math abs");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -7,8 +7,16 @@ fn const_ceil() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_ceil_range() {
|
||||
let actual = nu!("0..5 | math ceil");
|
||||
fn can_ceil_range_into_list() {
|
||||
let actual = nu!("(1.8)..(3.8) | math ceil");
|
||||
let expected = nu!("[2 3 4]");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_ceil_infinite_range() {
|
||||
let actual = nu!("0.. | math ceil");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -7,8 +7,16 @@ fn const_floor() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_floor_range() {
|
||||
fn can_floor_range_into_list() {
|
||||
let actual = nu!("(1.8)..(3.8) | math floor");
|
||||
let expected = nu!("[1 2 3]");
|
||||
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_floor_infinite_range() {
|
||||
let actual = nu!("0.. | math floor");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -7,8 +7,16 @@ fn const_log() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_log_range() {
|
||||
let actual = nu!("0.. | math log 2");
|
||||
fn can_log_range_into_list() {
|
||||
let actual = nu!("1..5 | math log 2");
|
||||
let expected = nu!("[1 2 3 4 5] | math log 2");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_log_infinite_range() {
|
||||
let actual = nu!("1.. | math log 2");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -42,8 +42,16 @@ fn const_round() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_round_infinite_range() {
|
||||
let actual = nu!("0..5 | math round");
|
||||
fn can_round_range_into_list() {
|
||||
let actual = nu!("(1.0)..(1.2)..(2.0) | math round");
|
||||
let expected = nu!("[1 1 1 2 2 2]");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_round_infinite_range() {
|
||||
let actual = nu!("0.. | math round");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -28,8 +28,16 @@ fn const_sqrt() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_sqrt_range() {
|
||||
fn can_sqrt_range() {
|
||||
let actual = nu!("0..5 | math sqrt");
|
||||
let expected = nu!("[0 1 2 3 4 5] | math sqrt");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_sqrt_infinite_range() {
|
||||
let actual = nu!("0.. | math sqrt");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -7,8 +7,16 @@ fn const_avg() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_stddev_range() {
|
||||
fn can_stddev_range() {
|
||||
let actual = nu!("0..5 | math stddev");
|
||||
let expected = nu!("[0 1 2 3 4 5] | math stddev");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_stddev_infinite_range() {
|
||||
let actual = nu!("0.. | math stddev");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -7,8 +7,16 @@ fn const_variance() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_variance_range() {
|
||||
fn can_variance_range() {
|
||||
let actual = nu!("0..5 | math variance");
|
||||
let expected = nu!("[0 1 2 3 4 5] | math variance");
|
||||
|
||||
assert!(actual.err.contains("nu::parser::input_type_mismatch"));
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_variance_infinite_range() {
|
||||
let actual = nu!("0.. | math variance");
|
||||
|
||||
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||
}
|
||||
|
@ -9,4 +9,4 @@ A complementary (currently stale) resource has been the [Nushell contributor boo
|
||||
- [Developer FAQ](FAQ.md)
|
||||
- [How to/SOPs](HOWTOS.md)
|
||||
- [Platform support policy](PLATFORM_SUPPORT.md)
|
||||
- [Our Rust style](devdocs/rust_style.md)
|
||||
- [Our Rust style](rust_style.md)
|
||||
|
Loading…
Reference in New Issue
Block a user