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}} + +
+

content

+
+"#; + + 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};