]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | /// Macro that allows you to quickly define a handlebars helper by passing a |
2 | /// name and a closure. | |
3 | /// | |
3dfed10e XL |
4 | /// There are several types of arguments available to closure: |
5 | /// | |
6 | /// * Parameters are mapped to closure arguments one by one. Any declared | |
7 | /// parameters are required | |
8 | /// * Hash are mapped as named arguments and declared in a bracket block. | |
9 | /// All named arguments are optional so default value is required. | |
10 | /// * An optional `*args` provides a vector of all helper parameters. | |
11 | /// * An optional `**kwargs` provides a map of all helper hash. | |
12 | /// | |
9fa01778 XL |
13 | /// # Examples |
14 | /// | |
15 | /// ```rust | |
16 | /// #[macro_use] extern crate handlebars; | |
17 | /// #[macro_use] extern crate serde_json; | |
18 | /// | |
19 | /// handlebars_helper!(is_above_10: |x: u64| x > 10); | |
3dfed10e | 20 | /// handlebars_helper!(is_above: |x: u64, { compare: u64 = 10 }| x > compare); |
9fa01778 XL |
21 | /// |
22 | /// # fn main() { | |
23 | /// # | |
24 | /// let mut handlebars = handlebars::Handlebars::new(); | |
25 | /// handlebars.register_helper("is-above-10", Box::new(is_above_10)); | |
3dfed10e | 26 | /// handlebars.register_helper("is-above", Box::new(is_above)); |
9fa01778 XL |
27 | /// |
28 | /// let result = handlebars | |
29 | /// .render_template("{{#if (is-above-10 12)}}great!{{else}}okay{{/if}}", &json!({})) | |
30 | /// .unwrap(); | |
31 | /// assert_eq!(&result, "great!"); | |
3dfed10e XL |
32 | /// let result2 = handlebars |
33 | /// .render_template("{{#if (is-above 12 compare=10)}}great!{{else}}okay{{/if}}", &json!({})) | |
34 | /// .unwrap(); | |
35 | /// assert_eq!(&result2, "great!"); | |
9fa01778 XL |
36 | /// # } |
37 | /// ``` | |
3dfed10e | 38 | |
9fa01778 XL |
39 | #[macro_export] |
40 | macro_rules! handlebars_helper { | |
3dfed10e XL |
41 | ($struct_name:ident: |$($name:ident: $tpe:tt),* |
42 | $($(,)?{$($hash_name:ident: $hash_tpe:tt=$dft_val:literal),*})? | |
43 | $($(,)?*$args:ident)? | |
44 | $($(,)?**$kwargs:ident)?| | |
45 | $body:expr ) => { | |
9fa01778 XL |
46 | #[allow(non_camel_case_types)] |
47 | pub struct $struct_name; | |
48 | ||
49 | impl $crate::HelperDef for $struct_name { | |
50 | #[allow(unused_assignments)] | |
51 | fn call_inner<'reg: 'rc, 'rc>( | |
52 | &self, | |
53 | h: &$crate::Helper<'reg, 'rc>, | |
94222f64 | 54 | r: &'reg $crate::Handlebars<'reg>, |
9fa01778 | 55 | _: &'rc $crate::Context, |
3dfed10e | 56 | _: &mut $crate::RenderContext<'reg, 'rc>, |
94222f64 | 57 | ) -> Result<$crate::ScopedJson<'reg, 'rc>, $crate::RenderError> { |
9fa01778 XL |
58 | let mut param_idx = 0; |
59 | ||
60 | $( | |
61 | let $name = h.param(param_idx) | |
94222f64 XL |
62 | .and_then(|x| { |
63 | if r.strict_mode() && x.is_value_missing() { | |
64 | None | |
65 | } else { | |
66 | Some(x.value()) | |
67 | } | |
68 | }) | |
9fa01778 XL |
69 | .ok_or_else(|| $crate::RenderError::new(&format!( |
70 | "`{}` helper: Couldn't read parameter {}", | |
3dfed10e | 71 | stringify!($struct_name), stringify!($name), |
9fa01778 XL |
72 | ))) |
73 | .and_then(|x| | |
74 | handlebars_helper!(@as_json_value x, $tpe) | |
75 | .ok_or_else(|| $crate::RenderError::new(&format!( | |
76 | "`{}` helper: Couldn't convert parameter {} to type `{}`. \ | |
77 | It's {:?} as JSON. Got these params: {:?}", | |
3dfed10e | 78 | stringify!($struct_name), stringify!($name), stringify!($tpe), |
9fa01778 XL |
79 | x, h.params(), |
80 | ))) | |
81 | )?; | |
82 | param_idx += 1; | |
83 | )* | |
84 | ||
3dfed10e XL |
85 | $( |
86 | $( | |
87 | let $hash_name = h.hash_get(stringify!($hash_name)) | |
88 | .map(|x| x.value()) | |
89 | .map(|x| | |
90 | handlebars_helper!(@as_json_value x, $hash_tpe) | |
91 | .ok_or_else(|| $crate::RenderError::new(&format!( | |
92 | "`{}` helper: Couldn't convert hash {} to type `{}`. \ | |
93 | It's {:?} as JSON. Got these hash: {:?}", | |
94 | stringify!($struct_name), stringify!($hash_name), stringify!($hash_tpe), | |
95 | x, h.hash(), | |
96 | ))) | |
97 | ) | |
98 | .unwrap_or_else(|| Ok($dft_val))?; | |
99 | )* | |
100 | )? | |
101 | ||
102 | $(let $args = h.params().iter().map(|x| x.value()).collect::<Vec<&serde_json::Value>>();)? | |
103 | $(let $kwargs = h.hash().iter().map(|(k, v)| (k.to_owned(), v.value())).collect::<std::collections::BTreeMap<&str, &serde_json::Value>>();)? | |
104 | ||
9fa01778 | 105 | let result = $body; |
94222f64 | 106 | Ok($crate::ScopedJson::Derived($crate::JsonValue::from(result))) |
9fa01778 XL |
107 | } |
108 | } | |
109 | }; | |
110 | ||
111 | (@as_json_value $x:ident, object) => { $x.as_object() }; | |
112 | (@as_json_value $x:ident, array) => { $x.as_array() }; | |
113 | (@as_json_value $x:ident, str) => { $x.as_str() }; | |
114 | (@as_json_value $x:ident, i64) => { $x.as_i64() }; | |
115 | (@as_json_value $x:ident, u64) => { $x.as_u64() }; | |
116 | (@as_json_value $x:ident, f64) => { $x.as_f64() }; | |
117 | (@as_json_value $x:ident, bool) => { $x.as_bool() }; | |
118 | (@as_json_value $x:ident, null) => { $x.as_null() }; | |
416331ca | 119 | (@as_json_value $x:ident, Json) => { Some($x) }; |
9fa01778 XL |
120 | } |
121 | ||
9fa01778 | 122 | #[cfg(feature = "no_logging")] |
94222f64 XL |
123 | #[macro_use] |
124 | #[doc(hidden)] | |
125 | pub mod logging { | |
126 | /// This macro is defined if the `logging` feature is set. | |
127 | /// | |
128 | /// It ignores all logging calls inside the library. | |
129 | #[doc(hidden)] | |
130 | #[macro_export] | |
131 | macro_rules! debug { | |
132 | (target: $target:expr, $($arg:tt)*) => {}; | |
133 | ($($arg:tt)*) => {}; | |
134 | } | |
9fa01778 | 135 | |
94222f64 XL |
136 | /// This macro is defined if the `logging` feature is not set. |
137 | /// | |
138 | /// It ignores all logging calls inside the library. | |
139 | #[doc(hidden)] | |
140 | #[macro_export] | |
141 | macro_rules! error { | |
142 | (target: $target:expr, $($arg:tt)*) => {}; | |
143 | ($($arg:tt)*) => {}; | |
144 | } | |
9fa01778 | 145 | |
94222f64 XL |
146 | /// This macro is defined if the `logging` feature is not set. |
147 | /// | |
148 | /// It ignores all logging calls inside the library. | |
149 | #[doc(hidden)] | |
150 | #[macro_export] | |
151 | macro_rules! info { | |
152 | (target: $target:expr, $($arg:tt)*) => {}; | |
153 | ($($arg:tt)*) => {}; | |
154 | } | |
9fa01778 | 155 | |
94222f64 XL |
156 | /// This macro is defined if the `logging` feature is not set. |
157 | /// | |
158 | /// It ignores all logging calls inside the library. | |
159 | #[doc(hidden)] | |
160 | #[macro_export] | |
161 | macro_rules! log { | |
162 | (target: $target:expr, $($arg:tt)*) => {}; | |
163 | ($($arg:tt)*) => {}; | |
164 | } | |
9fa01778 | 165 | |
94222f64 XL |
166 | /// This macro is defined if the `logging` feature is not set. |
167 | /// | |
168 | /// It ignores all logging calls inside the library. | |
169 | #[doc(hidden)] | |
170 | #[macro_export] | |
171 | macro_rules! trace { | |
172 | (target: $target:expr, $($arg:tt)*) => {}; | |
173 | ($($arg:tt)*) => {}; | |
174 | } | |
9fa01778 | 175 | |
94222f64 XL |
176 | /// This macro is defined if the `logging` feature is not set. |
177 | /// | |
178 | /// It ignores all logging calls inside the library. | |
179 | #[doc(hidden)] | |
180 | #[macro_export] | |
181 | macro_rules! warn { | |
182 | (target: $target:expr, $($arg:tt)*) => {}; | |
183 | ($($arg:tt)*) => {}; | |
184 | } | |
9fa01778 | 185 | } |