Crate horrorshow

Source
Expand description

§Horrorshow

An html templating library.

§Example:

use horrorshow::prelude::*;
use horrorshow::helper::doctype;

let my_title = "Hello world!";
let actual = format!("{}", html! {
    : doctype::HTML;
    html {
        head {
            // Use a variable
            title : my_title;
        }
        body {
            // attributes
            h1(id="heading", class="title") : my_title;
            p {
                // Insert escaped text
                : "Hello! This is <html />";
            }
            p {
                // Insert raw text (unescaped)
                : Raw("Let's <i>count</i> to 10!");
            }
            ol(id="count") {
                // You can embed for loops, while loops, and if statements.
                @ for i in 0..10 {
                    li(first? = (i == 0), class="item") {
                        // Format some text.
                        : format_args!("{}", i+1)
                    }
                }
            }
            // You need semi-colons for tags without children.
            br; br;
            p {
                // You can also embed closures.
                |tmpl| {
                    tmpl << "Easy!";
                }
            }
        }
    }
});

let expected = "\
<!DOCTYPE html>\
<html>\
  <head>\
    <title>Hello world!</title>\
  </head>\
  <body>\
    <h1 id=\"heading\" class=\"title\">Hello world!</h1>\
    <p>Hello! This is &lt;html /&gt;</p>\
    <p>Let's <i>count</i> to 10!</p>\
    <ol id=\"count\">\
      <li first class=\"item\">1</li>\
      <li class=\"item\">2</li>\
      <li class=\"item\">3</li>\
      <li class=\"item\">4</li>\
      <li class=\"item\">5</li>\
      <li class=\"item\">6</li>\
      <li class=\"item\">7</li>\
      <li class=\"item\">8</li>\
      <li class=\"item\">9</li>\
      <li class=\"item\">10</li>\
    </ol>\
    <br><br>\
    <p>Easy!</p>\
  </body>\
</html>";
assert_eq!(expected, actual);

§Usage

#[macro_use]
extern crate horrorshow;

Inside an html template, the following expressions are valid:

  • some_tag; – Insert a the tag some_tag.

  • some_tag(attr=rust_expresion,...); – Insert a the tag some_tag with the specified attributes. The attribute values will be evaluated as rust expressions at runtime and they must implement RenderOnce (already implemented on &str, String, other templates, etc.).

  • some_tag(attr,...); – You can also omit the value.

  • some_tag(attr? = Some("test"),...); – You can optionally include an attribute.

  • some_tag(attr? = some_boolean,...); – You can optionally include an attribute without a value.

  • some_tag { ... } – Insert the tag some_tag and recursively evaluate the ....

  • some_tag(...) { ... } – Same as above but with custom attributes.

  • : rust_expression, : { rust_code } – Evaluate the expression or block and insert result current position. To insert a literal html (unescaped), mark it as raw with the Raw marker type.

  • |tmpl| rust_expression, |tmpl| { rust_code } – Evaluate the expression or block. This is actually a closure so the block/expression can append to the current template through tmpl (of type &mut TemplateBuffer).

  • @ for ..., @ while ..., @ if ... – you can embed basic control flow expressions.

§Traits, traits oh-my!

You will likely notice that there are four render traits:

  1. RenderOnce
  2. RenderMut
  3. Render
  4. RenderBox

These three traits map to the four Fn traits and reflect the fact that some templates need exclusive access (RenderMut) in order to be rendered and others might even consume their environment (RenderOnce).

In general, just import Template into your environment (or import the prelude).

§Error Handling

Both render and IO errors are handled in the background. If an io (or fmt) error occurs, template rendering will continue but no more data will be written and the original write_to_* call will return the error when rendering terminates. If you need to record a render error, use TemplateBuffer::record_error. As with IO errors, custom errors DO NOT cause rendering to be aborted. Instead, all recorded errors (if any) are returned when rendering completes.

TL;DR: There is no way to abort rendering but you can report errors.

§Escaping

This library does HTML escaping by default. However, it doesn’t do any javascript/URL escaping. Furthermore, it will do html escaping in any literal javascript you might include.

For example, the following will display an alert:

html! {
  script {
    : "alert('hello');"
  }
}

The following will break due to html escaping (the " will be escaped to &quot;):

html! {
  script {
    : "alert(\"hello\");"
  }
}

And the following will display as-is (but won’t run any javascript) due to the HTML escaping:

html! {
    : "<script>alert(\"hello\");</script>"
}

Output:

&lt;script&gt;alert(&quot;hello&quot;);&lt;/script&gt;

§Returning Templates

To return a template directly, you have to create it using the box_html! macro instead of the html! macro. The template type will be one of Box<RenderBox> (can be rendered once), Box<RenderMut>, or Box<Render> depending on how the template affects its environment.

#[macro_use]
extern crate horrorshow;

use horrorshow::{RenderOnce, RenderBox, RenderMut, Render};

// Consume the environment
fn identity<T: RenderOnce + 'static>(something: T) -> Box<RenderBox + 'static> {
    box_html! {
        : something
    }
}

// Mutate the environment
fn counter() -> Box<RenderMut> {
    let mut counter = 0;
    box_html! {
        |t| {
            write!(t, "{}", counter);
            counter += 1;
        }
    }
}

// Borrow the environment.
fn say_hello(name: String) -> Box<Render> {
    let mut counter = 0;
    box_html! {
        span {
            : "Hello ";
            : &name;
            : ".";
        }
    }
}

Note: To avoid allocating, you can implement render manually instead of returning a boxed template:

#[macro_use]
extern crate horrorshow;

use horrorshow::{RenderOnce, TemplateBuffer, Template};

struct Page<C> {
    title: String,
    content: C,
}

impl Page<String> {
    fn from_string_content(title: String, content: String) -> Self {
        Page { title: title, content: content }
    }
}

impl<C> RenderOnce for Page<C> where C: RenderOnce {
    fn render_once(self, tmpl: &mut TemplateBuffer) {
        let Page {title, content} = self;
        // The actual template:
        tmpl << html! {
            article {
                header {
                    h1 : title
                }
                section : content
            }
        };
    }
}

fn main() {
  let page = Page::from_string_content(String::from("My title"),
                                       String::from("Some content."));
  assert_eq!(page.into_string().unwrap(),
             "<article>\
                <header><h1>My title</h1></header>\
                <section>Some content.</section>\
              </article>");
}

§Examples

See the test cases.

Modules§

  • Helpers templates.
  • Traits that should always be imported.

Macros§

  • Append html to the current template. Don’t call this manually.
  • Create a new owned html template.
  • Create a new html template.
  • Utility macro for generating a space-delimited string from a set of labels; some of which may be conditionally included into the final string. Labels are anything that implements the RenderOnce trait (e.g. String or &str).
  • Utility macro for generating a delimited string from a set of labels; some of which may be conditionally included into the final string. The delimiter/seperator and labels are anything that implements the RenderOnce trait (e.g. String or &str).
  • Create a new html template taking ownership of any variables used inside.
  • Create a new template.

Structs§

  • Error type returned when formatting templates.
  • A template renderer. The html! {} macro returns a FnRenderer.
  • Raw content marker.
  • A template buffer. This is the type that gets passed to closures inside templates.

Traits§

  • Something that can be rendered by reference.
  • Something that can be rendered once out of a box.
  • Something that can be rendered by mutable reference.
  • Something that can be rendered once.
  • A template that can be rendered into something.