1use crate::context::Context;
2use crate::error::RenderError;
3use crate::helpers::{HelperDef, HelperResult};
4use crate::json::value::JsonTruthy;
5use crate::output::Output;
6use crate::registry::Registry;
7use crate::render::{Helper, RenderContext, Renderable};
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<'reg, '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_else(|| RenderError::new("Param not found for helper \"if\""))?;
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(), "".to_string());
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_include_zero() {
101 use std::f64;
102 let handlebars = Registry::new();
103
104 assert_eq!(
105 "0".to_owned(),
106 handlebars
107 .render_template("{{#if a}}1{{else}}0{{/if}}", &json!({"a": 0}))
108 .unwrap()
109 );
110 assert_eq!(
111 "1".to_owned(),
112 handlebars
113 .render_template(
114 "{{#if a includeZero=true}}1{{else}}0{{/if}}",
115 &json!({"a": 0})
116 )
117 .unwrap()
118 );
119 assert_eq!(
120 "0".to_owned(),
121 handlebars
122 .render_template(
123 "{{#if a includeZero=true}}1{{else}}0{{/if}}",
124 &json!({ "a": f64::NAN })
125 )
126 .unwrap()
127 );
128 }
129
130 #[test]
131 fn test_invisible_line_stripping() {
132 let hbs = Registry::new();
133 assert_eq!(
134 "yes\n",
135 hbs.render_template("{{#if a}}\nyes\n{{/if}}\n", &json!({"a": true}))
136 .unwrap()
137 );
138
139 assert_eq!(
140 "yes\r\n",
141 hbs.render_template("{{#if a}}\r\nyes\r\n{{/if}}\r\n", &json!({"a": true}))
142 .unwrap()
143 );
144
145 assert_eq!(
146 "x\ny",
147 hbs.render_template("{{#if a}}x{{/if}}\ny", &json!({"a": true}))
148 .unwrap()
149 );
150
151 assert_eq!(
152 "y\nz",
153 hbs.render_template("{{#if a}}\nx\n{{^}}\ny\n{{/if}}\nz", &json!({"a": false}))
154 .unwrap()
155 );
156
157 assert_eq!(
158 r#"yes
159 foo
160 bar
161 baz"#,
162 hbs.render_template(
163 r#"yes
164 {{#if true}}
165 foo
166 bar
167 {{/if}}
168 baz"#,
169 &json!({})
170 )
171 .unwrap()
172 );
173
174 assert_eq!(
175 r#" foo
176 bar
177 baz"#,
178 hbs.render_template(
179 r#" {{#if true}}
180 foo
181 bar
182 {{/if}}
183 baz"#,
184 &json!({})
185 )
186 .unwrap()
187 );
188 }
189}
190