summaryrefslogtreecommitdiffstats
path: root/contrib/lua-lupa/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/lua-lupa/README.md')
-rw-r--r--contrib/lua-lupa/README.md179
1 files changed, 179 insertions, 0 deletions
diff --git a/contrib/lua-lupa/README.md b/contrib/lua-lupa/README.md
new file mode 100644
index 0000000..edf6dce
--- /dev/null
+++ b/contrib/lua-lupa/README.md
@@ -0,0 +1,179 @@
+# Lupa
+
+## Introduction
+
+Lupa is a [Jinja2][] template engine implementation written in Lua and supports
+Lua syntax within tags and variables.
+
+Lupa was sponsored by the [Library of the University of Antwerp][].
+
+[Jinja2]: http://jinja.pocoo.org
+[Library of the University of Antwerp]: http://www.uantwerpen.be/
+
+## Requirements
+
+Lupa has the following requirements:
+
+* [Lua][] 5.1, 5.2, or 5.3.
+* The [LPeg][] library.
+
+[Lua]: http://www.lua.org
+[LPeg]: http://www.inf.puc-rio.br/~roberto/lpeg/
+
+## Download
+
+Download Lupa from the project’s [download page][].
+
+[download page]: download
+
+## Installation
+
+Unzip Lupa and place the "lupa.lua" file in your Lua installation's
+`package.path`. This location depends on your version of Lua. Typical locations
+are listed below.
+
+* Lua 5.1: */usr/local/share/lua/5.1/* or */usr/local/share/lua/5.1/*
+* Lua 5.2: */usr/local/share/lua/5.2/* or */usr/local/share/lua/5.2/*
+* Lua 5.3: */usr/local/share/lua/5.3/* or */usr/local/share/lua/5.3/*
+
+You can also place the "lupa.lua" file wherever you'd like and add it to Lua's
+`package.path` manually in your program. For example, if Lupa was placed in a
+*/home/user/lua/* directory, it can be used as follows:
+
+ package.path = package.path..';/home/user/lua/?.lua'
+
+## Usage
+
+Lupa is simply a Lua library. Its `lupa.expand()` and `lupa.expand_file()`
+functions may called to process templates. For example:
+
+ lupa = require('lupa')
+ lupa.expand("hello {{ s }}!", {s = "world"}) --> "hello world!"
+ lupa.expand("{% for i in {1, 2, 3} %}{{ i }}{% endfor %}") --> 123
+
+By default, Lupa loads templates relative to the current working directory. This
+can be changed by reconfiguring Lupa:
+
+ lupa.expand_file('name') --> expands template "./name"
+ lupa.configure{loader = lupa.loaders.filesystem('path/to/templates')}
+ lupa.expand_file('name') --> expands template "path/to/templates/name"
+
+See Lupa's [API documentation][] for more information.
+
+[API documentation]: api.html
+
+## Syntax
+
+Please refer to Jinja2's extensive [template documentation][]. Any
+incompatibilities are listed in the sections below.
+
+[template documentation]: http://jinja.pocoo.org/docs/dev/templates/
+
+## Comparison with Jinja2
+
+While Lua and Python (Jinja2's implementation language) share some similarities,
+the languages themselves are fundamentally different. Nevertheless, a
+significant effort was made to support a vast majority of Jinja2's Python-style
+syntax. As a result, Lupa passes Jinja2's test suite with only a handful of
+modifications. The comprehensive list of differences between Lupa and Jinja2 is
+described in the following sections.
+
+### Fundamental Differences
+
+* Expressions use Lua's syntax instead of Python's, so many of Python's
+ syntactic constructs are not valid. However, the following constructs
+ *are valid*, despite being invalid in pure Lua:
+
+ + Iterating over table literals or table variables directly in a "for" loop:
+
+ {% for i in {1, 2, 3} %}...{% endfor %}
+
+ + Conditional loops via an "if" expression suffix:
+
+ {% for x in range(10) if is_odd(x) %}...{% endfor %}
+
+ + Table unpacking for list elements when iterating through a list of lists:
+
+ {% for a, b, c in {{1, 2, 3}, {4, 5, 6}} %}...{% endfor %}
+
+ + Default values for macro arguments:
+
+ {% macro m(a, b, c='c', d='d') %}...{% endmacro %}
+
+* Strings do not have unicode escapes nor is unicode interpreted in any way.
+
+### Syntactic Differences
+
+* Line statements are not supported due to parsing complexity.
+* In `{% for ... %}` loops, the `loop.length`, `loop.revindex`,
+ `loop.revindex0`, and `loop.last` variables only apply to sequences, where
+ Lua's `'#'` operator applies.
+* The `{% continue %}` and `{% break %}` loop controls are not supported due to
+ complexity.
+* Loops may be used recursively by default, so the `recursive` loop modifier is
+ not supported.
+* The `is` operator is not supported by Lua, so tests of the form `{{ x is y }}`
+ should be written `{{ is_y(x) }}` (e.g. `{{ is_number(42) }}`).
+* Filters cannot occur after tokens within an expression (e.g.
+ `{{ "foo"|upper .. "bar"|upper }}`), but can only occur at the end of an
+ expression (e.g. `{{ "foo".."bar"|upper }}`).
+* Blocks always have access to scoped variables, so the `scoped` block modifier
+ is not supported.
+* Named block end tags are not supported since the parser cannot easily keep
+ track of that state information.
+* Any `{% block ... %}` tags within a "false" block (e.g. `{% if a %}` where `a`
+ evaluates to `false`) are never read and stored due to the parser
+ implementation.
+* Inline "if" expressions (e.g. `{% extends b if a else c %}`) are not
+ supported. Instead, use a Lua conditional expression
+ (e.g. `{% extends a and b or c %}`).
+* Any `{% extends ... %}` tags within a sub-scope are not effective outside that
+ scope (e.g. `{% if a %}{% extends a %}{% else %}{% extends b %}{% endif %}`).
+ Instead, use a Lua conditional expression (e.g. `{% extends a or b %}`).
+* Macros are simply Lua functions and have no metadata attributes.
+* Macros do not have access to a `kwargs` variable since Lua does not support
+ keyword arguments.
+* `{% from x import y %}` tags are not supported. Instead, you must use either
+ `{% import x %}`, which imports all globals in `x` into the current
+ environment, or use `{% import x as z %}`, which imports all globals in `x`
+ into the variable `z`.
+* `{% set ... %}` does not support multiple assignment. Use `{% do ...%}`
+ instead. The catch is that `{% do ... %}` does not support filters.
+* The `{% trans %}` and `{% endtrans %}` tags, `{% with %}` and `{% endwith %}`
+ tags, and `{% autoescape %}` and `{% endautoescape %}` tags are not supported
+ since they are outside the scope of this implementation.
+
+### Filter Differences
+
+* Only the `batch`, `groupby`, and `slice` filters return generators which
+ produce one item at a time when looping. All other filters that produce
+ iterable results generate all items at once.
+* The `float` filter only works in Lua 5.3 since that version of Lua has a
+ distinction between floats and integers.
+* The `safe` filter must appear at the end of a filter chain since its output
+ cannot be passed to any other filter.
+
+### Function Differences
+
+* The global `range(n)` function returns a sequence from 1 to `n`, inclusive,
+ since lists start at 1 in Lua.
+* No `lipsum()`, `dict()`, or `joiner()` functions for the sake of simplicity.
+
+### API Differences
+
+* Lupa has a much simpler API consisting of just four functions and three
+ fields:
+
+ + `lupa.expand()`: Expands a string template subject to an environment.
+ + `lupa.expand_file()`: Expands a file template subject to an environment.
+ + `lupa.configure()` Configures delimiters and template options.
+ + `lupa.reset()`: Resets delimiters and options to their defaults.
+ + `lupa.env`: The default environment for templates.
+ + `lupa.filters`: The set of available filters (`escape`, `join`, etc.).
+ + `lupa.tests`: The set of available tests (`is_odd`, `is_defined`, etc.).
+
+* There is no bytecode caching.
+* Lupa has no extension mechanism. Instead, modify `lupa.env`, `lupa.filters`,
+ and `lupa.tests` directly. However, the parser cannot be extended.
+* Sandboxing is not supported, although `lupa.env` is safe by default (`io`,
+ `os.execute`, `os.remove`, etc. are not available).