1use cruet::Inflector;
2use handlebars::{
3 handlebars_helper, Context, Handlebars, Helper, HelperDef, RenderContext, RenderError,
4 ScopedJson,
5};
6
7#[macro_export]
8macro_rules! handlebars_register_cruet {
9 ($engine:ident, $fct_name:ident) => {
10 {
11 handlebars_helper!($fct_name: |v: str| v.$fct_name());
12 $engine.register_helper(stringify!($fct_name), Box::new($fct_name))
13 }
14 }
15}
16
17#[allow(non_camel_case_types)]
18pub struct first_non_empty_fct;
19
20impl HelperDef for first_non_empty_fct {
21 fn call_inner<'reg: 'rc, 'rc>(
22 &self,
23 h: &Helper<'rc>,
24 _: &'reg Handlebars,
25 _: &'rc Context,
26 _: &mut RenderContext<'reg, 'rc>,
27 ) -> Result<ScopedJson<'reg>, RenderError> {
28 let params = h.params();
29 Ok(params
30 .iter()
31 .filter_map(|p| p.value().as_str().filter(|s| !s.is_empty()))
32 .next()
38 .map(|v| ScopedJson::Derived(serde_json::Value::String(v.to_owned())))
39 .unwrap_or_else(|| ScopedJson::Derived(serde_json::Value::String("".to_owned()))))
40 }
41}
42
43pub fn register(handlebars: &mut Handlebars) {
44 {
45 handlebars_helper!(to_lower_case: |v: str| v.to_lowercase());
46 handlebars.register_helper("to_lower_case", Box::new(to_lower_case))
47 }
48 {
49 handlebars_helper!(to_upper_case: |v: str| v.to_uppercase());
50 handlebars.register_helper("to_upper_case", Box::new(to_upper_case))
51 }
52 {
53 handlebars_helper!(trim: |v: str| v.trim());
54 handlebars.register_helper("trim", Box::new(trim))
55 }
56 {
57 handlebars_helper!(trim_start: |v: str| v.trim_start());
58 handlebars.register_helper("trim_start", Box::new(trim_start))
59 }
60 {
61 handlebars_helper!(trim_end: |v: str| v.trim_end());
62 handlebars.register_helper("trim_end", Box::new(trim_end))
63 }
64 {
65 handlebars_helper!(replace: |v: str, from: str, to: str| v.replace(from, to));
66 handlebars.register_helper("replace", Box::new(replace))
67 }
68 handlebars_register_cruet!(handlebars, is_class_case);
69 handlebars_register_cruet!(handlebars, to_class_case);
70 handlebars_register_cruet!(handlebars, is_camel_case);
71 handlebars_register_cruet!(handlebars, to_camel_case);
72 handlebars_register_cruet!(handlebars, is_pascal_case);
73 handlebars_register_cruet!(handlebars, to_pascal_case);
74 handlebars_register_cruet!(handlebars, is_snake_case);
75 handlebars_register_cruet!(handlebars, to_snake_case);
76 handlebars_register_cruet!(handlebars, is_screaming_snake_case);
77 handlebars_register_cruet!(handlebars, to_screaming_snake_case);
78 handlebars_register_cruet!(handlebars, is_kebab_case);
79 handlebars_register_cruet!(handlebars, to_kebab_case);
80 handlebars_register_cruet!(handlebars, is_train_case);
81 handlebars_register_cruet!(handlebars, to_train_case);
82 handlebars_register_cruet!(handlebars, is_sentence_case);
83 handlebars_register_cruet!(handlebars, to_sentence_case);
84 handlebars_register_cruet!(handlebars, is_title_case);
85 handlebars_register_cruet!(handlebars, to_title_case);
86 handlebars_register_cruet!(handlebars, is_table_case);
87 handlebars_register_cruet!(handlebars, to_table_case);
88 handlebars_register_cruet!(handlebars, deordinalize);
89 handlebars_register_cruet!(handlebars, ordinalize);
90 handlebars_register_cruet!(handlebars, is_foreign_key);
91 handlebars_register_cruet!(handlebars, to_foreign_key);
92 handlebars_register_cruet!(handlebars, deconstantize);
93 handlebars_register_cruet!(handlebars, demodulize);
94 handlebars_register_cruet!(handlebars, to_plural);
95 handlebars_register_cruet!(handlebars, to_singular);
96 {
97 handlebars_helper!(quote: |quote_symbol: str, v: str| enquote::enquote(quote_symbol.chars().next().unwrap_or('"'), v));
98 handlebars.register_helper("quote", Box::new(quote))
99 }
100 {
101 handlebars_helper!(unquote: |v: str| match enquote::unquote(v){
102 Err(e) => {
103 log::warn!(
104 "helper: unquote failed for string '{:?}' with error '{:?}'",
105 v, e
106 );
107 v.to_owned()
108 }
109 Ok(s) => s,
110 });
111 handlebars.register_helper("unquote", Box::new(unquote))
112 }
113 handlebars.register_helper("first_non_empty", Box::new(first_non_empty_fct));
114}
115
116#[cfg(test)]
117mod tests {
118 use crate::assert_renders;
119 use crate::tests::assert_helpers;
120 use std::error::Error;
121
122 #[test]
123 fn test_register_string_helpers() -> Result<(), Box<dyn Error>> {
124 assert_helpers(
125 "Hello foo-bars",
126 vec![
127 ("to_lower_case", "hello foo-bars"),
128 ("to_upper_case", "HELLO FOO-BARS"),
129 ("to_camel_case", "helloFooBars"),
130 ("to_pascal_case", "HelloFooBars"),
131 ("to_snake_case", "hello_foo_bars"),
132 ("to_screaming_snake_case", "HELLO_FOO_BARS"),
133 ("to_kebab_case", "hello-foo-bars"),
134 ("to_train_case", "Hello-Foo-Bars"),
135 ("to_sentence_case", "Hello foo bars"),
136 ("to_title_case", "Hello Foo Bars"),
137 ("to_class_case", "HelloFooBar"),
138 ("to_table_case", "hello_foo_bars"),
139 ("to_plural", "bars"),
140 ("to_singular", "bar"),
141 ],
142 )?;
143 Ok(())
144 }
145
146 #[test]
147 fn test_helper_trim() -> Result<(), Box<dyn Error>> {
148 assert_renders![
149 (r##"{{ trim "foo" }}"##, r##"foo"##),
150 (r##"{{ trim " foo" }}"##, r##"foo"##),
151 (r##"{{ trim "foo " }}"##, r##"foo"##),
152 (r##"{{ trim " foo " }}"##, r##"foo"##)
153 ]
154 }
155
156 #[test]
157 fn test_helper_trim_start() -> Result<(), Box<dyn Error>> {
158 assert_renders![
159 (r##"{{ trim_start "foo" }}"##, r##"foo"##),
160 (r##"{{ trim_start " foo" }}"##, r##"foo"##),
161 (r##"{{ trim_start "foo " }}"##, r##"foo "##),
162 (r##"{{ trim_start " foo " }}"##, r##"foo "##)
163 ]
164 }
165
166 #[test]
167 fn test_helper_trim_end() -> Result<(), Box<dyn Error>> {
168 assert_renders![
169 (r##"{{ trim_end "foo" }}"##, r##"foo"##),
170 (r##"{{ trim_end " foo" }}"##, r##" foo"##),
171 (r##"{{ trim_end "foo " }}"##, r##"foo"##),
172 (r##"{{ trim_end " foo " }}"##, r##" foo"##)
173 ]
174 }
175
176 #[test]
177 fn test_helper_quote() -> Result<(), Box<dyn Error>> {
178 assert_renders![
179 (r##"{{ quote "'" "''" }}"##, r##"'\'\''"##),
180 (r##"{{ quote "'" "foo" }}"##, r##"'foo'"##),
181 (r##"{{ quote "\"" "foo" }}"##, r##""foo""##),
182 (r##"{{ quote "" "foo" }}"##, r##""foo""##),
183 ]
184 }
185
186 #[test]
187 fn test_helper_unquote() -> Result<(), Box<dyn Error>> {
188 assert_renders![
189 (r##"{{ unquote "''" }}"##, r##""##),
190 (r##"{{ unquote "'f'" }}"##, r##"f"##),
191 (r##"{{ unquote "foo" }}"##, r##"foo"##),
192 (r##"{{ unquote "'foo'" }}"##, r##"foo"##),
193 (r##"{{ unquote "\"foo\"" }}"##, r##"foo"##),
194 (r##"{{ unquote "foo'" }}"##, r##"foo'"##),
195 (r##"{{ unquote "'foo" }}"##, r##"'foo"##),
196 ]
197 }
198
199 #[test]
200 fn test_helper_replace() -> Result<(), Box<dyn Error>> {
201 assert_renders![(r##"{{ replace "foo" "oo" "aa"}}"##, r##"faa"##)]
202 }
203
204 #[test]
205 fn test_helper_first_non_empty() -> Result<(), Box<dyn Error>> {
206 assert_renders![
207 (r##"{{ first_non_empty ""}}"##, r##""##),
208 (r##"{{ first_non_empty "foo"}}"##, r##"foo"##),
209 (r##"{{ first_non_empty "foo" "bar"}}"##, r##"foo"##),
210 (r##"{{ first_non_empty "" "foo"}}"##, r##"foo"##),
211 (r##"{{ first_non_empty "" "foo" "bar"}}"##, r##"foo"##),
212 (r##"{{ first_non_empty "" null}}"##, r##""##),
213 (r##"{{ first_non_empty "" null 33}}"##, r##""##),
214 (r##"{{ first_non_empty "" null "foo" "bar"}}"##, r##"foo"##),
215 ]
216 }
217}