From 26c71cce04fb154b90dbffbedd6ff2b85abac861 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 16 Jun 2024 19:58:59 +0200 Subject: [PATCH 1/5] add BlockContext::set_block_param --- src/block.rs | 7 ++++++- src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) 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/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}; From 485faf5d8bbcd5e97344865d2f8fbbb28444cb53 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 16 Jun 2024 20:15:13 +0200 Subject: [PATCH 2/5] make PathAndJson members pub --- src/json/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json/value.rs b/src/json/value.rs index 16153052b..c59fb9f4d 100644 --- a/src/json/value.rs +++ b/src/json/value.rs @@ -60,8 +60,8 @@ impl<'reg: 'rc, 'rc> From for ScopedJson<'rc> { /// #[derive(Debug, Clone)] pub struct PathAndJson<'rc> { - relative_path: Option, - value: ScopedJson<'rc>, + pub relative_path: Option, + pub value: ScopedJson<'rc>, } impl<'rc> PathAndJson<'rc> { From b176776136f07d19ae3d8ce5678ffb25ff609bc4 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 30 Jun 2024 03:26:17 +0200 Subject: [PATCH 3/5] add let helper as an example --- examples/block_helper_macro_let.rs | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 examples/block_helper_macro_let.rs diff --git a/examples/block_helper_macro_let.rs b/examples/block_helper_macro_let.rs new file mode 100644 index 000000000..7ebf53e29 --- /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 handlebars::ScopedJson::Constant(Value::String(name_constant)) = name_param.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(()) +} From 43db3741af7326294af29c704a2eb2c67744a7e4 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 30 Jun 2024 16:06:53 +0200 Subject: [PATCH 4/5] add an accessor function instead of exposing the members of PathAndJson --- examples/block_helper_macro_let.rs | 2 +- src/json/value.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/block_helper_macro_let.rs b/examples/block_helper_macro_let.rs index 7ebf53e29..96dc1024d 100644 --- a/examples/block_helper_macro_let.rs +++ b/examples/block_helper_macro_let.rs @@ -16,7 +16,7 @@ pub fn helper_let<'reg, 'rc>( .param(0) .ok_or_else(|| RenderErrorReason::ParamNotFoundForIndex("let", 0))?; - let handlebars::ScopedJson::Constant(Value::String(name_constant)) = name_param.value else { + let Some(Value::String(name_constant)) = name_param.try_get_constant_value() else { return Err(RenderErrorReason::ParamTypeMismatchForName( "let", "0".to_string(), diff --git a/src/json/value.rs b/src/json/value.rs index c59fb9f4d..db579069e 100644 --- a/src/json/value.rs +++ b/src/json/value.rs @@ -60,8 +60,8 @@ impl<'reg: 'rc, 'rc> From for ScopedJson<'rc> { /// #[derive(Debug, Clone)] pub struct PathAndJson<'rc> { - pub relative_path: Option, - pub value: ScopedJson<'rc>, + relative_path: Option, + value: ScopedJson<'rc>, } impl<'rc> PathAndJson<'rc> { @@ -88,6 +88,15 @@ 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(value, _) => Some(*value), + ScopedJson::Derived(_) | ScopedJson::Missing => None, + } + } + /// Test if value is missing pub fn is_value_missing(&self) -> bool { self.value.is_missing() From 12b2f56e88ea61769f1fbaad349bec00d2214d9a Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Tue, 2 Jul 2024 15:34:12 +0200 Subject: [PATCH 5/5] only return Some for 'direct' constants in `try_get_constant_value` --- src/json/value.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/json/value.rs b/src/json/value.rs index db579069e..6d09d3288 100644 --- a/src/json/value.rs +++ b/src/json/value.rs @@ -92,8 +92,7 @@ impl<'rc> PathAndJson<'rc> { pub fn try_get_constant_value(&self) -> Option<&'rc Json> { match &self.value { ScopedJson::Constant(value) => Some(*value), - ScopedJson::Context(value, _) => Some(*value), - ScopedJson::Derived(_) | ScopedJson::Missing => None, + ScopedJson::Context(_, _) | ScopedJson::Derived(_) | ScopedJson::Missing => None, } }