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}