mirror of
https://github.com/nushell/nushell
synced 2024-12-28 05:53:09 +00:00
Merge pull request #266 from luccasmmg/engine-q-math-2
Added math and min commands
This commit is contained in:
commit
80a4a5eb28
6 changed files with 181 additions and 6 deletions
|
@ -53,6 +53,8 @@ pub fn create_default_context() -> EngineState {
|
|||
Math,
|
||||
MathAbs,
|
||||
MathAvg,
|
||||
MathMax,
|
||||
MathMin,
|
||||
Mkdir,
|
||||
Module,
|
||||
Mv,
|
||||
|
|
|
@ -50,6 +50,7 @@ pub fn average(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
|||
span: Span::unknown(),
|
||||
},
|
||||
values.to_vec(),
|
||||
*head,
|
||||
)?;
|
||||
match total {
|
||||
Value::Filesize { val, span } => Ok(Value::Filesize {
|
||||
|
|
57
crates/nu-command/src/math/max.rs
Normal file
57
crates/nu-command/src/math/max.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use crate::math::reducers::{reducer_for, Reduce};
|
||||
use crate::math::utils::run_with_function;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"math max"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("math max")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Finds the maximum within a list of numbers or tables"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
run_with_function(call, input, maximum)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Find the maximum of list of numbers",
|
||||
example: "[-50 100 25] | math max",
|
||||
result: Some(Value::test_int(100)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maximum(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
||||
let max_func = reducer_for(Reduce::Maximum);
|
||||
max_func(Value::nothing(), values.to_vec(), *head)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
57
crates/nu-command/src/math/min.rs
Normal file
57
crates/nu-command/src/math/min.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use crate::math::reducers::{reducer_for, Reduce};
|
||||
use crate::math::utils::run_with_function;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"math min"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("math min")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Finds the minimum within a list of numbers or tables"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
run_with_function(call, input, minimum)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Get the minimum of a list of numbers",
|
||||
example: "[-50 100 25] | math min",
|
||||
result: Some(Value::test_int(-50)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minimum(values: &[Value], head: &Span) -> Result<Value, ShellError> {
|
||||
let min_func = reducer_for(Reduce::Minimum);
|
||||
min_func(Value::nothing(), values.to_vec(), *head)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
mod abs;
|
||||
mod avg;
|
||||
pub mod command;
|
||||
mod max;
|
||||
mod min;
|
||||
mod reducers;
|
||||
mod utils;
|
||||
|
||||
pub use abs::SubCommand as MathAbs;
|
||||
pub use avg::SubCommand as MathAvg;
|
||||
pub use command::MathCommand as Math;
|
||||
pub use max::SubCommand as MathMax;
|
||||
pub use min::SubCommand as MathMin;
|
||||
|
|
|
@ -1,19 +1,73 @@
|
|||
use nu_protocol::{ShellError, Span, Value};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum Reduce {
|
||||
Summation,
|
||||
Minimum,
|
||||
Maximum,
|
||||
}
|
||||
|
||||
pub fn reducer_for(
|
||||
command: Reduce,
|
||||
) -> Box<dyn Fn(Value, Vec<Value>) -> Result<Value, ShellError> + Send + Sync + 'static> {
|
||||
pub type ReducerFunction =
|
||||
Box<dyn Fn(Value, Vec<Value>, Span) -> Result<Value, ShellError> + Send + Sync + 'static>;
|
||||
|
||||
pub fn reducer_for(command: Reduce) -> ReducerFunction {
|
||||
match command {
|
||||
Reduce::Summation => Box::new(|_, values| sum(values)),
|
||||
Reduce::Summation => Box::new(|_, values, head| sum(values, head)),
|
||||
Reduce::Minimum => Box::new(|_, values, head| min(values, head)),
|
||||
Reduce::Maximum => Box::new(|_, values, head| max(values, head)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
|
||||
pub fn max(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let mut biggest = data
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))?
|
||||
.clone();
|
||||
|
||||
for value in &data {
|
||||
if let Some(result) = value.partial_cmp(&biggest) {
|
||||
if result == Ordering::Greater {
|
||||
biggest = value.clone();
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
op_span: head,
|
||||
lhs_ty: biggest.get_type(),
|
||||
lhs_span: biggest.span()?,
|
||||
rhs_ty: value.get_type(),
|
||||
rhs_span: value.span()?,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(biggest)
|
||||
}
|
||||
|
||||
pub fn min(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let mut smallest = data
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))?
|
||||
.clone();
|
||||
|
||||
for value in &data {
|
||||
if let Some(result) = value.partial_cmp(&smallest) {
|
||||
if result == Ordering::Less {
|
||||
smallest = value.clone();
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
op_span: head,
|
||||
lhs_ty: smallest.get_type(),
|
||||
lhs_span: smallest.span()?,
|
||||
rhs_ty: value.get_type(),
|
||||
rhs_span: value.span()?,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(smallest)
|
||||
}
|
||||
|
||||
pub fn sum(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
|
||||
let initial_value = data.get(0);
|
||||
|
||||
let mut acc = match initial_value {
|
||||
|
@ -42,7 +96,7 @@ pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
|
|||
| Value::Float { .. }
|
||||
| Value::Filesize { .. }
|
||||
| Value::Duration { .. } => {
|
||||
let new_value = acc.add(acc.span().unwrap_or_else(|_| Span::unknown()), value);
|
||||
let new_value = acc.add(head, value);
|
||||
if new_value.is_err() {
|
||||
return new_value;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue