diff --git a/src/stdlib/helpers.rs b/src/stdlib/helpers.rs index 5dd68395..adf0384f 100644 --- a/src/stdlib/helpers.rs +++ b/src/stdlib/helpers.rs @@ -473,3 +473,46 @@ pub fn expect_datetime(value: &Value) -> Result, Runti )), } } + +/// Helper for unary text operations (Text -> Text) +/// +/// Handles argument count checking, type extraction, operation execution, +/// and result wrapping. +/// +/// # Arguments +/// +/// * `func_name` - Name of the function for error messages +/// * `args` - Arguments passed to the function +/// * `op` - The text operation to perform +pub fn unary_text_op(func_name: &str, args: Vec, op: F) -> Result +where + F: Fn(&str) -> String, +{ + check_arg_count(func_name, &args, 1)?; + let text = expect_text(&args[0])?; + Ok(Value::Text(Arc::from(op(&text)))) +} + +/// Helper for binary text predicates ((Text, Text) -> Bool) +/// +/// Handles argument count checking, type extraction, operation execution, +/// and result wrapping. +/// +/// # Arguments +/// +/// * `func_name` - Name of the function for error messages +/// * `args` - Arguments passed to the function +/// * `op` - The predicate to perform +pub fn binary_text_predicate( + func_name: &str, + args: Vec, + op: F, +) -> Result +where + F: Fn(&str, &str) -> bool, +{ + check_arg_count(func_name, &args, 2)?; + let a = expect_text(&args[0])?; + let b = expect_text(&args[1])?; + Ok(Value::Bool(op(&a, &b))) +} diff --git a/src/stdlib/text.rs b/src/stdlib/text.rs index b91c428b..9ee46bda 100644 --- a/src/stdlib/text.rs +++ b/src/stdlib/text.rs @@ -1,4 +1,6 @@ -use super::helpers::{check_arg_count, expect_number, expect_text}; +use super::helpers::{ + binary_text_predicate, check_arg_count, expect_number, expect_text, unary_text_op, +}; use crate::interpreter::environment::Environment; use crate::interpreter::error::RuntimeError; use crate::interpreter::value::Value; @@ -74,19 +76,11 @@ fn parse_key_value_pairs(input: &str, delimiter: char) -> std::collections::Hash // which handles both text and lists pub fn native_touppercase(args: Vec) -> Result { - check_arg_count("touppercase", &args, 1)?; - - let text = expect_text(&args[0])?; - let uppercase = text.to_uppercase(); - Ok(Value::Text(Arc::from(uppercase))) + unary_text_op("touppercase", args, |s| s.to_uppercase()) } pub fn native_tolowercase(args: Vec) -> Result { - check_arg_count("tolowercase", &args, 1)?; - - let text = expect_text(&args[0])?; - let lowercase = text.to_lowercase(); - Ok(Value::Text(Arc::from(lowercase))) + unary_text_op("tolowercase", args, |s| s.to_lowercase()) } pub fn native_substring(args: Vec) -> Result { @@ -135,29 +129,15 @@ pub fn native_string_split(args: Vec) -> Result { } pub fn native_trim(args: Vec) -> Result { - check_arg_count("trim", &args, 1)?; - - let text = expect_text(&args[0])?; - let trimmed = text.trim(); - Ok(Value::Text(Arc::from(trimmed))) + unary_text_op("trim", args, |s| s.trim().to_string()) } pub fn native_starts_with(args: Vec) -> Result { - check_arg_count("starts_with", &args, 2)?; - - let text = expect_text(&args[0])?; - let prefix = expect_text(&args[1])?; - let result = text.starts_with(prefix.as_ref()); - Ok(Value::Bool(result)) + binary_text_predicate("starts_with", args, |s, p| s.starts_with(p)) } pub fn native_ends_with(args: Vec) -> Result { - check_arg_count("ends_with", &args, 2)?; - - let text = expect_text(&args[0])?; - let suffix = expect_text(&args[1])?; - let result = text.ends_with(suffix.as_ref()); - Ok(Value::Bool(result)) + binary_text_predicate("ends_with", args, |s, p| s.ends_with(p)) } /// Parse query string into WFL object @@ -278,26 +258,20 @@ pub fn native_padright(args: Vec) -> Result { } pub fn native_capitalize(args: Vec) -> Result { - check_arg_count("capitalize", &args, 1)?; - - let text = expect_text(&args[0])?; - let mut chars = text.chars(); - let result = match chars.next() { - Some(c) => { - let upper: String = c.to_uppercase().collect(); - format!("{}{}", upper, chars.as_str()) + unary_text_op("capitalize", args, |text| { + let mut chars = text.chars(); + match chars.next() { + Some(c) => { + let upper: String = c.to_uppercase().collect(); + format!("{}{}", upper, chars.as_str()) + } + None => String::new(), } - None => String::new(), - }; - Ok(Value::Text(Arc::from(result))) + }) } pub fn native_reverse_text(args: Vec) -> Result { - check_arg_count("reverse", &args, 1)?; - - let text = expect_text(&args[0])?; - let reversed: String = text.chars().rev().collect(); - Ok(Value::Text(Arc::from(reversed))) + unary_text_op("reverse", args, |text| text.chars().rev().collect()) } pub fn register_text(env: &mut Environment) {