This template crate uses and defines a DisplayAs
trait, which
allows a type to be displayed in a particular format.
Overview
This crate defines three things that you need be aware of in order
to use it: the Format
trait, which defines a markup language or
other format, the DisplayAs
trait which is implemented for any
type that can be converted into some Format
, and finally the
template language and macros which allow you to conveniently
implement DisplayAs
for your own types. I will describe each of
these concepts in order. (FIXME I should also have a
quick-start...)
Format
There are a number of predefined Formats (and I can easily add
more if there are user requests), so the focus here will be on
using these Formats, rather than on defining your own (which also
isn't too hard). A format is a zero-size type that has a rule for
escaping strings and an associated MIME type. The builtin formats
include HTML
, LaTeX
, and Math
(which is math-mode LaTeX).
DisplayAs<F>
The DisplayAs<F: Format>
trait is entirely analogous to the Display
trait
in the standard library, except that it is parametrized by a
Format
so you can have different representations for the same
type in different formats. This also makes it harder to
accidentally include the wrong representation in your output.
Most of the primitive types already have DisplayAs
implemented
for the included Formats. If you encounter a type that you wish
had DisplayAs
implemented for a given format, just let me know.
You can manually implement DisplayAs
for any of your own types
(it's not worse than implementing Display
) but that isn't how
you are intended to do things (except perhaps in very simple
cases, like a wrapper around an integer). Instead you will want
to use a template to implement DisplayAs
for your own types.
Templates!
There are two template macros that you can use. If you just want
to get a string out of one or more DisplayAs
objects, you will
use something like display_as_string!("hello world" value)
. If
you want to implement DisplayAs
, you will use the attribute
with_template
. In these examples I will use
display_as_string!
because that makes it easy to write testable
documentation. But in practice you will most likely primarily use
the with_template
attribute.
String literals
The first thing you can include in a template is a string literal, which is treated literally.
use display_as::{HTML, display_as_string};
assert_eq!(&display_as_string!(HTML, "Treat this literally <" ),
"Treat this literally <");
Expressions
String literals are essential to representing some other format.
To include your data in the output, you can include any expression
that yields a type with DisplayAs<F>
where F
is your format.
Each expression is delimited by string literals (or the other
options below). Note that since an expression is
use display_as::{HTML, display_as_string};
let s = "This is not a literal: <";
assert_eq!(&display_as_string!(HTML, s ),
"This is not a literal: <");
Blocks and conditionals
You can use braces to enclose any template expression. Any rust code before the braces is treated as literal rust. This enables you to write conditionals, match expressions, and loops.
use display_as::{HTML, display_as_string};
assert_eq!(&display_as_string!(HTML,
for i in 1..4 {
"Counting " i "...\n"
}
"Blast off!"),
"Counting 1...\nCounting 2...\nCounting 3...\nBlast off!");
Semicolons
You may also play any rust statements you wish, if you end them with a semicolon. This enables you to define local variables.
use display_as::{HTML, display_as_string};
assert_eq!(&display_as_string!(HTML, "I am counting " let count = 5;
count " and again " count ),
"I am counting 5 and again 5");
Embedding a different format
You can also embed in one format a representation from another type. This can be helpful, for instance, if you want to use MathJax to handle LaTeX math embedded in an HTML file.
use display_as::{HTML, Math, display_as_string};
assert_eq!(&display_as_string!(HTML, "The number $" 1.2e12 as Math "$"),
r"The number $1.2\times10^{12}$");
Saving a portion of a template for reuse
You can also save a template expression using a let statement, provided the template expression is enclosed in braces. This allows you to achieve goals similar to the base templates in Jinja2. (Once we have an include feature... Example to come in the future.)
use display_as::{HTML, display_as_string};
assert_eq!(&display_as_string!(HTML,
let x = 1;
let announce = { "number " x };
"The " announce " is silly " announce),
"The number 1 is silly number 1");
Differences when putting a template in a file
You will most likely always put largish templates in a separate file. This makes editing your template simpler and keeps things in general easier. The template language for templates held in a distinct file has one differnce from those shown above: the file always begins and ends with string literals, but their initial and final quotes respectively are omitted. Furthermore, the first and last string literals must be "raw" literals with a number of # signs equal to the maximum used in the template. I suggest using an equal number of # signs for all string literals in a given template. Thus a template might look like:
"## self.title r##"
You can see that the quotes appear "inside out." This is intentional, so that for most formats the quotes will appear to enclose the rust code rather than everything else, and as a result editors will hopefully be able to do the "right thing" for the template format (e.g. HTML in this case).