Molde
Zero dependency, single file template engine for Lua 5.1+ with builtin sandbox support.
It compiles a template string to a function that generates the final string by substituting values by the ones in a sandboxed environment.
Templates
There are 3 constructs templates recognize:
- Literals: Content that will be copied unmodified to the final string. Read the note on long strings
- Value: A value processed by Lua and appended to the final string, stringified by tostring
- Statement: A Lua code block to be copied unmodified to the generated code, used for variable assignments, repetitions, conditions, etc. It doesn't directly generate contents for the final string
Values are delimited by matching {{
and }}
, statements by {%
and
%}
, and everything else is considered literal. Delimiter characters {
,
}
and %
can be escaped using a leading backslash. If you want literal }}
or %}
in your template, they must be escaped, or molde will return
error.
Example:
NOTE: This is not a valid molde template for educational purposes.
By default, everything is copied unmodified to the final string.
Values are just Lua expressions:
- Hello {{ "world" }}
"Hello world"
- {{ 5 + 3 * 4 }}
"17"
- {{ nil or "default" }}
"default"
- You are using {{ _VERSION }}
"You are using Lua 5.3" (You may use Lua 5.1 and 5.2 as well)
- Line 1{{ "\n" }}Line 2
"Line 1
Line 2"
- Escaping \{{ Hi! \}} (Note that you MUST escape the closing '}}')
"Escaping {{ Hi! }}"
- Escaping is characterwise, so \{{ is as valid as {\{
"Escaping is characterwise, so {{ is as valid as {{"
- table.insert is used in values {{ so they must be a valid expression! }}
Error: ')' expected near 'they'
Statements are Lua statements:
- {% for i = 1, 5 do %}{{ i }} {% end %}
"1 2 3 4 5 "
- {% -- this is just a comment, y'know %}
""
- {{ unbound_variable }}{% unbound_variable = "Hi!" %} {{ unbound_variable }}
"nil Hi!"
- {% if false then %}This will never be printed{% else %}Conditionals!{% end %}
"Conditionals!"
- \{% Escaping works \%} {\% here as well %\} (You MUST escape closing '%}' too)
"{% Escaping works %} {% here as well %}"
- {% if without_then %}Statements must form valid Lua code!{% end %}
Error: 'then' expected near 'table'
Note on long strings
The lua reference manual says:
For convenience, when the opening long bracket is immediately followed by a newline, the newline is not included in the string.
The code generated by molde to insert literals uses long strings, so newlines that come immediately after a closing value or statement will not be considered in the final string.
Installing
Using LuaRocks:
# luarocks install molde
Or you may copy the only source file molde.lua
to your Lua path
Using
local molde = require 'molde' -- molde.load and molde.loadfile return a function that receives a table -- with the values to substitute, and the optional environment (default: _G) hello_template = molde.load([[Hello {{ name or "world" }}]]) print(hello_template()) -- "Hello world" print(hello_template{name = "gilzoide"}) -- "Hello gilzoide" name = "gilzoide" print(hello_template({}, _ENV or getfenv())) -- "Hello gilzoide" -- load the template from a file (same template) hello_template = molde.loadfile("hello_template") name = nil print(hello_template()) -- "Hello world"
Testing
Run automated tests using busted:
$ busted
Documentation
The API is documented using LDoc and is available at github pages.
To generate:
$ ldoc . -d docs
Change log
- 2.0.0 - Removed dependency on LPegLabel in favor of a pure streaming parser,
added molde.tokenize, changed molde.parse function to be an iterator
instead of returning table, move doc comments to source file, changed
string_bracket_level
to be a function argument instead of module-wide configuration, change molde.load to returnnil
+ error instead of raising. - 1.0.1 - Fix error handling for matching on LpegLabel v1.5
- 1.0.0 - Updated to use LpegLabel version 1.5+
- 0.1.6 - Support for Lua 5.1