1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//! Dynamic templating engine support for Rocket.
//!
//! This crate adds support for dynamic template rendering to Rocket. It
//! automatically discovers templates, provides a `Responder` to render
//! templates, and automatically reloads templates when compiled in debug mode.
//! At present, it supports [Handlebars] and [Tera].
//!
//! # Usage
//!
//!   1. Depend on `rocket_dyn_templates`. Enable the feature(s) corresponding
//!      to your templating engine(s) of choice:
//!
//!      ```toml
//!      [dependencies.rocket_dyn_templates]
//!      version = "0.2.0"
//!      features = ["handlebars", "tera", "minijinja"]
//!      ```
//!
//!   2. Write your templates inside of the [configurable]
//!      `${ROCKET_ROOT}/templates`. The filename _must_ end with an extension
//!      corresponding to an enabled engine. The second-to-last extension should
//!      correspond to the file's type:
//!
//!      | Engine       | Extension | Example                                    |
//!      |--------------|-----------|--------------------------------------------|
//!      | [Tera]       | `.tera`   | `${ROCKET_ROOT}/templates/index.html.tera` |
//!      | [Handlebars] | `.hbs`    | `${ROCKET_ROOT}/templates/index.html.hbs`  |
//!      | [MiniJinja]  | `.j2`     | `${ROCKET_ROOT}/templates/index.html.j2`   |
//!
//!      [configurable]: #configuration
//!      [Tera]: https://docs.rs/crate/tera/1
//!      [Handlebars]: https://docs.rs/crate/handlebars/5
//!      [MiniJinja]: https://docs.rs/minijinja/2
//!
//!   3. Attach `Template::fairing()` and return a [`Template`] from your routes
//!      via [`Template::render()`], supplying the name of the template file
//!      **minus the last two extensions**:
//!
//!      ```rust
//!      # #[macro_use] extern crate rocket;
//!      use rocket_dyn_templates::{Template, context};
//!
//!      #[get("/")]
//!      fn index() -> Template {
//!          Template::render("index", context! { field: "value" })
//!      }
//!
//!      #[launch]
//!      fn rocket() -> _ {
//!          rocket::build().attach(Template::fairing())
//!      }
//!      ```
//!
//! ## Configuration
//!
//! This crate reads one configuration parameter from the configured figment:
//!
//!   * `template_dir` (**default: `templates/`**)
//!
//!      A path to a directory to search for template files in. Relative paths
//!      are considered relative to the configuration file, or there is no file,
//!      the current working directory.
//!
//! For example, to change the default and set `template_dir` to different
//! values based on whether the application was compiled for debug or release
//! from a `Rocket.toml` file (read by the default figment), you might write:
//!
//! ```toml
//! [debug]
//! template_dir = "static/templates"
//!
//! [release]
//! template_dir = "/var/opt/www/templates"
//! ```
//!
//! **Note:** `template_dir` defaults to `templates/`. It _does not_ need to be
//! specified if the default suffices.
//!
//! See the [configuration chapter] of the guide for more information on
//! configuration.
//!
//! [configuration chapter]: https://rocket.rs/v0.5/guide/configuration
//!
//! ## Template Naming and Content-Types
//!
//! Templates are rendered by _name_ via [`Template::render()`], which returns a
//! [`Template`] responder. The _name_ of the template is the path to the
//! template file, relative to `template_dir`, minus at most two extensions.
//!
//! The `Content-Type` of the response is automatically determined by the
//! non-engine extension using [`ContentType::from_extension()`]. If there is no
//! such extension or it is unknown, `text/plain` is used.
//!
//! The following table contains examples:
//!
//! | template path                                 | [`Template::render()`] call       | content-type |
//! |-----------------------------------------------|-----------------------------------|--------------|
//! | {template_dir}/index.html.hbs                 | `render("index")`                 | HTML         |
//! | {template_dir}/index.tera                     | `render("index")`                 | `text/plain` |
//! | {template_dir}/index.hbs                      | `render("index")`                 | `text/plain` |
//! | {template_dir}/dir/index.hbs                  | `render("dir/index")`             | `text/plain` |
//! | {template_dir}/dir/data.json.tera             | `render("dir/data")`              | JSON         |
//! | {template_dir}/data.template.xml.hbs          | `render("data.template")`         | XML          |
//! | {template_dir}/subdir/index.template.html.hbs | `render("subdir/index.template")` | HTML         |
//!
//! The recommended naming scheme is to use two extensions: one for the file
//! type, and one for the template extension. This means that template
//! extensions should look like: `.html.hbs`, `.html.tera`, `.xml.hbs`, and so
//! on.
//!
//! [`ContentType::from_extension()`]: ../rocket/http/struct.ContentType.html#method.from_extension
//!
//! ### Rendering Context
//!
//! In addition to a name, [`Template::render()`] requires a context to use
//! during rendering. The context can be any [`Serialize`] type that serializes
//! to an `Object` (a dictionary) value. The [`context!`] macro can be used to
//! create inline `Serialize`-able context objects.
//!
//! ```rust
//! # #[macro_use] extern crate rocket;
//! use rocket::serde::Serialize;
//! use rocket_dyn_templates::{Template, context};
//!
//! #[get("/")]
//! fn index() -> Template {
//!     // Using the `context! { }` macro.
//!     Template::render("index", context! {
//!         site_name: "Rocket - Home Page",
//!         version: 127,
//!     })
//! }
//!
//! #[get("/")]
//! fn index2() -> Template {
//!     #[derive(Serialize)]
//!     #[serde(crate = "rocket::serde")]
//!     struct IndexContext {
//!         site_name: &'static str,
//!         version: u8
//!     }
//!
//!     // Using an existing `IndexContext`, which implements `Serialize`.
//!     Template::render("index", IndexContext {
//!         site_name: "Rocket - Home Page",
//!         version: 127,
//!     })
//! }
//! ```
//!
//! ### Discovery, Automatic Reloads, and Engine Customization
//!
//! As long as one of [`Template::fairing()`], [`Template::custom()`], or
//! [`Template::try_custom()`] is [attached], any file in the configured
//! `template_dir` ending with a known engine extension (as described in the
//! [usage section](#usage)) can be rendered. The latter two fairings allow
//! customizations such as registering helpers and templates from strings.
//!
//! _**Note:** Templates that are registered directly via [`Template::custom()`],
//! use whatever name provided during that registration; no extensions are
//! automatically removed._
//!
//! In debug mode (without the `--release` flag passed to `cargo`), templates
//! are **automatically reloaded** from disk when changes are made. In release
//! builds, template reloading is disabled to improve performance and cannot be
//! enabled.
//!
//! [attached]: Rocket::attach()
//!
//! ### Metadata and Rendering to `String`
//!
//! The [`Metadata`] request guard allows dynamically querying templating
//! metadata, such as whether a template is known to exist
//! ([`Metadata::contains_template()`]), and to render templates to `String`
//! ([`Metadata::render()`]).

#![doc(html_root_url = "https://api.rocket.rs/v0.5/rocket_dyn_templates")]
#![doc(html_favicon_url = "https://rocket.rs/images/favicon.ico")]
#![doc(html_logo_url = "https://rocket.rs/images/logo-boxed.png")]

#[macro_use] extern crate rocket;

#[doc(inline)]
#[cfg(feature = "tera")]
/// The tera templating engine library, reexported.
pub use tera;

#[doc(inline)]
#[cfg(feature = "handlebars")]
/// The handlebars templating engine library, reexported.
pub use handlebars;

#[doc(inline)]
#[cfg(feature = "minijinja")]
/// The minijinja templating engine library, reexported.
pub use minijinja;

#[doc(hidden)]
pub use rocket::serde;

mod engine;
mod fairing;
mod context;
mod metadata;
mod template;

pub use engine::Engines;
pub use metadata::Metadata;
pub use template::Template;