handlebars/helpers/
helper_if.rs

1use crate::context::Context;
2use crate::helpers::{HelperDef, HelperResult};
3use crate::json::value::JsonTruthy;
4use crate::output::Output;
5use crate::registry::Registry;
6use crate::render::{Helper, RenderContext, Renderable};
7use crate::RenderErrorReason;
8
9#[derive(Clone, Copy)]
10pub struct IfHelper {
11    positive: bool,
12}
13
14impl HelperDef for IfHelper {
15    fn call<'reg: 'rc, 'rc>(
16        &self,
17        h: &Helper<'rc>,
18        r: &'reg Registry<'reg>,
19        ctx: &'rc Context,
20        rc: &mut RenderContext<'reg, 'rc>,
21        out: &mut dyn Output,
22    ) -> HelperResult {
23        let param = h
24            .param(0)
25            .ok_or(RenderErrorReason::ParamNotFoundForIndex("if", 0))?;
26        let include_zero = h
27            .hash_get("includeZero")
28            .and_then(|v| v.value().as_bool())
29            .unwrap_or(false);
30
31        let mut value = param.value().is_truthy(include_zero);
32
33        if !self.positive {
34            value = !value;
35        }
36
37        let tmpl = if value { h.template() } else { h.inverse() };
38        match tmpl {
39            Some(t) => t.render(r, ctx, rc, out),
40            None => Ok(()),
41        }
42    }
43}
44
45pub static IF_HELPER: IfHelper = IfHelper { positive: true };
46pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };
47
48#[cfg(test)]
49mod test {
50    use crate::helpers::WITH_HELPER;
51    use crate::registry::Registry;
52    use serde_json::value::Value as Json;
53    use std::str::FromStr;
54
55    #[test]
56    fn test_if() {
57        let mut handlebars = Registry::new();
58        assert!(handlebars
59            .register_template_string("t0", "{{#if this}}hello{{/if}}")
60            .is_ok());
61        assert!(handlebars
62            .register_template_string("t1", "{{#unless this}}hello{{else}}world{{/unless}}")
63            .is_ok());
64
65        let r0 = handlebars.render("t0", &true);
66        assert_eq!(r0.ok().unwrap(), "hello".to_string());
67
68        let r1 = handlebars.render("t1", &true);
69        assert_eq!(r1.ok().unwrap(), "world".to_string());
70
71        let r2 = handlebars.render("t0", &false);
72        assert_eq!(r2.ok().unwrap(), String::new());
73    }
74
75    #[test]
76    fn test_if_context() {
77        let json_str = r#"{"a":{"b":99,"c":{"d": true}}}"#;
78        let data = Json::from_str(json_str).unwrap();
79
80        let mut handlebars = Registry::new();
81        handlebars.register_helper("with", Box::new(WITH_HELPER));
82        assert!(handlebars
83            .register_template_string("t0", "{{#if a.c.d}}hello {{a.b}}{{/if}}")
84            .is_ok());
85        assert!(handlebars
86            .register_template_string(
87                "t1",
88                "{{#with a}}{{#if c.d}}hello {{../a.b}}{{/if}}{{/with}}"
89            )
90            .is_ok());
91
92        let r0 = handlebars.render("t0", &data);
93        assert_eq!(r0.unwrap(), "hello 99".to_string());
94
95        let r1 = handlebars.render("t1", &data);
96        assert_eq!(r1.unwrap(), "hello 99".to_string());
97    }
98
99    #[test]
100    fn test_if_else_chain() {
101        let handlebars = Registry::new();
102
103        assert_eq!(
104            "0".to_owned(),
105            handlebars
106                .render_template("{{#if a}}1{{else if b}}2{{else}}0{{/if}}", &json!({"d": 1}))
107                .unwrap()
108        );
109    }
110
111    #[test]
112    fn test_if_else_chain2() {
113        let handlebars = Registry::new();
114
115        assert_eq!(
116            "3".to_owned(),
117            handlebars
118                .render_template(
119                    "{{#if a}}1{{else if b}}2{{else if c}}3{{else if d}}4{{else}}0{{/if}}",
120                    &json!({"c": 1, "d":1})
121                )
122                .unwrap()
123        );
124    }
125
126    #[test]
127    fn test_if_else_chain3() {
128        let handlebars = Registry::new();
129
130        assert_eq!(
131            "4".to_owned(),
132            handlebars
133                .render_template(
134                    "{{#if a}}1{{else if b}}2{{else if c}}3{{else if d}}4{{/if}}",
135                    &json!({"d":1})
136                )
137                .unwrap()
138        );
139    }
140
141    #[test]
142    fn test_if_else_chain4() {
143        let handlebars = Registry::new();
144
145        assert_eq!(
146            "1".to_owned(),
147            handlebars
148                .render_template(
149                    "{{#if a}}1{{else if b}}2{{else if c}}3{{else if d}}4{{/if}}",
150                    &json!({"a":1})
151                )
152                .unwrap()
153        );
154    }
155
156    #[test]
157    fn test_if_include_zero() {
158        use std::f64;
159        let handlebars = Registry::new();
160
161        assert_eq!(
162            "0".to_owned(),
163            handlebars
164                .render_template("{{#if a}}1{{else}}0{{/if}}", &json!({"a": 0}))
165                .unwrap()
166        );
167        assert_eq!(
168            "1".to_owned(),
169            handlebars
170                .render_template(
171                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
172                    &json!({"a": 0})
173                )
174                .unwrap()
175        );
176        assert_eq!(
177            "0".to_owned(),
178            handlebars
179                .render_template(
180                    "{{#if a includeZero=true}}1{{else}}0{{/if}}",
181                    &json!({ "a": f64::NAN })
182                )
183                .unwrap()
184        );
185    }
186
187    #[test]
188    fn test_invisible_line_stripping() {
189        let hbs = Registry::new();
190        assert_eq!(
191            "yes\n",
192            hbs.render_template("{{#if a}}\nyes\n{{/if}}\n", &json!({"a": true}))
193                .unwrap()
194        );
195
196        assert_eq!(
197            "yes\r\n",
198            hbs.render_template("{{#if a}}\r\nyes\r\n{{/if}}\r\n", &json!({"a": true}))
199                .unwrap()
200        );
201
202        assert_eq!(
203            "x\ny",
204            hbs.render_template("{{#if a}}x{{/if}}\ny", &json!({"a": true}))
205                .unwrap()
206        );
207
208        assert_eq!(
209            "y\nz",
210            hbs.render_template("{{#if a}}\nx\n{{^}}\ny\n{{/if}}\nz", &json!({"a": false}))
211                .unwrap()
212        );
213
214        assert_eq!(
215            r"yes
216  foo
217  bar
218  baz",
219            hbs.render_template(
220                r"yes
221  {{#if true}}
222  foo
223  bar
224  {{/if}}
225  baz",
226                &json!({})
227            )
228            .unwrap()
229        );
230
231        assert_eq!(
232            r"  foo
233  bar
234  baz",
235            hbs.render_template(
236                r"  {{#if true}}
237  foo
238  bar
239  {{/if}}
240  baz",
241                &json!({})
242            )
243            .unwrap()
244        );
245    }
246}