]> git.proxmox.com Git - rustc.git/blame - src/vendor/handlebars/src/lib.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / vendor / handlebars / src / lib.rs
CommitLineData
8bb4bdeb
XL
1//! # Handlebars
2//!
3//! [Handlebars](http://handlebarsjs.com/) is a modern and extensible templating solution originally created in the JavaScript world. It's used by many popular frameworks like [Ember.js](http://emberjs.com) and Chaplin. It's also ported to some other platforms such as [Java](https://github.com/jknack/handlebars.java).
4//!
5//! And this is handlebars Rust implementation, designed for general purpose text generation.
6//!
7//! ## Quick Start
8//!
9//! ```
10//! use std::collections::BTreeMap;
11//! use handlebars::Handlebars;
12//!
13//! fn main() {
14//! // create the handlebars registry
15//! let mut handlebars = Handlebars::new();
16//!
17//! // register the template. The template string will be verified and compiled.
18//! let source = "hello {{world}}";
19//! assert!(handlebars.register_template_string("t1", source).is_ok());
20//!
21//! // Prepare some data.
22//! //
041b39d2 23//! // The data type should implements `serde::Serialize`
8bb4bdeb
XL
24//! let mut data = BTreeMap::new();
25//! data.insert("world".to_string(), "世界!".to_string());
26//! assert_eq!(handlebars.render("t1", &data).unwrap(), "hello 世界!");
27//! }
28//! ```
29//!
30//! In this example, we created a template registry and registered a template named `t1`.
31//! Then we rendered a `BTreeMap` with an entry of key `world`, the result is just what
32//! we expected.
33//!
34//! I recommend you to walk through handlebars.js' [intro page](http://handlebarsjs.com)
35//! if you are not quite familiar with the template language itself.
36//!
37//! ## Rational: Why (this) Handlebars?
38//!
39//! Handlebars is a real-world templating system that you can use to build
40//! your application without pain.
41//!
42//! ### Features
43//!
44//! #### Isolation of Rust and HTML
45//!
46//! This library doesn't attempt to use some macro magic to allow you to
47//! write your template within your rust code. I admit that it's fun (and feel cool) to do
48//! that but it doesn't fit real-world use case in my opinion.
49//!
50//! #### Limited but essential control structure built-in
51//!
52//! Only essential control directive `if` and `each` were built-in. This
53//! prevents you to put too much application logic into your template.
54//!
55//! #### Extensible helper system
56//!
57//! You can write your own helper with Rust! It can be a block helper or
58//! inline helper. Put you logic into the helper and don't repeat
59//! yourself.
60//!
61//! #### Template inheritance
62//!
63//! Every time I look into a templating system, I will investigate its
64//! support for [template
65//! inheritance](https://docs.djangoproject.com/en/1.9/ref/templates/language/#template-inh
66//! eritance).
67//!
68//! Template include is not enough. In most case you will need a skeleton
69//! of page as parent (header, footer, etc.), and embed you page into this
70//! parent.
71//!
72//! You can find a real example for template inheritance in
73//! `examples/partials.rs`, and templates used by this file.
74//!
75//! ### Limitations
76//!
77//! #### Compatibility with JavaScript version
78//!
79//! This implementation is **not fully compatible** with the original javascript version.
80//!
81//! First of all, mustache block is not supported. I suggest you to use `#if` and `#each` for
82//! same functionality.
83//!
84//! There are some other minor features missing:
85//!
86//! * Chained else [#12](https://github.com/sunng87/handlebars-rust/issues/12)
87//!
88//! Feel free to fire an issue on [github](https://github.com/sunng87/handlebars-rust/issues) if
89//! you find missing features.
90//!
91//! #### Static typed
92//!
93//! As a static typed language, it's a little verbose to use handlebars.
041b39d2
XL
94//! Handlebars templating language is designed against JSON data type. In rust,
95//! we will convert user's structs, vectors or maps to JSON type in order to use
96//! in template. You have to make sure your data implements the `Serialize` trait
97//! from the [Serde](https://serde.rs) project.
8bb4bdeb
XL
98//!
99//! ## Usage
100//!
101//! ### Template Creation and Registration
102//!
103//! Templates are created from String and registered to `Handlebars` with a name.
104//!
105//! ```
106//!
107//! extern crate handlebars;
108//!
109//! use handlebars::Handlebars;
110//!
111//! fn main() {
112//! let mut handlebars = Handlebars::new();
113//! let source = "hello {{world}}";
114//!
115//! assert!(handlebars.register_template_string("t1", source).is_ok())
116//! }
117//! ```
118//!
119//! On registeration, the template is parsed, compiled and cached in the registry. So further
120//! usage will benifite from the one-time work. Also features like include, inheritance
121//! that involves template reference requires you to register those template first with
122//! a name so the registry can find it.
123//!
124//! If you template is small or just to expirement, you can use `template_render` API
125//! without registration.
126//!
127//! ```
128//! use handlebars::Handlebars;
129//! use std::collections::BTreeMap;
130//!
131//! fn main() {
132//! let mut handlebars = Handlebars::new();
133//! let source = "hello {{world}}";
134//!
135//! let mut data = BTreeMap::new();
136//! data.insert("world".to_string(), "世界!".to_string());
137//! assert_eq!(handlebars.template_render(source, &data).unwrap(),"hello 世界!".to_owned());
138//! }
139//! ```
140//!
141//! ### Rendering Something
142//!
041b39d2 143//! Since handlebars is originally based on JavaScript type system. It supports dynamic features like duck-typing, truthy/falsey values. But for a static language like Rust, this is a little difficult. As a solution, we are using the `serde_json::value::Value` internally for data rendering.
8bb4bdeb 144//!
041b39d2 145//! That means, if you want to render something, you have to ensure the data type implements the `serde::Serialize` trait. Most rust internal types already have that trait. Use `#derive[Serialize]` for your types to generate default implementation.
8bb4bdeb
XL
146//!
147//! You can use default `render` function to render a template into `String`. From 0.9, there's `renderw` to render text into anything of `std::io::Write`.
148//!
149//! ```ignore
8bb4bdeb
XL
150//! use std::collections::BTreeMap;
151//!
152//! use handlebars::Handlebars;
153//!
041b39d2 154//! #[derive(Serialize)]
8bb4bdeb
XL
155//! struct Person {
156//! name: String,
157//! age: i16,
158//! }
159//!
8bb4bdeb
XL
160//! fn main() {
161//! let source = "Hello, {{name}}";
162//!
163//! let mut handlebars = Handlebars::new();
164//! assert!(handlebars.register_template_string("hello", source).is_ok());
165//!
166//!
167//! let data = Person {
168//! name: "Ning Sun".to_string(),
169//! age: 27
170//! };
171//! assert_eq!(handlebars.render("hello", &data).unwrap(), "Hello, Ning Sun".to_owned());
172//! }
173//! ```
174//!
175//! Or if you don't need the template to be cached or referenced by other ones, you can
176//! simply render it without registering.
177//!
178//! ```ignore
179//! fn main() {
180//! let source = "Hello, {{name}}";
181//!
182//! let mut handlebars = Handlebars::new();
183//!
184//! let data = Person {
185//! name: "Ning Sun".to_string(),
186//! age: 27
187//! };
188//! assert_eq!(handlebars.template_render("Hello, {{name}}", &data).unwrap(),
189//! "Hello, Ning Sun".to_owned());
190//! }
191//! ```
192//!
193//! #### Escaping
194//!
195//! As per the handlebars spec, output using `{{expression}}` is escaped by default (to be precise, the characters `&"<>` are replaced by their respective html / xml entities). However, since the use cases of a rust template engine are probably a bit more diverse than those of a JavaScript one, this implementation allows the user to supply a custom escape function to be used instead. For more information see the `EscapeFn` type and `Handlebars::register_escape_fn()` method.
196//!
197//! ### Custom Helper
198//!
199//! 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.
200//!
201//! ```
202//! use std::io::Write;
203//! use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context, JsonRender};
204//!
205//! // implement by a structure impls HelperDef
206//! #[derive(Clone, Copy)]
207//! struct SimpleHelper;
208//!
209//! impl HelperDef for SimpleHelper {
210//! fn call(&self, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
211//! let param = h.param(0).unwrap();
212//!
213//! try!(rc.writer.write("1st helper: ".as_bytes()));
214//! try!(rc.writer.write(param.value().render().into_bytes().as_ref()));
215//! Ok(())
216//! }
217//! }
218//!
219//! // implement via bare function
220//! fn another_simple_helper (h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
221//! let param = h.param(0).unwrap();
222//!
223//! try!(rc.writer.write("2nd helper: ".as_bytes()));
224//! try!(rc.writer.write(param.value().render().into_bytes().as_ref()));
225//! Ok(())
226//! }
227//!
228//!
229//! fn main() {
230//! let mut handlebars = Handlebars::new();
231//! handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
232//! handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
233//! // via closure
234//! handlebars.register_helper("closure-helper",
235//! Box::new(|h: &Helper, r: &Handlebars, rc: &mut RenderContext| -> Result<(), RenderError>{
236//! let param = h.param(0).unwrap();
237//!
238//! try!(rc.writer.write("3rd helper: ".as_bytes()));
239//! try!(rc.writer.write(param.value().render().into_bytes().as_ref()));
240//! Ok(())
241//! }));
242//!
243//! let tpl = "{{simple-helper 1}}\n{{another-simple-helper 2}}\n{{closure-helper 3}}";
244//! assert_eq!(handlebars.template_render(tpl, &()).unwrap(),
245//! "1st helper: 1\n2nd helper: 2\n3rd helper: 3".to_owned());
246//! }
247//! ```
248//! Data available to helper can be found in [Helper](struct.Helper.html). And there are more
249//! examples in [HelperDef](trait.HelperDef.html) page.
250//!
251//! You can learn more about helpers by looking into source code of built-in helpers.
252//!
253//! #### Built-in Helpers
254//!
255//! * `{{#raw}} ... {{/raw}}` escape handlebars expression within the block
256//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
257//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
258//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebar-rust doesn't support mustach iteration syntax so use this instead.
259//! * `{{#with ...}} ... {{/with}}` change current context. Similar to {{#each}}, used for replace corresponding mustach syntax.
260//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
261//! * `{{> ...}}` include template with name
262//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
263//!
264//! ### Template inheritance
265//!
266//! Handlebarsjs partial system is fully supported in this implementation.
267//! Check [example](https://github.com/sunng87/handlebars-rust/blob/master/examples/partials.rs#L49) for detail.
268//!
269//!
270
271#![allow(dead_code)]
272#![recursion_limit = "200"]
273
274#[macro_use]
275extern crate log;
276#[macro_use]
277extern crate quick_error;
278#[macro_use]
279extern crate pest;
280#[macro_use]
281extern crate lazy_static;
282
8bb4bdeb
XL
283#[cfg(test)]
284#[macro_use]
285extern crate maplit;
041b39d2
XL
286#[cfg(test)]
287#[macro_use]
288extern crate serde_derive;
8bb4bdeb 289
041b39d2
XL
290extern crate regex;
291extern crate serde;
292#[allow(unused_imports)]
293#[macro_use]
8bb4bdeb
XL
294extern crate serde_json;
295
296pub use self::template::Template;
297pub use self::error::{TemplateError, TemplateFileError, TemplateRenderError};
298pub use self::registry::{EscapeFn, no_escape, html_escape, Registry as Handlebars};
299pub use self::render::{Renderable, Evaluable, RenderError, RenderContext, Helper, ContextJson,
300 Directive as Decorator};
301pub use self::helpers::HelperDef;
302pub use self::directives::DirectiveDef as DecoratorDef;
303pub use self::context::{Context, JsonRender, to_json};
304
305mod grammar;
306mod template;
307mod error;
308mod registry;
309mod render;
310mod helpers;
311mod context;
312mod support;
313mod directives;
314#[cfg(not(feature="partial_legacy"))]
315mod partial;