use liquid_core::Expression;
use liquid_core::Result;
use liquid_core::Runtime;
use liquid_core::{
Display_filter, Filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
};
use liquid_core::{Value, ValueView};
#[derive(Debug, FilterParameters)]
struct ReplaceArgs {
#[parameter(description = "The text to search.", arg_type = "str")]
search: Expression,
#[parameter(
description = "The text to replace search results with. If not given, the filter will just delete search results.",
arg_type = "str"
)]
replace: Option<Expression>,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "replace",
description = "Replaces the occurrences of the `search` with `replace`. If `replace` is not given, just deletes occurrences of `search`.",
parameters(ReplaceArgs),
parsed(ReplaceFilter)
)]
pub struct Replace;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "replace"]
struct ReplaceFilter {
#[parameters]
args: ReplaceArgs,
}
impl Filter for ReplaceFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let input = input.to_kstr();
let replace = args.replace.unwrap_or_else(|| "".into());
Ok(Value::scalar(
input.replace(args.search.as_str(), replace.as_str()),
))
}
}
#[derive(Debug, FilterParameters)]
struct ReplaceFirstArgs {
#[parameter(description = "The text to search.", arg_type = "str")]
search: Expression,
#[parameter(
description = "The text to replace search result with. If not given, the filter will just delete search results«.",
arg_type = "str"
)]
replace: Option<Expression>,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "replace_first",
description = "Replaces the first occurrence of the `search` with `replace`. If `replace` is not given, just deletes the occurrence.",
parameters(ReplaceFirstArgs),
parsed(ReplaceFirstFilter)
)]
pub struct ReplaceFirst;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "replace_first"]
struct ReplaceFirstFilter {
#[parameters]
args: ReplaceFirstArgs,
}
impl Filter for ReplaceFirstFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let input = input.to_kstr();
let search = args.search;
let replace = args.replace.unwrap_or_else(|| "".into());
{
let tokens: Vec<&str> = input.splitn(2, search.as_str()).collect();
if tokens.len() == 2 {
let result = [tokens[0], replace.as_str(), tokens[1]].join("");
return Ok(Value::scalar(result));
}
}
Ok(Value::scalar(input.into_owned()))
}
}
#[derive(Debug, FilterParameters)]
struct RemoveArgs {
#[parameter(description = "The text to remove.", arg_type = "str")]
search: Expression,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "remove",
description = "Removes all occurrences of the given string.",
parameters(RemoveArgs),
parsed(RemoveFilter)
)]
pub struct Remove;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "remove"]
struct RemoveFilter {
#[parameters]
args: RemoveArgs,
}
impl Filter for RemoveFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let input = input.to_kstr();
Ok(Value::scalar(input.replace(args.search.as_str(), "")))
}
}
#[derive(Debug, FilterParameters)]
struct RemoveFirstArgs {
#[parameter(description = "The text to remove.", arg_type = "str")]
search: Expression,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "remove_first",
description = "Removes the first occurrence of the given string.",
parameters(RemoveFirstArgs),
parsed(RemoveFirstFilter)
)]
pub struct RemoveFirst;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "remove_first"]
struct RemoveFirstFilter {
#[parameters]
args: RemoveFirstArgs,
}
impl Filter for RemoveFirstFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let input = input.to_kstr();
Ok(Value::scalar(
input.splitn(2, args.search.as_str()).collect::<String>(),
))
}
}
#[derive(Debug, FilterParameters)]
struct AppendArgs {
#[parameter(description = "The string to append to the input.", arg_type = "str")]
string: Expression,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "append",
description = "Appends the given text to a string.",
parameters(AppendArgs),
parsed(AppendFilter)
)]
pub struct Append;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "append"]
struct AppendFilter {
#[parameters]
args: AppendArgs,
}
impl Filter for AppendFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let mut input = input.to_kstr().into_string();
input.push_str(args.string.as_str());
Ok(Value::scalar(input))
}
}
#[derive(Debug, FilterParameters)]
struct PrependArgs {
#[parameter(description = "The string to prepend to the input.", arg_type = "str")]
string: Expression,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "prepend",
description = "Prepends the given text to a string.",
parameters(PrependArgs),
parsed(PrependFilter)
)]
pub struct Prepend;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "prepend"]
struct PrependFilter {
#[parameters]
args: PrependArgs,
}
impl Filter for PrependFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &Runtime<'_>) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let input = input.to_kstr();
let mut string = args.string.into_string();
string.push_str(input.as_str());
Ok(Value::scalar(string))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_append() {
assert_eq!(
liquid_core::call_filter!(Append, "sam", "son").unwrap(),
liquid_core::value!("samson")
);
}
#[test]
fn unit_prepend() {
assert_eq!(
liquid_core::call_filter!(Prepend, "barbar", "foo").unwrap(),
liquid_core::value!("foobarbar")
);
}
#[test]
fn unit_remove() {
assert_eq!(
liquid_core::call_filter!(Remove, "barbar", "bar").unwrap(),
liquid_core::value!("")
);
assert_eq!(
liquid_core::call_filter!(Remove, "barbar", "").unwrap(),
liquid_core::value!("barbar")
);
assert_eq!(
liquid_core::call_filter!(Remove, "barbar", "barbar").unwrap(),
liquid_core::value!("")
);
assert_eq!(
liquid_core::call_filter!(Remove, "barbar", "a").unwrap(),
liquid_core::value!("brbr")
);
}
#[test]
fn unit_remove_first() {
assert_eq!(
liquid_core::call_filter!(RemoveFirst, "barbar", "bar").unwrap(),
liquid_core::value!("bar")
);
assert_eq!(
liquid_core::call_filter!(RemoveFirst, "barbar", "").unwrap(),
liquid_core::value!("barbar")
);
assert_eq!(
liquid_core::call_filter!(RemoveFirst, "barbar", "barbar").unwrap(),
liquid_core::value!("")
);
assert_eq!(
liquid_core::call_filter!(RemoveFirst, "barbar", "a").unwrap(),
liquid_core::value!("brbar")
);
}
#[test]
fn unit_replace() {
assert_eq!(
liquid_core::call_filter!(Replace, "barbar", "bar", "foo").unwrap(),
liquid_core::value!("foofoo")
);
}
#[test]
fn unit_replace_first() {
assert_eq!(
liquid_core::call_filter!(ReplaceFirst, "barbar", "bar", "foo").unwrap(),
liquid_core::value!("foobar")
);
assert_eq!(
liquid_core::call_filter!(ReplaceFirst, "barxoxo", "xo", "foo").unwrap(),
liquid_core::value!("barfooxo")
);
assert_eq!(
liquid_core::call_filter!(ReplaceFirst, "", "bar", "foo").unwrap(),
liquid_core::value!("")
);
}
}