nate/lib.rs
1// Copyright (c) 2021-2022 René Kijewski <crates.io@k6i.de>
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// --- LLVM Exceptions to the Apache 2.0 License ----
16//
17// As an exception, if, as a result of your compiling your source code, portions
18// of this Software are embedded into an Object form of such source code, you
19// may redistribute such embedded portions in such Object form without complying
20// with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
21//
22// In addition, if you combine or link compiled forms of this Software with
23// software that is licensed under the GPLv2 ("Combined Software") and if a
24// court of competent jurisdiction determines that the patent provision (Section
25// 3), the indemnity provision (Section 9) or other Section of the License
26// conflicts with the conditions of the GPLv2, you may retroactively and
27// prospectively choose to deem waived or otherwise exclude such Section(s) of
28// the License, but only in their entirety and only with respect to the Combined
29// Software.
30
31#![cfg_attr(docsrs, feature(doc_cfg))]
32#![forbid(unsafe_code)]
33#![allow(unused_attributes)]
34#![warn(absolute_paths_not_starting_with_crate)]
35#![warn(elided_lifetimes_in_paths)]
36#![warn(explicit_outlives_requirements)]
37#![warn(meta_variable_misuse)]
38#![warn(missing_copy_implementations)]
39#![warn(missing_debug_implementations)]
40#![warn(missing_docs)]
41#![warn(non_ascii_idents)]
42#![warn(noop_method_call)]
43#![warn(single_use_lifetimes)]
44#![warn(trivial_casts)]
45#![warn(unreachable_pub)]
46#![warn(unused_crate_dependencies)]
47#![warn(unused_extern_crates)]
48#![warn(unused_lifetimes)]
49#![warn(unused_results)]
50
51//! ## NaTE — Not a Template Engine
52//!
53//! [](https://github.com/Kijewski/nate/actions/workflows/ci.yml)
54//! [](https://crates.io/crates/nate)
55//! 
56//! [](https://github.com/Kijewski/nate/blob/v0.2.2/LICENSE "Apache-2.0 WITH LLVM-exception")
57//!
58//! This is *not* a template engine, but sugar to implicitly call `write!(…)` like in PHP.
59//! The only difference is that the output gets XML escaped automatically unless opted-out explicitly.
60//!
61//! Unlike other template engines like
62//! [Askama](https://crates.io/crates/askama), [Handlebars](https://crates.io/crates/handlebars),
63//! [Liquid](https://github.com/cobalt-org/liquid-rust), [Tera](https://crates.io/crates/tera), or
64//! [Tide](https://crates.io/crates/tide), you don't have to learn a new language.
65//! If you know Rust and HTML, you already know how to implement templates with NaTE!
66//!
67//! E.g.
68//!
69//! * templates/greeting.html:
70//!
71//! ```xml
72//! <h1>Hello, {{user}}!</h1>
73//! ```
74//!
75//! The path is relative to the cargo manifest dir (where you find Cargo.toml) of the project.
76//!
77//! * src/main.rs:
78//!
79//! ```ignore
80//! use std::fmt::Write;
81//! use nate::Nate;
82//!
83//! #[derive(Nate)]
84//! #[template(path = "templates/greeting.html")]
85//! struct Greetings<'a> {
86//! user: &'a str,
87//! }
88//!
89//! let mut output = String::new();
90//! let tmpl = Greetings { user: "<World>" };
91//! write!(output, "{}", tmpl).unwrap();
92//! println!("{}", output);
93//! ```
94//!
95//! * Output:
96//!
97//! ```html
98//! <h1>Hello, <World>!</h1>
99//! ```
100//!
101//! No new traits are needed, instead `#[derive(Nate)]` primarily works by implementing [`fmt::Display`](core::fmt::Display).
102//! This also makes nesting of NaTE templates possible.
103//!
104//! A more complex example would be:
105//!
106//! * src/main.rs:
107//!
108//! ```ignore
109//! use std::fmt::Write;
110//! use nate::Nate;
111//!
112//! #[derive(Nate)]
113//! #[template(path = "templates/99-bottles.html")]
114//! struct Template {
115//! limit: usize,
116//! }
117//!
118//! #[test]
119//! fn ninetynine_bottles_of_beer() {
120//! print!("{}", Template { limit: 99 });
121//! }
122//! ```
123//!
124//! * templates/99-bottles.txt:
125//!
126//! ```jinja
127//! {%-
128//! for i in (1..=self.limit).rev() {
129//! if i == 1 {
130//! -%}
131//! 1 bottle of beer on the wall.
132//! 1 bottle of beer.
133//! Take one down, pass it around.
134//! {%-
135//! } else {
136//! -%}
137//! {{i}} bottles of beer on the wall.
138//! {{i}} bottles of beer.
139//! Take one down, pass it around.
140//!
141//! {%
142//! }
143//! }
144//! -%}
145//! ```
146//!
147//! Inside of a `{% code block %}` you can write any and all rust code.
148//!
149//! Values in `{{ value blocks }}` are printed XML escaped.
150//!
151//! Values in `{{{ raw blocks }}}` are printed verbatim.
152//!
153//! For values in `{{{{ debug blocks }}}}` their debug message is printed as in `"{:?}"`.
154//!
155//! For values in `{{{{{ verbose blocks }}}}}` their debug message is printed verbose as in `"{:#?}"`.
156//!
157//! With `{< include >}` blocks you can include a template file.
158//! It then behaves like it was copy-pasted into the current file.
159//! If the path starts with "." or "..", the file is searched relative to the current file.
160//! Otherwise it is search in the project root.
161//!
162//! Using hyphens `-` at the start/end of a block, whitespaces before/after the block are trimmed.
163//!
164//! Data blocks `{{…}}` to `{{{{{…}}}}}` and includes `{<…>}` must not be empty.
165//! Code `{%…%}` and comment `{#…#}` blocks may be empty.
166//!
167//! Blocks don't need to be closed at the end of the file.
168//!
169//! To debug any errors you can add an argument as in `#[template(generated = "some/path/generated.rs")]`.
170//! The generated code is stored in there even if there were parsing errors in the Rust code.
171//! The path is relative to the project root (where your Cargo.toml lives).
172//!
173//! ## Feature flags
174//!
175//! * `std` <sup>\[enabled by default\]</sup> — enable features found in [`std`] crate, e.g. printing the value of a [`MutexGuard`](std::sync::MutexGuard)
176//!
177//! * `alloc` <sup>\[enabled by default, enabled by `std`\]</sup> — enable features found in the [`alloc`] crate, e.g. [`io::Write`](std::io::Write)
178//!
179
180#[cfg(doc)]
181extern crate alloc;
182#[cfg(doc)]
183extern crate std;
184
185#[doc(hidden)]
186pub mod details;
187mod escape;
188mod fast_float;
189mod fast_integer;
190mod raw;
191
192pub use ::nate_derive::{addr, Nate};
193
194pub use crate::details::{EscapeWrapper, RenderInto, WriteAny};
195pub use crate::fast_float::FloatMarker;
196pub use crate::fast_integer::IntMarker;
197pub use crate::raw::RawMarker;