Skip to content

Commit

Permalink
make "and" and "or" accept any number of parameters
Browse files Browse the repository at this point in the history
Writing ifs with multiple conditions used to be very painful, and not very performant

One had to write {{#if (and (cond1 (and cond2 cond3)))}}

One can now write {{#if (and cond1 cond2 cond3)}}
  • Loading branch information
lovasoa committed Dec 20, 2024
1 parent 190bc3b commit caf7fd6
Showing 1 changed file with 53 additions and 5 deletions.
58 changes: 53 additions & 5 deletions src/helpers/helper_extras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ handlebars_helper!(gt: |x: Json, y: Json| compare_json(x, y) == Some(Ordering::G
handlebars_helper!(gte: |x: Json, y: Json| compare_json(x, y).is_some_and(|ord| ord != Ordering::Less));
handlebars_helper!(lt: |x: Json, y: Json| compare_json(x, y) == Some(Ordering::Less));
handlebars_helper!(lte: |x: Json, y: Json| compare_json(x, y).is_some_and(|ord| ord != Ordering::Greater));
handlebars_helper!(and: |x: Json, y: Json| x.is_truthy(false) && y.is_truthy(false));
handlebars_helper!(or: |x: Json, y: Json| x.is_truthy(false) || y.is_truthy(false));
handlebars_helper!(not: |x: Json| !x.is_truthy(false));
handlebars_helper!(len: |x: Json| {
match x {
Expand Down Expand Up @@ -78,6 +76,38 @@ fn compare_json(x: &Json, y: &Json) -> Option<Ordering> {
}
}

#[allow(non_camel_case_types)]
pub struct and;

impl crate::HelperDef for and {
fn call_inner<'reg: 'rc, 'rc>(
&self,
h: &crate::Helper<'rc>,
_r: &'reg crate::Handlebars<'reg>,
_: &'rc crate::Context,
_: &mut crate::RenderContext<'reg, 'rc>,
) -> std::result::Result<crate::ScopedJson<'rc>, crate::RenderError> {
let all_true = h.params().iter().all(|p| p.value().is_truthy(false));
Ok(crate::ScopedJson::Derived(crate::JsonValue::from(all_true)))
}
}

#[allow(non_camel_case_types)]
pub struct or;

impl crate::HelperDef for or {
fn call_inner<'reg: 'rc, 'rc>(
&self,
h: &crate::Helper<'rc>,
_r: &'reg crate::Handlebars<'reg>,
_: &'rc crate::Context,
_: &mut crate::RenderContext<'reg, 'rc>,
) -> std::result::Result<crate::ScopedJson<'rc>, crate::RenderError> {
let any_true = h.params().iter().any(|p| p.value().is_truthy(false));
Ok(crate::ScopedJson::Derived(crate::JsonValue::from(any_true)))
}
}

#[cfg(test)]
mod test_conditions {
fn test_condition(condition: &str, expected: bool) {
Expand All @@ -93,12 +123,30 @@ mod test_conditions {
}

#[test]
fn foo() {
fn test_and_or() {
test_condition("(or (gt 3 5) (gt 5 3))", true);
test_condition("(and null 4)", false);
test_condition("(or null 4)", true);
test_condition("(and null 4 5 6)", false);
test_condition("(or null 4 5 6)", true);
test_condition("(and 1 2 3 4)", true);
test_condition("(or 1 2 3 4)", true);
test_condition("(and 1 2 3 4 0)", false);
test_condition("(or 1 2 3 4 0)", true);
test_condition("(or null 2 3 4 0)", true);
test_condition("(or [] [])", false);
test_condition("(or [1] [])", true);
test_condition("(or [1] [2])", true);
test_condition("(or [1] [2] [3])", true);
test_condition("(or [1] [2] [3] [4])", true);
test_condition("(or [1] [2] [3] [4] [])", true);
}

#[test]
fn test_cmp() {
test_condition("(gt 5 3)", true);
test_condition("(gt 3 5)", false);
test_condition("(or (gt 3 5) (gt 5 3))", true);
test_condition("(not [])", true);
test_condition("(and null 4)", false);
}

#[test]
Expand Down

0 comments on commit caf7fd6

Please sign in to comment.