parent
abbb565412
commit
1badbd9df2
5 changed files with 109 additions and 113 deletions
|
@ -5,9 +5,6 @@
|
||||||
//!
|
//!
|
||||||
//! [book]: http://lfairy.gitbooks.io/maud/content/
|
//! [book]: http://lfairy.gitbooks.io/maud/content/
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
/// Escapes an HTML value.
|
/// Escapes an HTML value.
|
||||||
pub fn escape(s: &str) -> String {
|
pub fn escape(s: &str) -> String {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -16,68 +13,11 @@ pub fn escape(s: &str) -> String {
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block of HTML markup, as returned by the `html!` macro.
|
|
||||||
///
|
|
||||||
/// Use `.to_string()` to convert it to a `String`, or `.render()` to
|
|
||||||
/// write it directly to a handle.
|
|
||||||
pub struct Markup<F> {
|
|
||||||
callback: F,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
|
|
||||||
/// Renders the markup to a `std::io::Write`.
|
|
||||||
pub fn render<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
|
||||||
struct Adaptor<'a, W: ?Sized + 'a> {
|
|
||||||
inner: &'a mut W,
|
|
||||||
error: io::Result<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, W: ?Sized + io::Write> fmt::Write for Adaptor<'a, W> {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
match self.inner.write_all(s.as_bytes()) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(e) => {
|
|
||||||
self.error = Err(e);
|
|
||||||
Err(fmt::Error)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut output = Adaptor { inner: w, error: Ok(()) };
|
|
||||||
match self.render_fmt(&mut output) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(_) => output.error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renders the markup to a `std::fmt::Write`.
|
|
||||||
pub fn render_fmt(&self, w: &mut fmt::Write) -> fmt::Result {
|
|
||||||
(self.callback)(w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> ToString for Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
let mut buf = String::new();
|
|
||||||
self.render_fmt(&mut buf).unwrap();
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal functions used by the `maud_macros` package. You should
|
/// Internal functions used by the `maud_macros` package. You should
|
||||||
/// never need to call these directly.
|
/// never need to call these directly.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod rt {
|
pub mod rt {
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use super::Markup;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn make_markup<F>(f: F) -> Markup<F> where
|
|
||||||
F: Fn(&mut fmt::Write) -> fmt::Result
|
|
||||||
{
|
|
||||||
Markup { callback: f }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Escaper<'a, 'b: 'a> {
|
pub struct Escaper<'a, 'b: 'a> {
|
||||||
pub inner: &'a mut (fmt::Write + 'b),
|
pub inner: &'a mut (fmt::Write + 'b),
|
||||||
|
|
|
@ -36,6 +36,6 @@ fn expand_html_debug<'cx>(cx: &'cx mut ExtCtxt, sp: Span, args: &[TokenTree]) ->
|
||||||
|
|
||||||
#[plugin_registrar]
|
#[plugin_registrar]
|
||||||
pub fn plugin_registrar(reg: &mut Registry) {
|
pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
reg.register_macro("html", expand_html);
|
reg.register_macro("write_html", expand_html);
|
||||||
reg.register_macro("html_debug", expand_html_debug);
|
reg.register_macro("write_html_debug", expand_html_debug);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,16 +43,30 @@ macro_rules! ident {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(cx: &ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> {
|
pub fn parse(cx: &ExtCtxt, input: &[TokenTree], sp: Span) -> P<Expr> {
|
||||||
|
let (write, input) = split_comma(cx, input, sp);
|
||||||
let mut parser = Parser {
|
let mut parser = Parser {
|
||||||
in_attr: false,
|
in_attr: false,
|
||||||
input: input,
|
input: input,
|
||||||
span: sp,
|
span: sp,
|
||||||
render: Renderer::new(cx),
|
render: Renderer::new(cx, write.to_vec()),
|
||||||
};
|
};
|
||||||
parser.markups();
|
parser.markups();
|
||||||
parser.into_render().into_expr()
|
parser.into_render().into_expr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn split_comma<'a>(cx: &ExtCtxt, input: &'a [TokenTree], sp: Span) -> (&'a [TokenTree], &'a [TokenTree]) {
|
||||||
|
fn is_comma(t: &TokenTree) -> bool {
|
||||||
|
match *t {
|
||||||
|
TtToken(_, token::Comma) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match input.iter().position(is_comma) {
|
||||||
|
Some(i) => (&input[..i], &input[1+i..]),
|
||||||
|
None => cx.span_fatal(sp, "expected two arguments to write_html!()"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Parser<'cx, 'i> {
|
struct Parser<'cx, 'i> {
|
||||||
in_attr: bool,
|
in_attr: bool,
|
||||||
input: &'i [TokenTree],
|
input: &'i [TokenTree],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use syntax::ast::{Expr, Ident, Pat, Stmt, TokenTree};
|
use syntax::ast::{Expr, Ident, Pat, Stmt, TokenTree, TtToken};
|
||||||
|
use syntax::codemap::DUMMY_SP;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::ext::build::AstBuilder;
|
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
|
@ -15,17 +15,25 @@ pub enum Escape {
|
||||||
pub struct Renderer<'cx> {
|
pub struct Renderer<'cx> {
|
||||||
pub cx: &'cx ExtCtxt<'cx>,
|
pub cx: &'cx ExtCtxt<'cx>,
|
||||||
w: Ident,
|
w: Ident,
|
||||||
|
r: Ident,
|
||||||
|
loop_label: Vec<TokenTree>,
|
||||||
stmts: Vec<P<Stmt>>,
|
stmts: Vec<P<Stmt>>,
|
||||||
tail: String,
|
tail: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx> Renderer<'cx> {
|
impl<'cx> Renderer<'cx> {
|
||||||
/// Creates a new `Renderer` using the given extension context.
|
/// Creates a new `Renderer` using the given extension context.
|
||||||
pub fn new(cx: &'cx ExtCtxt<'cx>) -> Renderer<'cx> {
|
pub fn new(cx: &'cx ExtCtxt<'cx>, writer_expr: Vec<TokenTree>) -> Renderer<'cx> {
|
||||||
|
let w = token::gensym_ident("__maud_writer");
|
||||||
|
let r = token::gensym_ident("__maud_result");
|
||||||
|
let loop_label = token::gensym_ident("__maud_loop_label");
|
||||||
|
let writer_stmt = quote_stmt!(cx, let $w = &mut $writer_expr).unwrap();
|
||||||
Renderer {
|
Renderer {
|
||||||
cx: cx,
|
cx: cx,
|
||||||
w: Ident::new(token::intern("w")),
|
w: w,
|
||||||
stmts: Vec::new(),
|
r: r,
|
||||||
|
loop_label: vec![TtToken(DUMMY_SP, token::Lifetime(loop_label))],
|
||||||
|
stmts: vec![writer_stmt],
|
||||||
tail: String::new(),
|
tail: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +43,8 @@ impl<'cx> Renderer<'cx> {
|
||||||
Renderer {
|
Renderer {
|
||||||
cx: self.cx,
|
cx: self.cx,
|
||||||
w: self.w,
|
w: self.w,
|
||||||
|
r: self.r,
|
||||||
|
loop_label: self.loop_label.clone(),
|
||||||
stmts: Vec::new(),
|
stmts: Vec::new(),
|
||||||
tail: String::new(),
|
tail: String::new(),
|
||||||
}
|
}
|
||||||
|
@ -48,7 +58,7 @@ impl<'cx> Renderer<'cx> {
|
||||||
let s = &*self.tail;
|
let s = &*self.tail;
|
||||||
quote_expr!(self.cx, $w.write_str($s))
|
quote_expr!(self.cx, $w.write_str($s))
|
||||||
};
|
};
|
||||||
let stmt = self.cx.stmt_expr(self.cx.expr_try(expr.span, expr));
|
let stmt = self.wrap_try(expr);
|
||||||
self.stmts.push(stmt);
|
self.stmts.push(stmt);
|
||||||
self.tail.clear();
|
self.tail.clear();
|
||||||
}
|
}
|
||||||
|
@ -56,13 +66,16 @@ impl<'cx> Renderer<'cx> {
|
||||||
|
|
||||||
/// Reifies the `Renderer` into a block of markup.
|
/// Reifies the `Renderer` into a block of markup.
|
||||||
pub fn into_expr(mut self) -> P<Expr> {
|
pub fn into_expr(mut self) -> P<Expr> {
|
||||||
let Renderer { cx, w, stmts, .. } = { self.flush(); self };
|
let Renderer { cx, r, loop_label, stmts, .. } = { self.flush(); self };
|
||||||
quote_expr!(cx,
|
quote_expr!(cx, {
|
||||||
::maud::rt::make_markup(|$w: &mut ::std::fmt::Write| -> Result<(), ::std::fmt::Error> {
|
let mut $r = Ok(());
|
||||||
|
$loop_label: loop {
|
||||||
use ::std::fmt::Write;
|
use ::std::fmt::Write;
|
||||||
$stmts
|
$stmts
|
||||||
Ok(())
|
break $loop_label;
|
||||||
}))
|
}
|
||||||
|
$r
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reifies the `Renderer` into a raw list of statements.
|
/// Reifies the `Renderer` into a raw list of statements.
|
||||||
|
@ -82,6 +95,21 @@ impl<'cx> Renderer<'cx> {
|
||||||
self.tail.push_str(s);
|
self.tail.push_str(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wraps an expression in a `try!` call.
|
||||||
|
fn wrap_try(&self, expr: P<Expr>) -> P<Stmt> {
|
||||||
|
let r = self.r;
|
||||||
|
let loop_label = &self.loop_label;
|
||||||
|
quote_stmt!(
|
||||||
|
self.cx,
|
||||||
|
match $expr {
|
||||||
|
Ok(()) => {},
|
||||||
|
Err(e) => {
|
||||||
|
$r = Err(e);
|
||||||
|
break $loop_label;
|
||||||
|
}
|
||||||
|
}).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Appends a literal string, with the specified escaping method.
|
/// Appends a literal string, with the specified escaping method.
|
||||||
pub fn string(&mut self, s: &str, escape: Escape) {
|
pub fn string(&mut self, s: &str, escape: Escape) {
|
||||||
let escaped;
|
let escaped;
|
||||||
|
@ -105,7 +133,7 @@ impl<'cx> Renderer<'cx> {
|
||||||
"{}",
|
"{}",
|
||||||
$expr)),
|
$expr)),
|
||||||
};
|
};
|
||||||
let stmt = self.cx.stmt_expr(self.cx.expr_try(expr.span, expr));
|
let stmt = self.wrap_try(expr);
|
||||||
self.push(stmt);
|
self.push(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,69 +5,75 @@ extern crate maud;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literals() {
|
fn literals() {
|
||||||
let s = html!("du\tcks" -23 3.14 '\n' "geese").to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, "du\tcks" -23 3.14 '\n' "geese").unwrap();
|
||||||
assert_eq!(s, "du\tcks-233.14\ngeese");
|
assert_eq!(s, "du\tcks-233.14\ngeese");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn escaping() {
|
fn escaping() {
|
||||||
let s = html!("<flim&flam>").to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, "<flim&flam>").unwrap();
|
||||||
assert_eq!(s, "<flim&flam>");
|
assert_eq!(s, "<flim&flam>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn semicolons() {
|
fn semicolons() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
"one";
|
"one";
|
||||||
"two";
|
"two";
|
||||||
"three";
|
"three";
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
"four";
|
"four";
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, "onetwothreefour");
|
assert_eq!(s, "onetwothreefour");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blocks() {
|
fn blocks() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
"hello"
|
"hello"
|
||||||
{
|
{
|
||||||
" ducks" " geese"
|
" ducks" " geese"
|
||||||
}
|
}
|
||||||
" swans"
|
" swans"
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, "hello ducks geese swans");
|
assert_eq!(s, "hello ducks geese swans");
|
||||||
}
|
}
|
||||||
|
|
||||||
mod elements {
|
mod elements {
|
||||||
#[test]
|
#[test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
p { b { "pickle" } "barrel" i { "kumquat" } }
|
write_html!(s, p { b { "pickle" } "barrel" i { "kumquat" } }).unwrap();
|
||||||
}.to_string();
|
|
||||||
assert_eq!(s, "<p><b>pickle</b>barrel<i>kumquat</i></p>");
|
assert_eq!(s, "<p><b>pickle</b>barrel<i>kumquat</i></p>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nesting() {
|
fn nesting() {
|
||||||
let s = html!(html body div p sup "butts").to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, html body div p sup "butts").unwrap();
|
||||||
assert_eq!(s, "<html><body><div><p><sup>butts</sup></p></div></body></html>");
|
assert_eq!(s, "<html><body><div><p><sup>butts</sup></p></div></body></html>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let s = html!("pinkie" br/ "pie").to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, "pinkie" br/ "pie").unwrap();
|
||||||
assert_eq!(s, "pinkie<br>pie");
|
assert_eq!(s, "pinkie<br>pie");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn attributes() {
|
fn attributes() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
link rel="stylesheet" href="styles.css"/
|
link rel="stylesheet" href="styles.css"/
|
||||||
section id="midriff" {
|
section id="midriff" {
|
||||||
p class="hotpink" "Hello!"
|
p class="hotpink" "Hello!"
|
||||||
}
|
}
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, concat!(
|
assert_eq!(s, concat!(
|
||||||
r#"<link rel="stylesheet" href="styles.css">"#,
|
r#"<link rel="stylesheet" href="styles.css">"#,
|
||||||
r#"<section id="midriff"><p class="hotpink">Hello!</p></section>"#));
|
r#"<section id="midriff"><p class="hotpink">Hello!</p></section>"#));
|
||||||
|
@ -75,7 +81,8 @@ mod elements {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_attributes() {
|
fn empty_attributes() {
|
||||||
let s = html! { div readonly? input type="checkbox" checked? / }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, div readonly? input type="checkbox" checked? /).unwrap();
|
||||||
assert_eq!(s, r#"<div readonly><input type="checkbox" checked></div>"#);
|
assert_eq!(s, r#"<div readonly><input type="checkbox" checked></div>"#);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,19 +90,22 @@ mod elements {
|
||||||
mod splices {
|
mod splices {
|
||||||
#[test]
|
#[test]
|
||||||
fn literals() {
|
fn literals() {
|
||||||
let s = html! { $"<pinkie>" }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $"<pinkie>").unwrap();
|
||||||
assert_eq!(s, "<pinkie>");
|
assert_eq!(s, "<pinkie>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn raw_literals() {
|
fn raw_literals() {
|
||||||
let s = html! { $$"<pinkie>" }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $$"<pinkie>").unwrap();
|
||||||
assert_eq!(s, "<pinkie>");
|
assert_eq!(s, "<pinkie>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blocks() {
|
fn blocks() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
${
|
${
|
||||||
let mut result = 1i32;
|
let mut result = 1i32;
|
||||||
for i in 2..11 {
|
for i in 2..11 {
|
||||||
|
@ -103,19 +113,20 @@ mod splices {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, "3628800");
|
assert_eq!(s, "3628800");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn attributes() {
|
fn attributes() {
|
||||||
let rocks = true;
|
let rocks = true;
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
input checked?=true /
|
input checked?=true /
|
||||||
input checked?=false /
|
input checked?=false /
|
||||||
input checked?=rocks /
|
input checked?=rocks /
|
||||||
input checked?=(!rocks) /
|
input checked?=(!rocks) /
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, concat!(
|
assert_eq!(s, concat!(
|
||||||
r#"<input checked>"#,
|
r#"<input checked>"#,
|
||||||
r#"<input>"#,
|
r#"<input>"#,
|
||||||
|
@ -127,14 +138,16 @@ mod splices {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn statics() {
|
fn statics() {
|
||||||
let s = html! { $BEST_PONY }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $BEST_PONY).unwrap();
|
||||||
assert_eq!(s, "Pinkie Pie");
|
assert_eq!(s, "Pinkie Pie");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn closures() {
|
fn closures() {
|
||||||
let best_pony = "Pinkie Pie";
|
let best_pony = "Pinkie Pie";
|
||||||
let s = html! { $best_pony }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $best_pony).unwrap();
|
||||||
assert_eq!(s, "Pinkie Pie");
|
assert_eq!(s, "Pinkie Pie");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,37 +172,36 @@ mod splices {
|
||||||
name: "Pinkie Pie",
|
name: "Pinkie Pie",
|
||||||
adorableness: 9,
|
adorableness: 9,
|
||||||
};
|
};
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
"Name: " $pinkie.name ". Rating: " $pinkie.repugnance()
|
"Name: " $pinkie.name ". Rating: " $pinkie.repugnance()
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, "Name: Pinkie Pie. Rating: 1");
|
assert_eq!(s, "Name: Pinkie Pie. Rating: 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nested_macro_invocation() {
|
fn nested_macro_invocation() {
|
||||||
let best_pony = "Pinkie Pie";
|
let best_pony = "Pinkie Pie";
|
||||||
let s = html! { $(format!("{}", best_pony)) }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $(format!("{}", best_pony))).unwrap();
|
||||||
assert_eq!(s, "Pinkie Pie");
|
assert_eq!(s, "Pinkie Pie");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn issue_1() {
|
|
||||||
let markup = html! { "Test" };
|
|
||||||
let _ = markup.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_13() {
|
fn issue_13() {
|
||||||
let owned = String::from("yay");
|
let owned = String::from("yay");
|
||||||
let _ = html! { $owned }.to_string();
|
let mut s = String::new();
|
||||||
|
write_html!(s, $owned).unwrap();
|
||||||
|
let _ = owned;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod control {
|
mod control {
|
||||||
#[test]
|
#[test]
|
||||||
fn if_expr() {
|
fn if_expr() {
|
||||||
for (number, &name) in (1..4).zip(["one", "two", "three"].iter()) {
|
for (number, &name) in (1..4).zip(["one", "two", "three"].iter()) {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
$if number == 1 {
|
$if number == 1 {
|
||||||
"one"
|
"one"
|
||||||
} $else if number == 2 {
|
} $else if number == 2 {
|
||||||
|
@ -199,7 +211,7 @@ mod control {
|
||||||
} $else {
|
} $else {
|
||||||
"oh noes"
|
"oh noes"
|
||||||
}
|
}
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, name);
|
assert_eq!(s, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,13 +219,14 @@ mod control {
|
||||||
#[test]
|
#[test]
|
||||||
fn if_let() {
|
fn if_let() {
|
||||||
for &(input, output) in [(Some("yay"), "yay"), (None, "oh noes")].iter() {
|
for &(input, output) in [(Some("yay"), "yay"), (None, "oh noes")].iter() {
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
$if let Some(value) = input {
|
$if let Some(value) = input {
|
||||||
$value
|
$value
|
||||||
} $else {
|
} $else {
|
||||||
"oh noes"
|
"oh noes"
|
||||||
}
|
}
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, output);
|
assert_eq!(s, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,11 +234,12 @@ mod control {
|
||||||
#[test]
|
#[test]
|
||||||
fn for_expr() {
|
fn for_expr() {
|
||||||
let ponies = ["Apple Bloom", "Scootaloo", "Sweetie Belle"];
|
let ponies = ["Apple Bloom", "Scootaloo", "Sweetie Belle"];
|
||||||
let s = html! {
|
let mut s = String::new();
|
||||||
|
write_html!(s, {
|
||||||
ul $for pony in &ponies {
|
ul $for pony in &ponies {
|
||||||
li $pony
|
li $pony
|
||||||
}
|
}
|
||||||
}.to_string();
|
}).unwrap();
|
||||||
assert_eq!(s, concat!(
|
assert_eq!(s, concat!(
|
||||||
"<ul>",
|
"<ul>",
|
||||||
"<li>Apple Bloom</li>",
|
"<li>Apple Bloom</li>",
|
||||||
|
|
Loading…
Add table
Reference in a new issue