diff --git a/examples/block_helper_macro_let.rs b/examples/block_helper_macro_let.rs
new file mode 100644
index 000000000..96dc1024d
--- /dev/null
+++ b/examples/block_helper_macro_let.rs
@@ -0,0 +1,65 @@
+use handlebars::{
+ BlockParamHolder, Context, Handlebars, Helper, Output, RenderContext, RenderError,
+ RenderErrorReason,
+};
+use serde_json::{json, Value};
+
+// a custom block helper to bind a variable name to a value
+pub fn helper_let<'reg, 'rc>(
+ h: &Helper<'rc>,
+ _r: &'reg Handlebars<'reg>,
+ _ctx: &'rc Context,
+ rc: &mut RenderContext<'reg, 'rc>,
+ _out: &mut dyn Output,
+) -> Result<(), RenderError> {
+ let name_param = h
+ .param(0)
+ .ok_or_else(|| RenderErrorReason::ParamNotFoundForIndex("let", 0))?;
+
+ let Some(Value::String(name_constant)) = name_param.try_get_constant_value() else {
+ return Err(RenderErrorReason::ParamTypeMismatchForName(
+ "let",
+ "0".to_string(),
+ "constant string".to_string(),
+ )
+ .into());
+ };
+
+ let value = h
+ .param(1)
+ .as_ref()
+ .map(|v| v.value().to_owned())
+ .ok_or_else(|| RenderErrorReason::ParamNotFoundForIndex("let", 2))?;
+
+ let block = rc.block_mut().unwrap();
+
+ block.set_block_param(name_constant, BlockParamHolder::Value(value));
+
+ Ok(())
+}
+
+fn main() -> Result<(), RenderError> {
+ // create the handlebars registry
+ let mut handlebars = Handlebars::new();
+
+ handlebars.register_helper("let", Box::new(helper_let));
+
+ let input = r#"
+{{#if foo}}
+{{let "mixin_classes" "foo-bar baz"}}
+{{else}}
+{{let "mixin_classes" "quux"}}
+{{/if}}
+
+
+"#;
+
+ println!(
+ "{}",
+ handlebars.render_template(input, &json!({"foo": true}))?
+ );
+
+ Ok(())
+}
diff --git a/src/block.rs b/src/block.rs
index 10e429136..2a2f8f587 100644
--- a/src/block.rs
+++ b/src/block.rs
@@ -124,8 +124,13 @@ impl<'rc> BlockContext<'rc> {
self.block_params.get(block_param_name)
}
- /// Set a block parameter into this block.
+ /// Reassign the block parameters for this block.
pub fn set_block_params(&mut self, block_params: BlockParams<'rc>) {
self.block_params = block_params;
}
+
+ /// Set a block parameter into this block.
+ pub fn set_block_param(&mut self, key: &'rc str, value: BlockParamHolder) {
+ self.block_params.data.insert(key, value);
+ }
}
diff --git a/src/json/value.rs b/src/json/value.rs
index 16153052b..6d09d3288 100644
--- a/src/json/value.rs
+++ b/src/json/value.rs
@@ -88,6 +88,14 @@ impl<'rc> PathAndJson<'rc> {
self.value.as_json()
}
+ /// Returns the value, if it is a constant. Otherwise returns None.
+ pub fn try_get_constant_value(&self) -> Option<&'rc Json> {
+ match &self.value {
+ ScopedJson::Constant(value) => Some(*value),
+ ScopedJson::Context(_, _) | ScopedJson::Derived(_) | ScopedJson::Missing => None,
+ }
+ }
+
/// Test if value is missing
pub fn is_value_missing(&self) -> bool {
self.value.is_missing()
diff --git a/src/lib.rs b/src/lib.rs
index e41eee268..a2cdfc76d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -406,7 +406,7 @@ extern crate serde_derive;
#[macro_use]
extern crate serde_json;
-pub use self::block::{BlockContext, BlockParams};
+pub use self::block::{BlockContext, BlockParamHolder, BlockParams};
pub use self::context::Context;
pub use self::decorators::DecoratorDef;
pub use self::error::{RenderError, RenderErrorReason, TemplateError, TemplateErrorReason};