]> git.proxmox.com Git - rustc.git/blame - vendor/handlebars/src/lib.rs
New upstream version 1.47.0~beta.2+dfsg1
[rustc.git] / vendor / handlebars / src / lib.rs
CommitLineData
3dfed10e 1#![doc(html_root_url = "https://docs.rs/handlebars/3.4.0")]
8bb4bdeb
XL
2//! # Handlebars
3//!
4//! [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).
5//!
6//! And this is handlebars Rust implementation, designed for general purpose text generation.
7//!
8//! ## Quick Start
9//!
10//! ```
11//! use std::collections::BTreeMap;
12//! use handlebars::Handlebars;
13//!
14//! fn main() {
15//! // create the handlebars registry
16//! let mut handlebars = Handlebars::new();
17//!
18//! // register the template. The template string will be verified and compiled.
19//! let source = "hello {{world}}";
20//! assert!(handlebars.register_template_string("t1", source).is_ok());
21//!
22//! // Prepare some data.
23//! //
041b39d2 24//! // The data type should implements `serde::Serialize`
8bb4bdeb
XL
25//! let mut data = BTreeMap::new();
26//! data.insert("world".to_string(), "世界!".to_string());
27//! assert_eq!(handlebars.render("t1", &data).unwrap(), "hello 世界!");
28//! }
29//! ```
30//!
31//! In this example, we created a template registry and registered a template named `t1`.
32//! Then we rendered a `BTreeMap` with an entry of key `world`, the result is just what
33//! we expected.
34//!
35//! I recommend you to walk through handlebars.js' [intro page](http://handlebarsjs.com)
36//! if you are not quite familiar with the template language itself.
37//!
f9f354fc 38//! ## Features
8bb4bdeb
XL
39//!
40//! Handlebars is a real-world templating system that you can use to build
41//! your application without pain.
42//!
f9f354fc 43//! ### Isolation of Rust and HTML
8bb4bdeb
XL
44//!
45//! This library doesn't attempt to use some macro magic to allow you to
f9f354fc 46//! write your template within your rust code. I admit that it's fun to do
3dfed10e 47//! that but it doesn't fit real-world use cases.
8bb4bdeb 48//!
3dfed10e 49//! ### Limited but essential control structures built-in
8bb4bdeb 50//!
3dfed10e
XL
51//! Only essential control directives `if` and `each` are built-in. This
52//! prevents you from putting too much application logic into your template.
8bb4bdeb 53//!
f9f354fc 54//! ### Extensible helper system
8bb4bdeb
XL
55//!
56//! You can write your own helper with Rust! It can be a block helper or
3dfed10e 57//! inline helper. Put your logic into the helper and don't repeat
8bb4bdeb
XL
58//! yourself.
59//!
f9f354fc
XL
60//! The built-in helpers like `if` and `each` were written with these
61//! helper APIs and the APIs are fully available to developers.
62//!
63//! ### Template inheritance
8bb4bdeb
XL
64//!
65//! Every time I look into a templating system, I will investigate its
83c7162d
XL
66//! support for [template inheritance][t].
67//!
68//! [t]: https://docs.djangoproject.com/en/1.9/ref/templates/language/#template-inheritance
8bb4bdeb 69//!
3dfed10e
XL
70//! Template include is not sufficient for template reuse. In most cases
71//! you will need a skeleton of page as parent (header, footer, etc.), and
72//! embed your page into this parent.
8bb4bdeb 73//!
3dfed10e
XL
74//! You can find a real example of template inheritance in
75//! `examples/partials.rs` and templates used by this file.
8bb4bdeb 76//!
f9f354fc 77//! ### Strict mode
83c7162d
XL
78//!
79//! Handlebars, the language designed to work with JavaScript, has no
3dfed10e
XL
80//! strict restriction on accessing nonexistent fields or indexes. It
81//! generates empty strings for such cases. However, in Rust we want to be
82//! a little stricter sometimes.
83c7162d 83//!
9fa01778 84//! By enabling `strict_mode` on handlebars:
83c7162d
XL
85//!
86//! ```
87//! # use handlebars::Handlebars;
88//! # let mut handlebars = Handlebars::new();
89//! handlebars.set_strict_mode(true);
90//! ```
91//!
3dfed10e 92//! You will get a `RenderError` when accessing fields that do not exist.
83c7162d 93//!
f9f354fc 94//! ## Limitations
8bb4bdeb 95//!
f9f354fc 96//! ### Compatibility with original JavaScript version
8bb4bdeb 97//!
3dfed10e 98//! This implementation is **not fully compatible** with the original JavaScript version.
8bb4bdeb 99//!
3dfed10e
XL
100//! First of all, mustache blocks are not supported. I suggest you to use `#if` and `#each` for
101//! the same functionality.
8bb4bdeb
XL
102//!
103//! There are some other minor features missing:
104//!
105//! * Chained else [#12](https://github.com/sunng87/handlebars-rust/issues/12)
106//!
3dfed10e 107//! Feel free to file an issue on [github](https://github.com/sunng87/handlebars-rust/issues) if
8bb4bdeb
XL
108//! you find missing features.
109//!
f9f354fc 110//! ### Types
8bb4bdeb
XL
111//!
112//! As a static typed language, it's a little verbose to use handlebars.
041b39d2 113//! Handlebars templating language is designed against JSON data type. In rust,
3dfed10e
XL
114//! we will convert user's structs, vectors or maps into Serde-Json's `Value` type
115//! in order to use in templates. You have to make sure your data implements the
f9f354fc 116//! `Serialize` trait from the [Serde](https://serde.rs) project.
8bb4bdeb
XL
117//!
118//! ## Usage
119//!
120//! ### Template Creation and Registration
121//!
3dfed10e 122//! Templates are created from `String`s and registered to `Handlebars` with a name.
8bb4bdeb
XL
123//!
124//! ```
9fa01778 125//! # extern crate handlebars;
8bb4bdeb
XL
126//!
127//! use handlebars::Handlebars;
128//!
9fa01778 129//! # fn main() {
8bb4bdeb
XL
130//! let mut handlebars = Handlebars::new();
131//! let source = "hello {{world}}";
132//!
133//! assert!(handlebars.register_template_string("t1", source).is_ok())
9fa01778 134//! # }
8bb4bdeb
XL
135//! ```
136//!
9fa01778
XL
137//! On registration, the template is parsed, compiled and cached in the registry. So further
138//! usage will benefit from the one-time work. Also features like include, inheritance
8bb4bdeb
XL
139//! that involves template reference requires you to register those template first with
140//! a name so the registry can find it.
141//!
9fa01778 142//! If you template is small or just to experiment, you can use `render_template` API
8bb4bdeb
XL
143//! without registration.
144//!
145//! ```
9fa01778 146//! # use std::error::Error;
8bb4bdeb
XL
147//! use handlebars::Handlebars;
148//! use std::collections::BTreeMap;
149//!
9fa01778 150//! # fn main() -> Result<(), Box<Error>> {
8bb4bdeb
XL
151//! let mut handlebars = Handlebars::new();
152//! let source = "hello {{world}}";
153//!
154//! let mut data = BTreeMap::new();
155//! data.insert("world".to_string(), "世界!".to_string());
9fa01778
XL
156//! assert_eq!(handlebars.render_template(source, &data)?, "hello 世界!".to_owned());
157//! # Ok(())
158//! # }
8bb4bdeb
XL
159//! ```
160//!
161//! ### Rendering Something
162//!
041b39d2 163//! 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 164//!
041b39d2 165//! 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 166//!
3dfed10e 167//! You can use default `render` function to render a template into `String`. From 0.9, there's `render_to_write` to render text into anything of `std::io::Write`.
8bb4bdeb 168//!
9fa01778
XL
169//! ```
170//! # use std::error::Error;
171//! # #[macro_use]
172//! # extern crate serde_derive;
173//! # extern crate handlebars;
8bb4bdeb
XL
174//!
175//! use handlebars::Handlebars;
176//!
041b39d2 177//! #[derive(Serialize)]
8bb4bdeb
XL
178//! struct Person {
179//! name: String,
180//! age: i16,
181//! }
182//!
9fa01778 183//! # fn main() -> Result<(), Box<Error>> {
8bb4bdeb
XL
184//! let source = "Hello, {{name}}";
185//!
186//! let mut handlebars = Handlebars::new();
187//! assert!(handlebars.register_template_string("hello", source).is_ok());
188//!
189//!
190//! let data = Person {
191//! name: "Ning Sun".to_string(),
192//! age: 27
193//! };
9fa01778
XL
194//! assert_eq!(handlebars.render("hello", &data)?, "Hello, Ning Sun".to_owned());
195//! # Ok(())
196//! # }
197//! #
8bb4bdeb
XL
198//! ```
199//!
200//! Or if you don't need the template to be cached or referenced by other ones, you can
201//! simply render it without registering.
202//!
9fa01778
XL
203//! ```
204//! # use std::error::Error;
205//! # #[macro_use]
206//! # extern crate serde_derive;
207//! # extern crate handlebars;
208//! use handlebars::Handlebars;
209//! # #[derive(Serialize)]
210//! # struct Person {
211//! # name: String,
212//! # age: i16,
213//! # }
214//!
416331ca 215//! # fn main() -> Result<(), Box<dyn Error>> {
8bb4bdeb
XL
216//! let source = "Hello, {{name}}";
217//!
218//! let mut handlebars = Handlebars::new();
219//!
220//! let data = Person {
221//! name: "Ning Sun".to_string(),
222//! age: 27
223//! };
9fa01778 224//! assert_eq!(handlebars.render_template("Hello, {{name}}", &data)?,
8bb4bdeb 225//! "Hello, Ning Sun".to_owned());
9fa01778
XL
226//! # Ok(())
227//! # }
8bb4bdeb
XL
228//! ```
229//!
230//! #### Escaping
231//!
232//! 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.
233//!
234//! ### Custom Helper
235//!
236//! 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.
237//!
238//! ```
239//! use std::io::Write;
9fa01778
XL
240//! # use std::error::Error;
241//! use handlebars::{Handlebars, HelperDef, RenderContext, Helper, Context, JsonRender, HelperResult, Output, RenderError};
8bb4bdeb
XL
242//!
243//! // implement by a structure impls HelperDef
244//! #[derive(Clone, Copy)]
245//! struct SimpleHelper;
246//!
247//! impl HelperDef for SimpleHelper {
416331ca 248//! fn call<'reg: 'rc, 'rc>(&self, h: &Helper, _: &Handlebars, _: &Context, rc: &mut RenderContext, out: &mut dyn Output) -> HelperResult {
8bb4bdeb
XL
249//! let param = h.param(0).unwrap();
250//!
9fa01778
XL
251//! out.write("1st helper: ")?;
252//! out.write(param.value().render().as_ref())?;
8bb4bdeb
XL
253//! Ok(())
254//! }
255//! }
256//!
257//! // implement via bare function
416331ca 258//! fn another_simple_helper (h: &Helper, _: &Handlebars, _: &Context, rc: &mut RenderContext, out: &mut dyn Output) -> HelperResult {
8bb4bdeb
XL
259//! let param = h.param(0).unwrap();
260//!
9fa01778
XL
261//! out.write("2nd helper: ")?;
262//! out.write(param.value().render().as_ref())?;
8bb4bdeb
XL
263//! Ok(())
264//! }
265//!
266//!
416331ca 267//! # fn main() -> Result<(), Box<dyn Error>> {
8bb4bdeb
XL
268//! let mut handlebars = Handlebars::new();
269//! handlebars.register_helper("simple-helper", Box::new(SimpleHelper));
270//! handlebars.register_helper("another-simple-helper", Box::new(another_simple_helper));
271//! // via closure
272//! handlebars.register_helper("closure-helper",
416331ca 273//! Box::new(|h: &Helper, r: &Handlebars, _: &Context, rc: &mut RenderContext, out: &mut dyn Output| -> HelperResult {
9fa01778 274//! let param = h.param(0).ok_or(RenderError::new("param not found"))?;
8bb4bdeb 275//!
9fa01778
XL
276//! out.write("3rd helper: ")?;
277//! out.write(param.value().render().as_ref())?;
8bb4bdeb
XL
278//! Ok(())
279//! }));
280//!
281//! let tpl = "{{simple-helper 1}}\n{{another-simple-helper 2}}\n{{closure-helper 3}}";
9fa01778 282//! assert_eq!(handlebars.render_template(tpl, &())?,
8bb4bdeb 283//! "1st helper: 1\n2nd helper: 2\n3rd helper: 3".to_owned());
9fa01778
XL
284//! # Ok(())
285//! # }
286//!
8bb4bdeb 287//! ```
3dfed10e 288//!
8bb4bdeb
XL
289//! Data available to helper can be found in [Helper](struct.Helper.html). And there are more
290//! examples in [HelperDef](trait.HelperDef.html) page.
291//!
292//! You can learn more about helpers by looking into source code of built-in helpers.
293//!
3dfed10e
XL
294//!
295//! ### Script Helper
296//!
297//! Like our JavaScript counterparts, handlebars allows user to define simple helpers with
298//! a scripting language, [rhai](https://docs.rs/crate/rhai/). This can be enabled by
299//! turning on `script_helper` feature flag.
300//!
301//! A sample script:
302//!
303//! ```handlebars
304//! {{percent 0.34 label="%"}}
305//! ```
306//!
307//! ```rhai
308//! // percent.rhai
309//! // get first parameter from `params` array
310//! let value = params[0];
311//! // get key value pair `label` from `hash` map
312//! let label = hash["label"];
313//!
314//! // compute the final string presentation
315//! (value * 100).to_string() + label
316//! ```
317//!
318//! A runnable [example](https://github.com/sunng87/handlebars-rust/blob/master/examples/script.rs) can be find in the repo.
319//!
8bb4bdeb
XL
320//! #### Built-in Helpers
321//!
416331ca 322//! * `{{{{raw}}}} ... {{{{/raw}}}}` escape handlebars expression within the block
8bb4bdeb
XL
323//! * `{{#if ...}} ... {{else}} ... {{/if}}` if-else block
324//! * `{{#unless ...}} ... {{else}} .. {{/unless}}` if-not-else block
3dfed10e
XL
325//! * `{{#each ...}} ... {{/each}}` iterates over an array or object. Handlebars-rust doesn't support mustache iteration syntax so use this instead.
326//! * `{{#with ...}} ... {{/with}}` change current context. Similar to `{{#each}}`, used for replace corresponding mustache syntax.
8bb4bdeb
XL
327//! * `{{lookup ... ...}}` get value from array by `@index` or `@key`
328//! * `{{> ...}}` include template with name
329//! * `{{log ...}}` log value with rust logger, default level: INFO. Currently you cannot change the level.
9fa01778
XL
330//! * Boolean helpers that can be used in `if` as subexpression, for example `{{#if (gt 2 1)}} ...`:
331//! * `eq`
332//! * `ne`
333//! * `gt`
334//! * `gte`
335//! * `lt`
336//! * `lte`
337//! * `and`
338//! * `or`
339//! * `not`
8bb4bdeb
XL
340//!
341//! ### Template inheritance
342//!
9fa01778
XL
343//! Handlebars.js' partial system is fully supported in this implementation.
344//! Check [example](https://github.com/sunng87/handlebars-rust/blob/master/examples/partials.rs#L49) for details.
8bb4bdeb
XL
345//!
346//!
347
348#![allow(dead_code)]
3dfed10e 349#![warn(rust_2018_idioms)]
8bb4bdeb
XL
350#![recursion_limit = "200"]
351
9fa01778 352#[cfg(not(feature = "no_logging"))]
8bb4bdeb 353#[macro_use]
83c7162d 354extern crate log;
9fa01778 355
83c7162d 356#[cfg(test)]
8bb4bdeb 357#[macro_use]
83c7162d 358extern crate maplit;
8bb4bdeb 359#[macro_use]
83c7162d 360extern crate pest_derive;
8bb4bdeb 361#[macro_use]
83c7162d 362extern crate quick_error;
041b39d2
XL
363#[cfg(test)]
364#[macro_use]
365extern crate serde_derive;
8bb4bdeb 366
041b39d2
XL
367#[allow(unused_imports)]
368#[macro_use]
8bb4bdeb
XL
369extern crate serde_json;
370
f9f354fc
XL
371pub use self::block::{BlockContext, BlockParams};
372pub use self::context::Context;
373pub use self::decorators::DecoratorDef;
ea8adc8c 374pub use self::error::{RenderError, TemplateError, TemplateFileError, TemplateRenderError};
83c7162d 375pub use self::helpers::{HelperDef, HelperResult};
f9f354fc
XL
376pub use self::json::path::Path;
377pub use self::json::value::{to_json, JsonRender, PathAndJson, ScopedJson};
9fa01778
XL
378pub use self::output::Output;
379pub use self::registry::{html_escape, no_escape, EscapeFn, Registry as Handlebars};
f9f354fc 380pub use self::render::{Decorator, Evaluable, Helper, RenderContext, Renderable};
9fa01778 381pub use self::template::Template;
8bb4bdeb 382
9fa01778
XL
383#[doc(hidden)]
384pub use self::serde_json::Value as JsonValue;
385
386#[macro_use]
387mod macros;
f9f354fc 388mod block;
9fa01778 389mod context;
f9f354fc 390mod decorators;
8bb4bdeb 391mod error;
9fa01778
XL
392mod grammar;
393mod helpers;
f9f354fc 394mod json;
9fa01778
XL
395mod output;
396mod partial;
8bb4bdeb
XL
397mod registry;
398mod render;
8bb4bdeb 399mod support;
9fa01778 400pub mod template;
f9f354fc 401mod util;