From d094f654c34c756e585e482452c0af1a6ddc295e Mon Sep 17 00:00:00 2001 From: onthebridgetonowhere <71919805+onthebridgetonowhere@users.noreply.github.com> Date: Wed, 10 Nov 2021 01:51:55 +0100 Subject: [PATCH] Port str endswith (#321) * Port str endswith command * Fix clippy warnings * Styling Co-authored-by: Stefan Stanciulescu --- crates/nu-command/src/default_context.rs | 1 + .../nu-command/src/strings/str_/ends_with.rs | 123 ++++++++++++++++++ crates/nu-command/src/strings/str_/mod.rs | 2 + 3 files changed, 126 insertions(+) create mode 100644 crates/nu-command/src/strings/str_/ends_with.rs diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index b5291941f..3d42e28bc 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -101,6 +101,7 @@ pub fn create_default_context() -> EngineState { StrCollect, StrContains, StrDowncase, + StrEndswith, StrKebabCase, StrPascalCase, StrScreamingSnakeCase, diff --git a/crates/nu-command/src/strings/str_/ends_with.rs b/crates/nu-command/src/strings/str_/ends_with.rs new file mode 100644 index 000000000..571a4a77b --- /dev/null +++ b/crates/nu-command/src/strings/str_/ends_with.rs @@ -0,0 +1,123 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::ast::CellPath; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::Spanned; +use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "str ends-with" + } + + fn signature(&self) -> Signature { + Signature::build("str ends-with") + .required("pattern", SyntaxShape::String, "the pattern to match") + .rest( + "rest", + SyntaxShape::CellPath, + "optionally matches suffix of text by column paths", + ) + } + + fn usage(&self) -> &str { + "checks if string ends with pattern" + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + operate(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Checks if string ends with '.rb' pattern", + example: "'my_library.rb' | str ends-with '.rb'", + result: Some(Value::Bool { + val: true, + span: Span::unknown(), + }), + }, + Example { + description: "Checks if string ends with '.txt' pattern", + example: "'my_library.rb' | str ends-with '.txt'", + result: Some(Value::Bool { + val: false, + span: Span::unknown(), + }), + }, + ] + } +} + +fn operate( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, +) -> Result { + let head = call.head; + let pattern: Spanned = call.req(engine_state, stack, 0)?; + let column_paths: Vec = call.rest(engine_state, stack, 1)?; + + input.map( + move |v| { + if column_paths.is_empty() { + action(&v, &pattern.item, head) + } else { + let mut ret = v; + for path in &column_paths { + let p = pattern.item.clone(); + let r = ret.update_cell_path( + &path.members, + Box::new(move |old| action(old, &p, head)), + ); + if let Err(error) = r { + return Value::Error { error }; + } + } + ret + } + }, + engine_state.ctrlc.clone(), + ) +} + +fn action(input: &Value, pattern: &str, head: Span) -> Value { + match input { + Value::String { val, .. } => Value::Bool { + val: val.ends_with(pattern), + span: head, + }, + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Input's type is {}. This command only works with strings.", + other.get_type() + ), + Span::unknown(), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/strings/str_/mod.rs b/crates/nu-command/src/strings/str_/mod.rs index 8a85d02ba..71b73d01d 100644 --- a/crates/nu-command/src/strings/str_/mod.rs +++ b/crates/nu-command/src/strings/str_/mod.rs @@ -3,9 +3,11 @@ mod case; mod collect; mod contains; mod downcase; +mod ends_with; pub use capitalize::SubCommand as StrCapitalize; pub use case::*; pub use collect::*; pub use contains::SubCommand as StrContains; pub use downcase::SubCommand as StrDowncase; +pub use ends_with::SubCommand as StrEndswith;