• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sunng87 / handlebars-rust / 15733898660

11 Jun 2025 06:05PM UTC coverage: 82.399% (-0.1%) from 82.509%
15733898660

push

github

web-flow
feat: Added dynamic partial blocks by adding support for empty block closing tags (#713)

* Added support for empty partial block end

* Bump version to 6.3.3

* fix: panic when there was content after empty block ends

* Update Cargo.toml

---------

Co-authored-by: Ning Sun <classicning@gmail.com>

4 of 8 new or added lines in 1 file covered. (50.0%)

3 existing lines in 2 files now uncovered.

1587 of 1926 relevant lines covered (82.4%)

7.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.19
/src/macros.rs
1
/// Macro that allows you to quickly define a handlebars helper by passing a
2
/// name and a closure.
3
///
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
///
13
/// # Examples
14
///
15
/// ```rust
16
/// # use handlebars::{handlebars_helper, Handlebars};
17
/// # use serde_json::json;
18
/// handlebars_helper!(is_above_10: |x: u64| x > 10);
19
/// handlebars_helper!(is_above: |x: u64, { compare: u64 = 10 }| x > compare);
20
///
21
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
22
/// let mut handlebars = Handlebars::new();
23
/// handlebars.register_helper("is-above-10", Box::new(is_above_10));
24
/// handlebars.register_helper("is-above", Box::new(is_above));
25
///
26
/// let result = handlebars
27
///     .render_template("{{#if (is-above-10 12)}}great!{{else}}okay{{/if}}", &json!({}))?;
28
///  assert_eq!(&result, "great!");
29
///
30
/// let result2 = handlebars
31
///     .render_template("{{#if (is-above 12 compare=10)}}great!{{else}}okay{{/if}}", &json!({}))?;
32
///  assert_eq!(&result2, "great!");
33
/// # Ok(()) }
34
/// ```
35
#[macro_export]
36
macro_rules! handlebars_helper {
37
    ($struct_name:ident: |$($name:ident: $tpe:tt$(<$($gen:ty),+>)?),*
38
     $($(,)?{$($hash_name:ident: $hash_tpe:tt=$dft_val:literal),*})?
39
     $($(,)?*$args:ident)?
40
     $($(,)?**$kwargs:ident)?|
41
     $body:expr ) => {
42
        #[allow(non_camel_case_types)]
×
43
        pub struct $struct_name;
44

45
        impl $crate::HelperDef for $struct_name {
46
            #[allow(unused_assignments)]
47
            fn call_inner<'reg: 'rc, 'rc>(
27✔
48
                &self,
49
                h: &$crate::Helper<'rc>,
50
                r: &'reg $crate::Handlebars<'reg>,
51
                _: &'rc $crate::Context,
52
                _: &mut $crate::RenderContext<'reg, 'rc>,
53
            ) -> std::result::Result<$crate::ScopedJson<'rc>, $crate::RenderError> {
54
                let mut param_idx = 0;
27✔
55

56
                $(
57
                    let $name = h.param(param_idx)
41✔
58
                        .and_then(|x| {
38✔
59
                            if r.strict_mode() && x.is_value_missing() {
76✔
60
                                None
1✔
61
                            } else {
62
                                Some(x.value())
38✔
63
                            }
64
                        })
65
                        .ok_or_else(|| $crate::RenderErrorReason::ParamNotFoundForName(stringify!($struct_name), stringify!($name).to_string()))
6✔
66
                        .and_then(|x|
41✔
67
                                  $crate::handlebars_helper!(@as_json_value x, $tpe$(<$($gen),+>)?)
39✔
68
                                  .ok_or_else(|| $crate::RenderErrorReason::ParamTypeMismatchForName(stringify!($struct_name), stringify!($name).to_string(), stringify!($tpe$(<$($gen),+>)?).to_string()).into())
38✔
69
                        )?;
70
                    param_idx += 1;
39✔
71
                )*
72

73
                    $(
74
                        $(
75
                            let $hash_name = h.hash_get(stringify!($hash_name))
2✔
76
                                .map(|x| x.value())
4✔
77
                                .map(|x|
2✔
78
                                     $crate::handlebars_helper!(@as_json_value x, $hash_tpe)
2✔
79
                                     .ok_or_else(|| $crate::RenderErrorReason::HashTypeMismatchForName(
×
80
                                         stringify!($struct_name), stringify!($hash_name).to_string(), stringify!($hash_tpe).to_string()
×
81
                                     ))
82
                                )
83
                                .unwrap_or_else(|| Ok($dft_val))?;
4✔
84
                        )*
85
                    )?
86

87
                    $(let $args = h.params().iter().map(|x| x.value()).collect::<Vec<&serde_json::Value>>();)?
3✔
88
                    $(let $kwargs = h.hash().iter().map(|(k, v)| (k.to_owned(), v.value())).collect::<std::collections::BTreeMap<&str, &serde_json::Value>>();)?
3✔
89

90
                let result = $body;
1✔
91
                Ok($crate::ScopedJson::Derived($crate::JsonValue::from(result)))
28✔
92
            }
93
        }
94
    };
95

96
    (@as_json_value $x:ident, object) => { $x.as_object() };
97
    (@as_json_value $x:ident, array) => { $x.as_array() };
98
    (@as_json_value $x:ident, str) => { $x.as_str() };
99
    (@as_json_value $x:ident, i64) => { $x.as_i64() };
100
    (@as_json_value $x:ident, u64) => { $x.as_u64() };
6✔
101
    (@as_json_value $x:ident, f64) => { $x.as_f64() };
102
    (@as_json_value $x:ident, bool) => { $x.as_bool() };
103
    (@as_json_value $x:ident, null) => { $x.as_null() };
104
    (@as_json_value $x:ident, Json) => { Some($x) };
21✔
105
    (@as_json_value $x:ident, $tpe:tt$(<$($gen:ty),+>)?) => { serde_json::from_value::<$tpe$(<$($gen),+>)?>($x.clone()).ok() };
106
}
107

108
#[cfg(feature = "no_logging")]
109
#[macro_use]
110
#[doc(hidden)]
111
pub mod logging {
112
    /// This macro is defined if the `logging` feature is set.
113
    ///
114
    /// It ignores all logging calls inside the library.
115
    #[doc(hidden)]
×
116
    #[macro_export]
117
    macro_rules! debug {
118
        (target: $target:expr, $($arg:tt)*) => {};
119
        ($($arg:tt)*) => {};
120
    }
121

122
    /// This macro is defined if the `logging` feature is not set.
123
    ///
124
    /// It ignores all logging calls inside the library.
125
    #[doc(hidden)]
126
    #[macro_export]
127
    macro_rules! error {
128
        (target: $target:expr, $($arg:tt)*) => {};
129
        ($($arg:tt)*) => {};
130
    }
131

132
    /// This macro is defined if the `logging` feature is not set.
133
    ///
134
    /// It ignores all logging calls inside the library.
135
    #[doc(hidden)]
136
    #[macro_export]
137
    macro_rules! info {
138
        (target: $target:expr, $($arg:tt)*) => {};
139
        ($($arg:tt)*) => {};
140
    }
141

142
    /// This macro is defined if the `logging` feature is not set.
143
    ///
144
    /// It ignores all logging calls inside the library.
145
    #[doc(hidden)]
146
    #[macro_export]
147
    macro_rules! log {
148
        (target: $target:expr, $($arg:tt)*) => {};
149
        ($($arg:tt)*) => {};
150
    }
151

152
    /// This macro is defined if the `logging` feature is not set.
153
    ///
154
    /// It ignores all logging calls inside the library.
155
    #[doc(hidden)]
156
    #[macro_export]
157
    macro_rules! trace {
158
        (target: $target:expr, $($arg:tt)*) => {};
UNCOV
159
        ($($arg:tt)*) => {};
×
160
    }
161

162
    /// This macro is defined if the `logging` feature is not set.
163
    ///
164
    /// It ignores all logging calls inside the library.
165
    #[doc(hidden)]
166
    #[macro_export]
×
167
    macro_rules! warn {
×
UNCOV
168
        (target: $target:expr, $($arg:tt)*) => {};
×
169
        ($($arg:tt)*) => {};
170
    }
171
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc