diff --git a/README.adoc b/README.adoc index 3158d49..48234d2 100644 --- a/README.adoc +++ b/README.adoc @@ -854,10 +854,14 @@ The executable is at: /bin/just ==== String Manipulation -- `uppercase(s)` - Convert `s` to uppercase. - `lowercase(s)` - Convert `s` to lowercase. -- `trim(s)` - Remove leading and trailing whitespace from `s`. - `replace(s, from, to)` - Replace all occurrences of `from` in `s` to `to`. +- `trim(s)` - Remove leading and trailing whitespace from `s`. +- `trim_end_match(s, pat)` - Remove suffix of `s` matching `pat`. +- `trim_end_matches(s, pat)` - Repeatedly remove suffixes of `s` matching `pat`. +- `trim_start_match(s, pat)` - Remove prefix of `s` matching `pat`. +- `trim_start_matches(s, pat)` - Repeatedly remove prefixes of `s` matching `pat`. +- `uppercase(s)` - Convert `s` to uppercase. ==== Dotenv Integration diff --git a/src/function.rs b/src/function.rs index 70c619e..178fcc4 100644 --- a/src/function.rs +++ b/src/function.rs @@ -28,6 +28,10 @@ lazy_static! { ("parent_directory", Unary(parent_directory)), ("replace", Ternary(replace)), ("trim", Unary(trim)), + ("trim_end_match", Binary(trim_end_match)), + ("trim_end_matches", Binary(trim_end_matches)), + ("trim_start_match", Binary(trim_start_match)), + ("trim_start_matches", Binary(trim_start_matches)), ("uppercase", Unary(uppercase)), ("without_extension", Unary(without_extension)), ] @@ -197,6 +201,22 @@ fn trim(_context: &FunctionContext, s: &str) -> Result { Ok(s.trim().to_owned()) } +fn trim_end_match(_context: &FunctionContext, s: &str, pat: &str) -> Result { + Ok(s.strip_suffix(pat).unwrap_or(s).to_owned()) +} + +fn trim_end_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result { + Ok(s.trim_end_matches(pat).to_owned()) +} + +fn trim_start_match(_context: &FunctionContext, s: &str, pat: &str) -> Result { + Ok(s.strip_prefix(pat).unwrap_or(s).to_owned()) +} + +fn trim_start_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result { + Ok(s.trim_start_matches(pat).to_owned()) +} + fn uppercase(_context: &FunctionContext, s: &str) -> Result { Ok(s.to_uppercase()) } diff --git a/tests/functions.rs b/tests/functions.rs index 62cf0d0..ee5a77f 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -302,3 +302,37 @@ test! { stdout: "foofoofoo\n", stderr: "echo foofoofoo\n", } + +fn assert_eval_eq(expression: &str, result: &str) { + Test::new() + .justfile(format!("x := {}", expression)) + .args(&["--evaluate", "x"]) + .stdout(result) + .run(); +} + +#[test] +fn trim_end_matches() { + assert_eval_eq("trim_end_matches('foo', 'o')", "f"); + assert_eval_eq("trim_end_matches('fabab', 'ab')", "f"); + assert_eval_eq("trim_end_matches('fbaabab', 'ab')", "fba"); +} + +#[test] +fn trim_end_match() { + assert_eval_eq("trim_end_match('foo', 'o')", "fo"); + assert_eval_eq("trim_end_match('fabab', 'ab')", "fab"); +} + +#[test] +fn trim_start_matches() { + assert_eval_eq("trim_start_matches('oof', 'o')", "f"); + assert_eval_eq("trim_start_matches('ababf', 'ab')", "f"); + assert_eval_eq("trim_start_matches('ababbaf', 'ab')", "baf"); +} + +#[test] +fn trim_start_match() { + assert_eval_eq("trim_start_match('oof', 'o')", "of"); + assert_eval_eq("trim_start_match('ababf', 'ab')", "abf"); +}