After fiddling around with zero-allocation solutions, I concluded that all non-allocating approaches are too annoying to work with in realistic code. Using closures leads to yak-shaving with lifetimes; and because Iron needs to take ownership of the response body we often end up cloning the input data anyway. Removing this constraint has let me simplify the entire system, removing a net 300 lines from the library. The `html!` macro no longer takes a writer, and instead returns a `PreEscaped<String>`. This means that the result of an `html!` can be spliced directly into another `html!`, removing the need for the `impl Template` rigmarole. To rub it in, benchmarks show the new code is in fact *faster* than it was before. How lovely.
127 lines
3.1 KiB
Rust
127 lines
3.1 KiB
Rust
#![feature(conservative_impl_trait, plugin)]
|
|
#![plugin(maud_macros)]
|
|
|
|
extern crate maud;
|
|
|
|
#[test]
|
|
fn if_expr() {
|
|
for (number, &name) in (1..4).zip(["one", "two", "three"].iter()) {
|
|
let s = html! {
|
|
@if number == 1 {
|
|
"one"
|
|
} @else if number == 2 {
|
|
"two"
|
|
} @else if number == 3 {
|
|
"three"
|
|
} @else {
|
|
"oh noes"
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, name);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn if_let() {
|
|
for &(input, output) in [(Some("yay"), "yay"), (None, "oh noes")].iter() {
|
|
let s = html! {
|
|
@if let Some(value) = input {
|
|
(value)
|
|
} @else {
|
|
"oh noes"
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, output);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn for_expr() {
|
|
let ponies = ["Apple Bloom", "Scootaloo", "Sweetie Belle"];
|
|
let s = html! {
|
|
ul @for pony in &ponies {
|
|
li (pony)
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, concat!(
|
|
"<ul>",
|
|
"<li>Apple Bloom</li>",
|
|
"<li>Scootaloo</li>",
|
|
"<li>Sweetie Belle</li>",
|
|
"</ul>"));
|
|
}
|
|
|
|
#[test]
|
|
fn match_expr() {
|
|
for &(input, output) in [(Some("yay"), "<div>yay</div>"), (None, "oh noes")].iter() {
|
|
let s = html! {
|
|
@match input {
|
|
Some(value) => {
|
|
div (value)
|
|
},
|
|
None => {
|
|
"oh noes"
|
|
},
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, output);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn match_expr_without_delims() {
|
|
for &(input, output) in [(Some("yay"), "yay"), (None, "<span>oh noes</span>")].iter() {
|
|
let s = html! {
|
|
@match input {
|
|
Some(value) => (value),
|
|
None => span "oh noes",
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, output);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn match_expr_with_guards() {
|
|
for &(input, output) in [(Some(1), "one"), (None, "none"), (Some(2), "2")].iter() {
|
|
let s = html! {
|
|
@match input {
|
|
Some(value) if value == 1 => "one",
|
|
Some(value) => (value),
|
|
None => "none",
|
|
}
|
|
}.into_string();
|
|
assert_eq!(s, output);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn match_in_attribute() {
|
|
for &(input, output) in [(1, "<span class=\"one\">1</span>"), (2, "<span class=\"two\">2</span>"), (3, "<span class=\"many\">3</span>")].iter() {
|
|
let s = html! {
|
|
span class=@match input {
|
|
1 => "one",
|
|
2 => "two",
|
|
_ => "many",
|
|
} { (input) }
|
|
}.into_string();
|
|
assert_eq!(s, output);
|
|
}
|
|
}
|
|
|
|
fn assert_cute<'a>(name: &'a str) -> impl FnOnce(&mut String) + 'a {
|
|
move |s: &mut String| s.push_str(&html! {
|
|
p {
|
|
(name) " is the cutest"
|
|
}
|
|
}.into_string())
|
|
}
|
|
|
|
#[test]
|
|
fn call() {
|
|
let s = html! {
|
|
@call (assert_cute("Pinkie Pie"))
|
|
@call (assert_cute("Rarity"))
|
|
}.into_string();
|
|
assert_eq!(s, "<p>Pinkie Pie is the cutest</p><p>Rarity is the cutest</p>");
|
|
}
|