Replace $$ syntax with a general trait thing

This commit is contained in:
Chris Wong 2015-10-06 19:14:31 +13:00
parent 48729378cf
commit 2e0aa3e433
4 changed files with 36 additions and 34 deletions
maud/src
maud_macros

View file

@ -8,6 +8,32 @@
use std::fmt;
use std::io;
/// Represents a type that can be rendered as HTML.
///
/// Most of the time you should implement `std::fmt::Display` instead,
/// which will be picked up by the blanket impl.
pub trait Render {
fn render(&self, &mut fmt::Write) -> fmt::Result;
}
impl<T: fmt::Display + ?Sized> Render for T {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
use std::fmt::Write;
write!(Escaper::new(w), "{}", self)
}
}
/// A wrapper that renders the inner value without escaping.
#[derive(Debug)]
pub struct PreEscaped<T>(pub T);
impl<T: fmt::Display> Render for PreEscaped<T> {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
use std::fmt::Write;
write!(w, "{}", self.0)
}
}
/// An adapter that escapes HTML special characters.
///
/// # Example

View file

@ -10,7 +10,7 @@ use syntax::parse::token::{BinOpToken, DelimToken, IdentStyle, Token};
use syntax::parse::token::keywords::Keyword;
use syntax::ptr::P;
use super::render::{Escape, Renderer};
use super::render::Renderer;
macro_rules! error {
($cx:expr, $sp:expr, $msg:expr) => ({
@ -162,15 +162,10 @@ impl<'cx, 'i> Parser<'cx, 'i> {
self.render.emit_call(func);
},
// Splice
[ref tt @ dollar!(), dollar!(), ..] => {
self.shift(2);
let expr = try!(self.splice(tt.get_span()));
self.render.splice(expr, Escape::PassThru);
},
[ref tt @ dollar!(), ..] => {
self.shift(1);
let expr = try!(self.splice(tt.get_span()));
self.render.splice(expr, Escape::Escape);
self.render.splice(expr);
},
// Element
[ident!(sp, _), ..] => {
@ -205,7 +200,7 @@ impl<'cx, 'i> Parser<'cx, 'i> {
fn literal(&mut self, tt: &TokenTree, minus: bool) -> PResult<()> {
let lit = try!(self.with_rust_parser(vec![tt.clone()], RustParser::parse_lit));
let s = try!(lit_to_string(self.render.cx, lit, minus));
self.render.string(&s, Escape::Escape);
self.render.string(&s);
Ok(())
}

View file

@ -7,12 +7,6 @@ use syntax::ptr::P;
use maud::Escaper;
#[derive(Copy, Clone)]
pub enum Escape {
PassThru,
Escape,
}
pub struct Renderer<'cx> {
pub cx: &'cx ExtCtxt<'cx>,
writer: Ident,
@ -116,29 +110,15 @@ impl<'cx> Renderer<'cx> {
}).unwrap()
}
/// Appends a literal string, with the specified escaping method.
pub fn string(&mut self, s: &str, escape: Escape) {
let escaped;
let s = match escape {
Escape::PassThru => s,
Escape::Escape => { escaped = html_escape(s); &*escaped },
};
self.push_str(s);
/// Appends a literal string.
pub fn string(&mut self, s: &str) {
self.push_str(&html_escape(s));
}
/// Appends the result of an expression, with the specified escaping method.
pub fn splice(&mut self, expr: P<Expr>, escape: Escape) {
pub fn splice(&mut self, expr: P<Expr>) {
let w = self.writer;
let expr = match escape {
Escape::PassThru =>
quote_expr!(self.cx, write!($w, "{}", $expr)),
Escape::Escape =>
quote_expr!(self.cx,
write!(
::maud::Escaper::new(&mut *$w),
"{}",
$expr)),
};
let expr = quote_expr!(self.cx, ::maud::Render::render(&$expr, &mut *$w));
let stmt = self.wrap_try(expr);
self.push(stmt);
}

View file

@ -99,8 +99,9 @@ mod splices {
#[test]
fn raw_literals() {
use maud::PreEscaped;
let mut s = String::new();
html!(s, $$"<pinkie>").unwrap();
html!(s, $PreEscaped("<pinkie>")).unwrap();
assert_eq!(s, "<pinkie>");
}