femstache 0.1.13

Embrace the feminine mustache to unlock your templating dreams! Or something, I don't know. :3
Documentation

Femstache

Femstache is a mustache-like templating library with its own extensions.

Features

  • Template inheritance
  • Hindley-Milner static type system with PureScript-like extensible records
  • Macros
  • Custom escape modes
  • Contains meows

Syntax

Templates are composed of text interspersed with three kinds of control sequences:

  • {{ ... }}: interpolation
  • {% ... %}: control
  • {# ... #}: metadata (only at the top of a document)

There are a few kinds of control structures:

  • {% if COND %} ... {% end %}
  • {% if let PATTERN = EXPR %} ... {% end %}
  • {% for item in LIST %} ... {% end %}
  • {% for item in dict DICT %} ... {% end %}
  • {% for i in range NUM ... NUM %} ... {% end %}

There are also variable assignments, these are of the form {% let VAR = EXPR %}.

It is also possible to include one template directly into another using {% include "PATH" %}.

Template inheritance is also supported, using {# inherit "PATH_TO_PARENT" #} and {% block BLOCKNAME %}{% end %}.

Macros are done like this:

{% macro hello(thingy) %}
hello {{thingy}}!! :3
{% end %}

{% render hello("world") %}
{% render hello("kity") %}

Types

There are several available types:

  • boolean values: bool
  • integer values: int
  • string values: string (these can be raw strings, which are not escaped)
  • fragments: fragment
  • options: option(a)
  • lists: list(a)
  • dicts: dict(a) (this is from strings to a)
  • structs: struct(field1: ty1, field2: ty2, ...)
  • functions: fun (args...) -> ret

These are statically inferred and checked.

Operators

On all values

  • equals: x == y
  • not equals: x != y

On bool

  • not: !x
  • and: x && y
  • or: x || y

On int

  • addition: x + y
  • subtraction: x - y
  • multiplication: x * y
  • division: x / y

On string

  • concatenation: x ++ y

On dict(a)

  • key access: d[k]

On struct(...)

  • field access: st.field

On fun arg -> ret

  • function call: f(a)

Built-in functions

  • raw: string -> string: string to raw (unescaped) string
  • show_bool: bool -> string: bool to string
  • show_int: int -> string: int to string

Usage

Run cargo add femstache.

Examples

Template

index.fem.html:

{# inherit "./template.fem.html" #}

{% block "title" %}uwu{% end %}

{% block "body" %}
  <p>hello :3</p>

  {% for kitty in kitties %}
    <section>
      <p>{{kitty}} needs a new home, adopt them! =^w^=</p>
    </section>
  {% end %}
{% end %}

template.fem.html:

<!DOCTYPE html>

<html>
  <head>
    <title>{% block "title" %}{% end %}</title>
  </head>
  <body>
    {% block "body" %}{% end %}
  </body>
</html>

Usage in Rust

use std::{collections::BTreeMap, path::PathBuf};
use femstache::{Femstache, TemplateSource, EscapeMode, Value};

let mut files = BTreeMap::new();

files.insert(PathBuf::from("hello.fem.html"), "{% for place in places %}hello {{ place }}! :3\n{% end %}".to_owned());

let mut femstache = Femstache::new(TemplateSource::map(files), EscapeMode::Html);

let mut inputs = BTreeMap::new();
inputs.insert("places".to_owned(), Value::List(vec![
   Value::string("world"),
   Value::string("mom"),
   Value::string("puniqt"),
]));

let output = femstache.render("hello.fem.html", inputs).unwrap();

assert_eq!(output, "hello world! :3\nhello mom! :3\nhello puniqt! :3\n");