Crate handlebars[stability] [-] [+] [src]

Handlebars

Handlebars is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like Ember.js and Chaplin. It's also ported to some other platforms such as Java.

And this is handlebars Rust implementation, designed for server-side page generation. It's a general-purpose library so you use it for any kind of text generation.

Handlebars spec

Base

You can go to Handlebars.js website for its syntax. This implementation should be compatible with most parts of the spec, except:

Extensions

We have template reuse facilities supported via built-in helpers >, partial and block.

There are two ways to reuse a template:

Consult Handlebar.java document about template inheritance.

Usage

Template Creation and Registration

Templates are created from String and registered to Handlebars with a name.


extern crate handlebars;

use handlebars::Handlebars;

fn main() {
  let mut handlebars = Handlebars::new();
  let source = "hello {{world}}";

  //compile returns an Option, we use unwrap() to deref it directly here
  handlebars.register_template_string("helloworld", source.to_string())
          .ok().unwrap();
}

Rendering Something

I should say that rendering is a little tricky. Since handlebars is originally a JavaScript templating framework. It supports dynamic features like duck-typing, truthy/falsy values. But for a static language like Rust, this is a little difficult. As a solution, I'm using the serialize::json::Json internally for data rendering, which seems good by far.

That means, if you want to render something, you have to ensure that it implements the serialize::json::ToJson trait. Luckily, most built-in types already have trait. However, if you want to render your custom struct, you need to implement this trait manually. (Rust has a deriving facility, but it's just for selected types. Maybe I will add some syntax extensions or macros to simplify this process.)

extern crate rustc_serialize;
extern crate handlebars;

use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;

use handlebars::Handlebars;

struct Person {
  name: String,
  age: i16,
}

impl ToJson for Person {
  fn to_json(&self) -> Json {
    let mut m: BTreeMap<String, Json> = BTreeMap::new();
    m.insert("name".to_string(), self.name.to_json());
    m.insert("age".to_string(), self.age.to_json());
    m.to_json()
  }
}

fn main() {
  let source = "hello {{world}}";

  let mut handlebars = Handlebars::new();
  handlebars.register_template_string("helloworld", source.to_string())
          .ok().unwrap();

  let mut data = Person {
      name: "Ning Sun".to_string(),
      age: 27
  };
  let result = handlebars.render("helloworld", &data);
}

Custom Helper

Handlebars is nothing without helpers. You can also create your own helpers with rust. Helpers in handlebars-rust are custom struct implements the HelperDef trait, concretely, the call function. For your convenience, most of stateless helpers can be implemented as bare functions.


extern crate handlebars;

use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};

// implement by a structure impls HelperDef
#[derive(Clone, Copy)]
struct SimpleHelper;

impl HelperDef for SimpleHelper {
  fn call(&self, c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
    let param = h.params().get(0).unwrap();

    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let value = c.navigate(rc.get_path(), param);
    Ok(format!("My helper dumps: {} ", value))
  }
}

// implement via bare function
fn another_simple_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
    let param = h.params().get(0).unwrap();

    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let value = c.navigate(rc.get_path(), param);
    Ok(format!("My second helper dumps: {} ", value))
}


fn main() {
  let mut handlebars = Handlebars::new();
  handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
  handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
  // via closure
  handlebars.register_helper("closure-helper",
      Box::new(|c: &Context, h: &Helper, r: &Handlebars, rc: &mut RenderContext| -> Result<String, RenderError>{
        Ok(format!("..."))
      }));

  //...
}

Arguments of HelpDef

You can get data from the Helper argument about the template information:

You can learn more about helpers by looking into source code of built-in helpers.

Built-in Helpers

Structs

Context
Handlebars
Helper
RenderContext
RenderError
Template
TemplateError

Traits

HelperDef

Helper Definitions

JsonRender
JsonTruthy
Renderable