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
//! Templates in your Rust code. //! //! This library allows you to write templates, using 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. //! //! **Caveat**: This library is going to be mostly useful for HTML, primarily //! because it collapses whitespace (whitespace, including newlines are //! collapsed into a single space). It also defaults to HTML escaping, though //! that can be altered by using directives. //! //! # Basics //! //! The most basic template is this: //! //! ``` //! use qtpl::{tplfn, tpl}; //! //! #[tplfn] //! fn hello(name: &str) { //! tpl! {Hello, {name}!} //! } //! ``` //! //! 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 socket //! at the least. //! //! ## To a `File` //! ``` //! # use qtpl::{tplfn, tpl}; //! # //! # #[tplfn] //! # fn hello(name: &str) { //! # tpl! {Hello, {name}!} //! # } //! # //! 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, {name}!} //! # } //! # //! let mut out = vec![]; //! hello(&mut out, "world")?; //! assert_eq!(out, b"Hello, world!"); //! # //! # 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, {name}!} //! # } //! # //! assert_eq!(render_string!(hello("world")), "Hello, world!"); //! # //! # 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, {name}!} //! # } //! # //! assert_eq!(render_string!(hello("<world>")), "Hello, <world>!"); //! # //! # Ok::<(), std::io::Error>(()) //! ``` pub use qtpl_macros::{child, render_string, tpl, tplfn}; use std::io::{Result, Write}; pub use v_htmlescape::escape; pub trait Render { fn render(self, destination: &mut dyn Write) -> Result<()>; } impl<F> Render for F where F: FnOnce(&mut dyn Write) -> Result<()>, { fn render(self, destination: &mut dyn Write) -> Result<()> { self(destination) } }