From 8c0fa0d26e9a703c47e23e7eba6f44a7230573b0 Mon Sep 17 00:00:00 2001 From: Arthur Targaryen Date: Sun, 28 Nov 2021 09:29:35 +0100 Subject: [PATCH] Add `Any` command (#375) --- crates/nu-command/src/default_context.rs | 1 + crates/nu-command/src/filters/any.rs | 98 ++++++++++++++++++++++++ crates/nu-command/src/filters/mod.rs | 2 + 3 files changed, 101 insertions(+) create mode 100644 crates/nu-command/src/filters/any.rs diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index b889eb5dca..6ac977d2aa 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -21,6 +21,7 @@ pub fn create_default_context() -> EngineState { bind_command!( Alias, All, + Any, Append, Benchmark, BuildString, diff --git a/crates/nu-command/src/filters/any.rs b/crates/nu-command/src/filters/any.rs new file mode 100644 index 0000000000..7cb4519560 --- /dev/null +++ b/crates/nu-command/src/filters/any.rs @@ -0,0 +1,98 @@ +use nu_engine::eval_block; +use nu_protocol::{ + ast::{Call, Expr, Expression}, + engine::{Command, EngineState, Stack}, + Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, +}; + +#[derive(Clone)] +pub struct Any; + +impl Command for Any { + fn name(&self) -> &str { + "any?" + } + + fn signature(&self) -> Signature { + Signature::build(self.name()) + .required( + "predicate", + SyntaxShape::RowCondition, + "the predicate that must match", + ) + .category(Category::Filters) + } + + fn usage(&self) -> &str { + "Tests if any element of the input matches a predicate." + } + + fn examples(&self) -> Vec { + use nu_protocol::Value; + + vec![ + Example { + description: "Find if a service is not running", + example: "echo [[status]; [UP] [DOWN] [UP]] | any? status == DOWN", + result: Some(Value::from(true)), + }, + Example { + description: "Check if any of the values is odd", + example: "echo [2 4 1 6 8] | any? ($it mod 2) == 1", + result: Some(Value::from(true)), + }, + ] + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let predicate = &call.positional[0]; + let block_id = match predicate { + Expression { + expr: Expr::RowCondition(block_id), + .. + } => *block_id, + _ => return Err(ShellError::InternalError("Expected row condition".into())), + }; + + let span = call.head; + + let block = engine_state.get_block(block_id); + let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id); + let mut stack = stack.collect_captures(&block.captures); + + let ctrlc = engine_state.ctrlc.clone(); + let engine_state = engine_state.clone(); + + Ok(input + .into_interruptible_iter(ctrlc) + .any(move |value| { + if let Some(var_id) = var_id { + stack.add_var(var_id, value); + } + + eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) + }) + .into_pipeline_data()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(Any) + } +} diff --git a/crates/nu-command/src/filters/mod.rs b/crates/nu-command/src/filters/mod.rs index 8cd39f229a..98e1f8c404 100644 --- a/crates/nu-command/src/filters/mod.rs +++ b/crates/nu-command/src/filters/mod.rs @@ -1,4 +1,5 @@ mod all; +mod any; mod append; mod collect; mod drop; @@ -19,6 +20,7 @@ mod wrap; mod zip; pub use all::All; +pub use any::Any; pub use append::Append; pub use collect::Collect; pub use drop::*;