Skip to main content
The bomboni_template crate provides a comprehensive collection of custom Handlebars helpers for template rendering. These helpers enable mathematical operations, string transformations, value manipulation, conditional logic, and dynamic template rendering.

Quick Start

Register all helpers with your Handlebars instance:
use handlebars::Handlebars;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

Math Operations

Perform mathematical calculations directly in templates:
use handlebars::Handlebars;
use serde_json::Value;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

// Basic arithmetic
assert_eq!(hbs.render_template("{{add 1 2}}", &Value::Null).unwrap(), "3.0");
assert_eq!(hbs.render_template("{{multiply 5 3}}", &Value::Null).unwrap(), "15.0");
assert_eq!(hbs.render_template("{{subtract 10 4}}", &Value::Null).unwrap(), "6.0");
assert_eq!(hbs.render_template("{{divide 20 4}}", &Value::Null).unwrap(), "5.0");

// Advanced operations
assert_eq!(hbs.render_template("{{sqrt 2}}", &Value::Null).unwrap(), "1.4142135623730951");
assert_eq!(hbs.render_template("{{pow 2 8}}", &Value::Null).unwrap(), "256.0");
assert_eq!(hbs.render_template("{{clamp 5 1 3}}", &Value::Null).unwrap(), "3.0");
assert_eq!(hbs.render_template("{{absolute -42}}", &Value::Null).unwrap(), "42.0");

Available Math Helpers

HelperDescriptionExample
addAddition{{add 1 2}}3.0
subtractSubtraction{{subtract 10 4}}6.0
multiplyMultiplication{{multiply 5 3}}15.0
divideDivision{{divide 20 4}}5.0
moduloModulo operation{{modulo 10 3}}1.0
negateNegate value{{negate 5}}-5.0
absoluteAbsolute value{{absolute -42}}42.0
roundRound to nearest{{round 3.7}}4.0
ceilCeiling{{ceil 3.2}}4.0
floorFloor{{floor 3.8}}3.0
sqrtSquare root{{sqrt 16}}4.0
signSign of number{{sign -5}}-1.0
powPower{{pow 2 8}}256.0
clampClamp between min/max{{clamp 5 1 3}}3.0

String Helpers

Case Conversion

Transform strings between different case conventions:
use handlebars::Handlebars;
use serde_json::Value;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

assert_eq!(
    hbs.render_template(r#"{{upperCase "hello world"}}"#, &Value::Null).unwrap(),
    "HELLO WORLD"
);

assert_eq!(
    hbs.render_template(r#"{{pascalCase "hello world"}}"#, &Value::Null).unwrap(),
    "HelloWorld"
);

assert_eq!(
    hbs.render_template(r#"{{snakeCase "hello world"}}"#, &Value::Null).unwrap(),
    "hello_world"
);

assert_eq!(
    hbs.render_template(r#"{{screamingSnakeCase "hello world"}}"#, &Value::Null).unwrap(),
    "HELLO_WORLD"
);

assert_eq!(
    hbs.render_template(r#"{{camelCase "hello world"}}"#, &Value::Null).unwrap(),
    "helloWorld"
);

assert_eq!(
    hbs.render_template(r#"{{kebabCase "hello world"}}"#, &Value::Null).unwrap(),
    "hello-world"
);

Available Case Helpers

  • upperCase - UPPER CASE
  • lowerCase - lower case
  • titleCase - Title Case
  • camelCase - camelCase
  • pascalCase - PascalCase
  • snakeCase - snake_case
  • screamingSnakeCase - SCREAMING_SNAKE_CASE
  • kebabCase - kebab-case
  • trainCase - Train-Case
  • cobolCase - COBOL-CASE
  • flatCase - flatcase
  • toggleCase - tOGGLE cASE
  • alternatingCase - aLtErNaTiNg CaSe

String Formatting

use handlebars::Handlebars;
use serde_json::{Value, json};
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

// Convert to integer string
assert_eq!(
    hbs.render_template(r"{{toIntegerString 3.14}}", &Value::Null).unwrap(),
    "3"
);

// Concatenate values
assert_eq!(
    hbs.render_template(r#"{{concat "Hello" " " "World"}}"#, &Value::Null).unwrap(),
    "Hello World"
);

// Convert to JSON
let data = json!({"name": "Alice", "age": 30});
assert_eq!(
    hbs.render_template(r"{{toJson this}}", &data).unwrap(),
    r#"{"age":30,"name":"Alice"}"#
);

Value Helpers

Object and Array Operations

use handlebars::Handlebars;
use serde_json::Value;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

// Create objects
assert_eq!(
    hbs.render_template(r#"{{objectHasKey (object x=42) "x"}}"#, &Value::Null).unwrap(),
    "true"
);

// Create arrays
assert_eq!(
    hbs.render_template(r"{{contains (array 1 2 3 4) 2}}", &Value::Null).unwrap(),
    "true"
);

// Check truthiness
assert_eq!(
    hbs.render_template(r"{{none false 0}}", &Value::Null).unwrap(),
    "true"
);

assert_eq!(
    hbs.render_template(r"{{all true 1 \"text\"}}", &Value::Null).unwrap(),
    "true"
);

assert_eq!(
    hbs.render_template(r"{{some false 0 true}}", &Value::Null).unwrap(),
    "true"
);

Available Value Helpers

HelperDescription
objectCreate object from named parameters
objectHasKeyCheck if object has key
arrayCreate array from parameters
groupByGroup array by key
containsCheck if haystack contains needle
noneCheck if all values are falsy
allCheck if all values are truthy
someCheck if some value is truthy
filterFilter array by predicate template
orElseReturn item if truthy, else fallback
andThenReturn fallback if item truthy, else item
eitherOrConditional value selection

Group By Example

use handlebars::Handlebars;
use serde_json::Value;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

// Group objects by a key
hbs.render_template(
    r#"{{groupBy (array (object x=1 y=2) (object x=2 y=4)) "x"}}"#,
    &Value::Null
).unwrap();

Switch/Case Pattern Matching

Implement pattern matching in templates:
use handlebars::Handlebars;
use serde_json::json;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

let template = r#"
{{#switch x}}
    {{#case 42}}life{{/case}}
    {{#case 2 4 8}}power of two{{/case}}
    {{#default}}other{{/default}}
{{/switch}}
"#;

assert_eq!(hbs.render_template(template, &json!({"x": 42})).unwrap().trim(), "life");
assert_eq!(hbs.render_template(template, &json!({"x": 2})).unwrap().trim(), "power of two");
assert_eq!(hbs.render_template(template, &json!({"x": 5})).unwrap().trim(), "other");

Switch Statement Structure

{{#switch value}}
    {{#case "option1"}}Handle option 1{{/case}}
    {{#case "option2" "option3"}}Handle options 2 or 3{{/case}}
    {{#default}}Handle all other cases{{/default}}
{{/switch}}
The case helper supports multiple values, matching if any value equals the switch value.

Dynamic Template Rendering

Render templates dynamically at runtime:
use handlebars::Handlebars;
use serde_json::json;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

// Render a template string with current context
assert_eq!(
    hbs.render_template(r#"{{render "x = {{x}}"}}"#, &json!({"x": 42})).unwrap(),
    "x = 42"
);

// Use with nested data
let template = r#"{{render "User: {{user.name}}, Age: {{user.age}}"}}"}"#;
assert_eq!(
    hbs.render_template(template, &json!({
        "user": {"name": "Alice", "age": 30}
    })).unwrap(),
    "User: Alice, Age: 30"
);
This is particularly useful for:
  • Code generation with dynamic templates
  • Configuration-driven template composition
  • Building templates from database content

Local Variables

Set and use local variables within templates:
use handlebars::Handlebars;
use bomboni_template::helpers::register_helpers;

let mut hbs = Handlebars::new();
register_helpers(&mut hbs);

let template = r#"
{{*set name = "John" age = 14000}}
{{@name}} is {{@age}} years old.
"#;

let rendered = hbs.render_template(template, &serde_json::Value::Null).unwrap();
assert_eq!(rendered.trim(), "John is 14000 years old.");

Variable Scope

Local variables set with the set decorator:
  • Use the * prefix for decorators: {{*set ...}}
  • Access with @ prefix: {{@variableName}}
  • Are scoped to the current template block
  • Can be used in nested contexts

Use Cases

Code Generation

{{*set structName = (pascalCase name)}}
struct {{@structName}} {
    {{#each fields}}
    pub {{snakeCase this.name}}: {{this.type}},
    {{/each}}
}

API Response Formatting

{{#switch status}}
    {{#case 200 201}}Success: {{message}}{{/case}}
    {{#case 400 404}}Client Error: {{error}}{{/case}}
    {{#default}}Server Error{{/default}}
{{/switch}}

Configuration Templates

{{*set port = (orElse config.port 8080)}}
server:
  host: {{config.host}}
  port: {{@port}}
  workers: {{multiply cpus 2}}

Best Practices

Register helpers once at application startup for optimal performance.
Avoid complex logic in templates. Use helpers for simple transformations and move business logic to your Rust code.

Performance Tips

  • Compile templates ahead of time with hbs.register_template_string()
  • Reuse Handlebars instances across requests
  • Keep templates focused on presentation logic
  • Use render helper sparingly as it has runtime overhead

Request Parsing

Parse and validate API requests

Protocol Buffers

Work with protobuf messages

Build docs developers (and LLMs) love