Templates for MoonBit: text with braces, indented markup or Markdown over one expression language; compiled once, rendered many times.
let out = @moonpug.render("Hello {{ name|title }}!", { "name": "ada" })
// Hello Ada!moon add moonbitstack/moonpugimport {
"moonbitstack/moonpug",
}struct Book {
title : String
year : Int
tags : Array[String]
} derive(ToJson)
struct Shelf {
shelf : String
books : Array[Book]
} derive(ToJson)
let page =
#|<h1>{{ shelf }}</h1>
#|<ul>{% for b in books|sort(attribute='year') %}
#| <li>{{ b.title }}, {{ b.year }}{% if b.tags %} ({{ b.tags|join(', ') }}){% endif %}</li>
#|{% endfor %}</ul>
let html = @moonpug.render(page, Shelf::{ shelf: "Reading <list>", books: [...] })| Name | Also | Reads | Preset |
|---|---|---|---|
| html | text with {{ }}, {% %} and {# #} | html (escaped), text (not escaped) | |
| pug | pg | elements by indentation, < lines passed through, {% %} lines as statements | pug |
| md | markdown | the brace syntax, with a tag on a line of its own leaving no blank line | markdown |
let data : Json = { "title": "Notes", "items": ["ink", "paper"] }
@moonpug.render("h1= title\neach i in items\n p= i", data, format=@moonpug.pug)
// <h1>Notes</h1><p>ink</p><p>paper</p><section>
{% block lang=pug %}
ul
each i in items
li= i
{% endblock %}
</section>let env = @moonpug.Env::new()
env.add_global("today", @moonpug.Value::func("today", (_, _, _) => Text("2026-10-25")))
env.add_filter("money", (call, value, _, _) => Text("¥" + call.text(value)))
env.add_test("short", (call, value, _) => call.text(value).length() <= 3)impl @moonpug.Object for Cart with fn kind(_) { "the cart" }
impl @moonpug.Object for Cart with fn attr(self, name) { ... } // cart.total
impl @moonpug.Object for Cart with fn items(self) { ... } // for x in cart
impl @moonpug.Object for Cart with fn assign(self, name, value) { ... } // {% set cart.coupon = … %}
env.compile(source).render_values({ "cart": Object(cart) })let env = @moonpug.Env::new(load=name => sources.get(name))
let page = env.template("page.html") // read, compiled and kept
page.render(data)fn read_csv(source : String, reading : @moonpug.Reading) -> Array[@syntax.Node] raise @moonpug.Refused {
...
nodes.append(reading.block(cell, "html", None, reading.line)) // cells read as HTML
...
}
env.add_lang({ name: "csv", aliases: ["table"], options: @syntax.options, read: read_csv })| Record | Fields | Preset |
|---|---|---|
| Format | lang, autoescape, trim_blocks, lstrip_blocks, keep_trailing_newline | html, pug, markdown, text |
| Settings | format, formats, force, undefined, line_statement, line_comment, limits | settings |
| Limits | depth (1000), range (100 000) | limits |
library preset < the record you pass < the same name passed to this call| Variant | When |
|---|---|
| Syntax(template, line, column, reason) | the source is not well formed |
| Unknown(template, line, kind, name) | a name, filter, test, template, language or attribute that resolves to nothing |
| Invalid(template, line, reason) | values that do not fit: wrong arguments, an operation a type does not take |
| Exceeded(template, line, limit, got) | a bound in Limits was crossed |
page.html:3: price is undefinedmoon run src/examples/01-first-page
moon run src/examples/02-three-languages
moon run src/examples/03-template-set
moon run src/examples/04-own-language
moon run src/examples/05-host-objectspub struct Env {
// private fields
}pub(all) struct Format {
lang : String
autoescape : Bool
trim_blocks : Bool
lstrip_blocks : Bool
keep_trailing_newline : Bool
}pub struct Template {
// private fields
}fn escape(text : String) -> StringInstall
Download zipTemplates for MoonBit: text with braces, indented markup or Markdown over one expression language; compiled once, rendered many times.