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::fmt;
use std::io; 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. /// An adapter that escapes HTML special characters.
/// ///
/// # Example /// # Example

View file

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

View file

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

View file

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