diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index 438d830092..62a68fbfe1 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -217,6 +217,7 @@ pub fn create_default_context(interactive: bool) -> Result &str { + "math abs" + } + + fn signature(&self) -> Signature { + Signature::build("math abs") + } + + fn usage(&self) -> &str { + "Returns absolute values of a list of numbers" + } + + async fn run( + &self, + args: CommandArgs, + _: &CommandRegistry, + ) -> Result { + let mapped = args.input.map(move |val| match val.value { + UntaggedValue::Primitive(Primitive::Int(val)) => { + UntaggedValue::int(val.magnitude().clone()).into() + } + UntaggedValue::Primitive(Primitive::Decimal(val)) => { + UntaggedValue::decimal(val.abs()).into() + } + UntaggedValue::Primitive(Primitive::Duration(val)) => { + UntaggedValue::duration(val.magnitude().clone()).into() + } + other => abs_default(other), + }); + Ok(OutputStream::from_input(mapped)) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Get absolute of each value in a list of numbers", + example: "echo [-50 -100.0 25] | math abs", + result: Some(vec![ + UntaggedValue::int(50).into(), + UntaggedValue::decimal_from_float(100.0, Span::default()).into(), + UntaggedValue::int(25).into(), + ]), + }] + } +} + +fn abs_default(_: UntaggedValue) -> Value { + UntaggedValue::Error(ShellError::unexpected( + "Only numerical values are supported", + )) + .into() +} + +#[cfg(test)] +mod tests { + use super::ShellError; + use super::SubCommand; + + #[test] + fn examples_work_as_expected() -> Result<(), ShellError> { + use crate::examples::test as test_examples; + + Ok(test_examples(SubCommand {})?) + } +} diff --git a/crates/nu-cli/src/commands/math/mod.rs b/crates/nu-cli/src/commands/math/mod.rs index eca8ac55ce..b3ed5e96a2 100644 --- a/crates/nu-cli/src/commands/math/mod.rs +++ b/crates/nu-cli/src/commands/math/mod.rs @@ -1,3 +1,4 @@ +pub mod abs; pub mod avg; pub mod ceil; pub mod command; @@ -16,6 +17,7 @@ pub mod variance; mod reducers; mod utils; +pub use abs::SubCommand as MathAbs; pub use avg::SubCommand as MathAverage; pub use ceil::SubCommand as MathCeil; pub use command::Command as Math; diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 85102151e6..f5dc2568c4 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -242,8 +242,8 @@ impl UntaggedValue { } /// Helper for creating date duration values - pub fn duration(nanos: BigInt) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Duration(nanos)) + pub fn duration(nanos: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Duration(nanos.into())) } /// Helper for creating datatime values diff --git a/docs/commands/math.md b/docs/commands/math.md index 7f25cf1b3d..078a7fadbb 100644 --- a/docs/commands/math.md +++ b/docs/commands/math.md @@ -3,6 +3,7 @@ Mathematical functions that generally only operate on a list of numbers (integers, decimals, bytes) and tables. Currently the following functions are implemented: +* `math abs`: Returns absolute values of a list of numbers * `math avg`: Finds the average of a list of numbers or tables * `math ceil`: Applies the ceil function to a list of numbers * [`math eval`](math-eval.md): Evaluates a list of math expressions into numbers @@ -147,6 +148,15 @@ To get the average of the file sizes in a directory, simply pipe the size column ───┴──── ``` +```shell +> echo [1 -2 -3.0] | math abs +───┬──────── + 0 │ 1 + 1 │ 2 + 2 │ 3.0000 +───┴──────── +``` + ### Dates ```shell