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
//! Templates in your Rust code.
//!
//! This library allows you to write HTML templates, using the power of macros,
//! mixed in with your Rust code. This allows you to use normal Rust code for
//! the logic, and embed template code along side it.
//!
//! **Contents:**
//!
//! 1. [Basics](#basics)
//! 1. [Rendering](#rendering)
//! 1. [Escaping](#escaping)
//! 1. [Returning Errors](#returning-errors)
//! 1. [Whitespace](#whitespace)
//!
//! # Basics
//!
//! The most basic template is this:
//!
//! ```
//! use qtpl::{tplfn, tpl};
//!
//! #[tplfn]
//! fn hello(name: &str) {
//!     tpl! {Hello, <strong>{name}</strong>!}
//! }
//! ```
//!
//! There are a few things going on here -- first, we're adding the `#[tlpfn]`
//! attribute to our template function. This makes it possible to use this
//! function as a template. Second, we're using the `tpl!` macro inside the body
//! and embedding some textual content. Lastly, we're putting the variable
//! `name` inside another block.
//!
//! # Rendering
//!
//! Fundamentally rendering happens to something that implements
//! `std::io::Write`. This means you could potentially write directly to a
//! socket. Usually you'll buffer the content entirely, or use a buffered
//! writer at the least.
//!
//! ## To a `File`
//! ```
//! # use qtpl::{tplfn, tpl};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, <strong>{name}</strong>!}
//! # }
//! #
//! let mut file = std::fs::File::create("/tmp/qtpl.txt")?;
//! hello(&mut file, "world")?;
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! ## To a `Vec<u8>`
//! ```
//! # use qtpl::{tplfn, tpl};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, <strong>{name}</strong>!}
//! # }
//! #
//! let mut out = vec![];
//! hello(&mut out, "world")?;
//! assert_eq!(out, b"Hello, <strong>world</strong>!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! ## To a `String` for Testing
//! Purely as a convinience, a `render_string!` macro is provided which
//! panics on errors, and returns a `String`. Remember, this is useful for
//! testing and documentation, but you shouldn't be using this in production
//! code, because it involves unnecessary copies and conversions.
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, <strong>{name}</strong>!}
//! # }
//! #
//! assert_eq!(render_string!(hello("world")), "Hello, <strong>world</strong>!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! # Escaping
//!
//! The default escaping used by the library is geared towards HTML. Using the
//! same example above:
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, <strong>{name}</strong>!}
//! # }
//! #
//! assert_eq!(render_string!(hello("<world>")), "Hello, <strong>&lt;world&gt;</strong>!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! # Returning Errors
//!
//! The `#[tplfn]` attribute will add a return type of `std::io::Result<()>`,
//! but only if one isn't present. You can customize the return type and take
//! control of the errors being returned. The only requirement is that
//! `std::io::Error` types can be converted into that error using the usual
//! process.
//!
//! A contrived but real example:
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! type BoxError = Box<dyn std::error::Error + Send + Sync>;
//!
//! #[tplfn]
//! fn answer(a: &str) -> Result<(), BoxError> {
//!     let a: i8 = a.parse()?;
//!     tpl! {{&a.to_string()}}
//! }
//!
//! assert_eq!(render_string!(answer("42")), "42");
//!
//! let mut w = vec![];
//! match answer(&mut w, "not a number") {
//!     Result::Err(err) => {
//!         assert_eq!(format!("{}", err), "invalid digit found in string");
//!     },
//!     _ => panic!("expected an error"),
//! };
//! ```
//!
//! # Whitespace
//!
//! The library takes an opinionated stance on whitespace. The rules are as
//! follows:
//!
//! * Whitespace at the begining of the template is stripped.
//! * Whitespace at the end of the template is stripped.
//! * Whitespace around a whitelisted set of elements, where it should be
//!   insignificant is stripped.
//! * All whitespace, including newlines is collapsed into a single space.
//! * Rules only apply to template text, contents of varibles are not modified.
//!
//! This example shows all the rules in action, including how certain tags
//! behave differently, and how multiple spaces including newlines are
//! collapsed:
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! #[tplfn]
//! fn home() {
//!     tpl! {
//!         <div>
//!             <a>Go <i class="icon">   </i></a>
//!             <a>{"   "}</a>
//!         </div>
//!     }
//! }
//!
//! assert_eq!(
//!     render_string!(home()),
//!     concat!(
//!         "<div>",
//!         r#"<a>Go <i class="icon"> </i></a>"#,
//!         " ",
//!         "<a>   </a>",
//!         "</div>",
//!     ),
//! );
//! ```
//!
//! Note how the space inside and around the `<i>` tag is preserved, but the
//! space around the `<div>` tag is stripped. Also notice how the multiple
//! spaces inside the `<i>` are collapsed into a single space.

#![doc(html_favicon_url = "https://raw.githubusercontent.com/daaku/qtpl/master/assets/favicon.png")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/daaku/qtpl/master/assets/logo.png")]

pub use qtpl_macros::{render, render_string, tpl, tplfn};

// This is used internally for escaping in macro output.
#[doc(hidden)]
pub use v_htmlescape::escape;