]>
Commit | Line | Data |
---|---|---|
8bb4bdeb XL |
1 | handlebars-rust |
2 | =============== | |
3 | ||
4 | Rust templating with [Handlebars templating language](https://handlebarsjs.com). | |
5 | ||
6 | [![Build Status](https://travis-ci.org/sunng87/handlebars-rust.svg?branch=master)](https://travis-ci.org/sunng87/handlebars-rust) | |
7 | [![](http://meritbadge.herokuapp.com/handlebars)](https://crates.io/crates/handlebars) | |
8 | [![](https://img.shields.io/crates/d/handlebars.svg)](https://crates.io/crates/handlebars) | |
9 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) | |
83c7162d | 10 | [![Docs](https://docs.rs/handlebars/badge.svg)](https://docs.rs/crate/handlebars/) |
8bb4bdeb XL |
11 | |
12 | ## Getting Started | |
13 | ||
ea8adc8c XL |
14 | ### Quick Start |
15 | ||
16 | ```rust | |
17 | extern crate handlebars; | |
18 | #[macro_use] | |
19 | extern crate serde_json; | |
20 | ||
21 | use handlebars::Handlebars; | |
22 | ||
23 | fn main() { | |
24 | let mut reg = Handlebars::new(); | |
25 | // render without register | |
26 | println!( | |
27 | "{}", | |
83c7162d | 28 | reg.render_template("Hello {{name}}", &json!({"name": "foo"})) |
ea8adc8c XL |
29 | .unwrap() |
30 | ); | |
31 | ||
32 | // register template using given name | |
33 | reg.register_template_string("tpl_1", "Good afternoon, {{name}}") | |
34 | .unwrap(); | |
35 | println!("{}", reg.render("tpl_1", &json!({"name": "foo"})).unwrap()); | |
36 | } | |
37 | ``` | |
38 | ||
39 | Note that I use `unwrap` here which is not recommended in your real code. | |
40 | ||
41 | ### Code Example | |
42 | ||
8bb4bdeb XL |
43 | If you are not familiar with [handlebars language |
44 | syntax](https://handlebarsjs.com), it is recommended to walk through | |
45 | their introduction first. | |
46 | ||
47 | Check `render` example in the source tree. The example shows you how | |
48 | to: | |
49 | ||
50 | * Create a `Handlebars` registry and register the template from files; | |
51 | * Create a custom Helper with closure or struct implementing | |
52 | `HelperDef`, and register it; | |
53 | * Define and prepare some data; | |
54 | * Render it; | |
55 | ||
56 | Run `cargo run --example render` to see results. | |
57 | (or `RUST_LOG=handlebars=info cargo run --example render` for logging | |
58 | output). | |
59 | ||
60 | Checkout `examples/` for more concrete demos of current API. | |
61 | ||
041b39d2 XL |
62 | From 0.26, [Serde](https://serde.rs/) JSON is the default type system |
63 | for this library. The data you pass to handlebars template must | |
64 | implements the `Serialize` trait. Note that we don't actually | |
65 | serialize data to JSON string, we just use the JSON type: number, | |
66 | boolean and etc. | |
67 | ||
68 | Rustc_serialize is now officially deprecated. If your application is | |
69 | still using it, you need to use handlebars-rust `0.25.*`. | |
8bb4bdeb XL |
70 | |
71 | ## Documents | |
72 | ||
73 | [Rust | |
74 | doc](http://sunng87.github.io/handlebars-rust/handlebars/index.html). | |
75 | ||
76 | ## Changelog | |
77 | ||
78 | Change log is available in the source tree named as `CHANGELOG.md`. | |
79 | ||
8faf50e0 XL |
80 | ## Contributor Guide |
81 | ||
82 | Any contribution to this library is welcomed. To get started into | |
83 | development, I have several [Helper | |
84 | Wanted](https://github.com/sunng87/handlebars-rust/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) | |
85 | issue, with difficult level labeled. When running into any problem, | |
86 | feel free to contact me on github. | |
87 | ||
88 | I'm always looking for maintainers to work together on this library, | |
89 | also let me know (via email or anywhere in the issue tracker) if you | |
90 | want to join. | |
91 | ||
8bb4bdeb XL |
92 | ## Why (this) Handlebars? |
93 | ||
94 | Handlebars is a real-world templating system that you can use to build | |
95 | your application without pain. | |
96 | ||
97 | ### Features | |
98 | ||
99 | #### Isolation of Rust and HTML | |
100 | ||
101 | This library doesn't attempt to use some macro magic to allow you to | |
102 | write your template within your rust code. I admit that it's fun to do | |
103 | that but it doesn't fit real-world use case. | |
104 | ||
105 | #### Limited but essential control structure built-in | |
106 | ||
107 | Only essential control directive `if` and `each` were built-in. This | |
108 | prevents you to put too much application logic into your template. | |
109 | ||
110 | #### Extensible helper system | |
111 | ||
112 | You can write your own helper with Rust! It can be a block helper or | |
113 | inline helper. Put you logic into the helper and don't repeat | |
114 | yourself. | |
115 | ||
116 | A helper can be as a simple as a Rust function like: | |
117 | ||
118 | ```rust | |
119 | fn hex_helper (h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { | |
120 | // just for example, add error check for unwrap | |
121 | let param = h.param(0).unwrap().value(); | |
122 | let rendered = format!("0x{:x}", param.as_u64().unwrap()); | |
123 | try!(rc.writer.write(rendered.into_bytes().as_ref())); | |
124 | Ok(()) | |
125 | } | |
126 | ||
127 | /// register the helper | |
128 | handlebars.register_helper("hex", Box::new(hex_helper)); | |
129 | ``` | |
130 | ||
131 | And using it in your template: | |
132 | ||
133 | ```handlebars | |
134 | {{hex my_value}} | |
135 | ``` | |
136 | ||
137 | #### Template inheritance | |
138 | ||
139 | Every time I look into a templating system, I will investigate its | |
140 | support for [template | |
141 | inheritance](https://docs.djangoproject.com/en/1.9/ref/templates/language/#template-inheritance). | |
142 | ||
143 | Template include is not sufficient for template reuse. In most case | |
144 | you will need a skeleton of page as parent (header, footer, etc.), and | |
145 | embed you page into this parent. | |
146 | ||
147 | You can find a real example for template inheritance in | |
148 | `examples/partials.rs`, and templates used by this file. | |
149 | ||
8bb4bdeb XL |
150 | #### WebAssembly compatible |
151 | ||
152 | You can use this handlebars implementation in your rust project that | |
153 | compiles to WebAssembly. Checkout my fork of | |
154 | [todomvc](https://github.com/sunng87/rust-todomvc) demo. | |
155 | ||
83c7162d XL |
156 | #### Strict mode |
157 | ||
158 | Handlebars, the language designed to work with JavaScript, has no | |
159 | strict restriction on accessing non-existed fields or index. It | |
160 | generates empty string for such case. However, in Rust we want a | |
161 | little bit strict sometime. | |
162 | ||
8faf50e0 | 163 | By enabling `strict_mode` on handlebars: |
83c7162d XL |
164 | |
165 | ```rust | |
166 | handlebars.set_strict_mode(true); | |
167 | ``` | |
168 | ||
169 | You will get a `RenderError` when accessing fields that not exists. | |
170 | ||
8bb4bdeb XL |
171 | ### Limitations |
172 | ||
173 | * This implementation is **not fully compatible** with the original | |
174 | javascript version. Specifically, mustache list iteration and null | |
175 | check doesn't work. But you can use `#each` and `#if` for same | |
176 | behavior. | |
ea8adc8c XL |
177 | * You will need to make your data `Serializable` on serde. We don't |
178 | actually serialize data into JSON string or similar. However, we use | |
179 | JSON data type system in template render process. | |
8bb4bdeb XL |
180 | |
181 | ### Handlebars-js features supported in Handlebars-rust | |
182 | ||
183 | * Expression / Block Helpers | |
184 | * Built-in helpers | |
185 | * each | |
186 | * if | |
187 | * with | |
188 | * lookup | |
189 | * log | |
190 | * Custom helper | |
191 | * Parameter and hashes for helper, block params | |
192 | * Partials, include, template inheritance | |
193 | * Omitting whitespace with `~` | |
194 | * Subexpression `{{(foo bar)}}` | |
195 | * Json expression `a.b.[0]` and `a.b.[c]` | |
196 | * RawHelper syntax `{{{{raw-helper}}}}...{{{{/raw-helper}}}}` | |
197 | * Decorator, implemented in Rust way | |
198 | ||
199 | ### JavaScript implementation features we don't have | |
200 | ||
201 | * Mustache block (use `if`/`each` instead) | |
202 | * Chained else | |
203 | ||
204 | Feel free to report an issue if you find something broken. We aren't | |
205 | going to implement all features of handlebars-js, but we should have a | |
206 | workaround for cases we don't support. | |
207 | ||
208 | ## Handlebars for Web Frameworks | |
209 | ||
210 | * Iron: [handlebars-iron](https://github.com/sunng87/handlebars-iron) | |
211 | * Rocket: [rocket/contrib](https://api.rocket.rs/rocket_contrib/struct.Template.html) | |
212 | ||
213 | ## Using handlebars-rust? | |
214 | ||
215 | Add your project to our | |
216 | [adopters](https://github.com/sunng87/handlebars-rust/wiki/adopters). | |
217 | ||
218 | ## License | |
219 | ||
220 | This library (handlebars-rust) is open sourced under MIT License. | |
221 | ||
222 | ## Contact | |
223 | ||
83c7162d | 224 | [Ning Sun](https://github.com/sunng87) (sunng@protonmail.com) |