ginger2-2.2.0.0: Jinja templates for Haskell
Safe HaskellNone
LanguageHaskell2010

Language.Ginger

Description

Jinja is a dynamically-typed template language designed for generating HTML and text output.

Ginger2 provides most of the Jinja template language, as much as that makes sense in a Haskell host application.

We do, however, avoid some of the most blatant Pythonisms, especially where we felt the features in question were more of an accidental result of binding template constructs to Python constructs.

We also add some optional features that are absent from the Python implementation, but that we felt useful and worth adding.

Template Syntax

Minimal Example

Expand
<!DOCTYPE html>
<html>
    <head>
        <title>{{ title }}</title>
    </head>
    {# This is a comment. Comments are removed from the output. #}
    <body>
        <menu id="nav-main">
        {% for item in navigation %}
            <li><a href="{{ item.url }}">{{ item.label }}</a></li>
        {% endfor %}
        </menu>
        <div class="layout-content-main">
            <h1>{{ title }}</h1>
            {{ body }}
        </div>
    </body>
</html>

Comments

Expand

Comments are delimited by {# ... #} markers.

It is not currently possible to nest comments.

Interpolation

Expand

The {{ and }} markers delimit interpolation: anything between these markers is interpreted as an expression, and the result of evaluating that expression is written into the template output at this point.

The following expression constructs are available:

Literals

String Literals

String literals can be written with single quotes:

'Hello, world!'

...or double quotes:

"Hello, world!"

Quotes inside string literals can be escaped using backslashes:

"Hello, \"world!\""

Numeric Literals

Integers can be written in decimal:

23

Floats can be written as decimal fractions:

23.5

...or in scientific notation:

0.25e10

Booleans

Two boolean literals exist: true and false. For backwards compatibility with Jinja, True and False are accepted as alternative spellings.

None

The literal none designates the NULL object (approximately equivalent to () or Nothing in Haskell). For backwards compatibility with Jinja, None is accepted as an alternative spelling.

Variables

Variables (built-in, passed in by the host application, or defined within the template itself) are written as barewords. Their names must follow the rules for identifiers:

  • They must start with an alphabetic ASCII character or an underscore.
  • All subsequent characters must be alphanumeric ASCII characters or underscores.

Lists

List literals are written as comma-separated lists between square brackets, like in most programming languages:

["foo", "bar", "baz"]

Because Ginger is dynamically typed, lists are heterogenous, so the following is perfectly fine:

["foo", 23, none, true, 1.5]

Unlike Jinja, Ginger does not distinguish lists from tuples; there is only one list type, and all lists in Ginger are immutable.

Dictionaries

Dictionaries ("dicts") are key-value association containers. They are written as comma-separated lists of dot-separated key/value pairs between curly braces, like so:

{ "foo": 23, "bar": 42 }

Keys and values are both interpreted as expressions; this means that string keys must be written as string literals, not barewords - barewords are interpreted as variables, so for example { foo: "bar" } will not make a dictionary key "foo", but rather try to look up a variable named foo in the current scope, and use its value as the key.

Values can be anything; keys, however, must be scalars, that is, strings, numbers, booleans, or none.

Dot Member Access

Members of dictionaries and (some) native objects can be obtained using dot access syntax, like so:

someDictionary.foo

Note that the member name is written as a bareword; these are *not* interpreted as variables, and quoting member names in dot syntax like string literals is a syntax error. Dot syntax can also be used to access built-in methods of various types of values; for example, the string type provides a method upper(), which returns the original string converted to uppercase, so you can write:

"Hello, world!".upper()

...which will yield the string "HELLO, WORLD!".

Dot syntax will prioritize *attributes* (built-in properties) over *items* (data items stored in a dictionary).

Indexing

Members of dictionaries, as well as elements of lists and characters in a string, can be accessed using an index between square brackets, as follows.

Get an item from a list:

someList[3]

Get a member/item from a dictionary:

someDict["foo"]

Get the n-th character from a string:

someString[3]

Note that strings and lists will only accept integer indices, while dictionaries and native objects may accept arbitrary scalars.

Note further that, unlike dot syntax, the thing between square brackets is evaluated as an expression, so if you want to access a string key in a dictionary, it must be written as a quoted string literal. The following is an example of accessing a dictionary member through a variable key:

someDict[foo]

This will *not* look up a key named "foo", but rather, try to find a variable named "foo" in the current scope, get its value, and use that as a key to look up in someDict.

Indices into strings and lists are zero-based, that is, [0] yields the first element of a list, or the first character of a string.

Square bracket syntax will prioritize *items* (data items stored in a container) over *attributes* (built-in methods associated with a value).

Slicing

Square bracket syntax can also be used to get sub-ranges from a list or string, using the colon (:) to separate the start and end of the desired range. Negative indices imply counting from the end of the range; absent indices refer to the start or end of the original sequence respectively.

Examples:

"Hello, world!"[1:2]

Get a substring of length 2, starting at the second character: "el".

"Hello, world!"[:2]

Get a substring of length 2, starting at the beginning of the string: He.

"Hello, world!"[-2:]

Get a substring up to the end of the string, starting two characters before the end: "d!".

"Hello, world!"[2:-2]

Get a substring from the third character up to 2 characters before the end of the string: "llo, worl".

Unary Operators

Two unary operators are available, both written in prefix notation:

  • not provides boolean negation
  • - provides numeric negation

Binary Operators

All binary operators are written in infix notation. In order of precedence, the following classes of operators are available:

Boolean

  • and - boolean AND
  • or - boolean OR

Boolean Negation

Not a binary operator, but listed here to indicate precedence; see above.

Comparative and Membership

  • == - equals
  • != - not-equals
  • < - less-than; works on numbers as well as strings
  • > - greater-than; dito
  • <= - less-than-or-equal; dito
  • >= - greater-than-or-equal; dito
  • in - membership test

Test

Not a real operator, but listed here to indicate precendence. See below for details on tests.

Concatenation

  • ~ - String concatenation. If non-string arguments are given, they are converted to string. However, if either argument is encoded text, then the other argument will also be encoded first.

Additive

These operations are numeric. If both arguments are integers, integer operations will be used, otherwise, both arguments will be converted to float.

  • + - Numeric addition.
  • - - Numeric subtraction.

Multiplicative

These operations are numeric. If both arguments are integers, integer operations will be used, otherwise, both arguments will be converted to float, unless specified otherwise.

  • * - Numeric multiplication.
  • / - Numeric division.
  • % - Integer modulus. Both arguments will be converted to int.
  • // - Integer division. Both arguments will be converted to int.

Power

Numeric operation; if both arguments are integers, integer arithmetic will be used, otherwise, both arguments will be cast to float.

  • ** Exponentiation: a ** b means "a to the power of b".

Member access, filter, call

Not operators, but listed here to indicate precedence. See respective sections for details.

Ternary Operator

The ternary operator consists of the keywords if and else, and works much like in Python:

"foo" if condition else "bar"

...means "evaluate to 'foo' if condition holds, otherwise, evaluate to 'bar'".

Procedure Calls

Procedure calls are written like in most imperative languages, appending a comma-separated list of arguments between parentheses to the procedure to be called.

To call a procedure foo with two arguments, 1 and 2:

foo(1, 2)

Procedures may have optional arguments (which can be left out, using a default value instead), and arguments can also be given by name instead of positionally, e.g.:

foo(bar=23)

This calls procedure foo with the bar argument set to 23, and any other arguments left at their defaults.

Some objects can be called as procedures while also offering other APIs; an exampe is the loop object that is available within recursive for loops (see below), which exposes a number of fields providing information about the state of the iteration, but can also be called as a procedure to recurse into a deeper iteration level.

Filters

Filter syntax is a convenient syntactic alternative to procedure call syntax. It looks like this:

foo|center(10)

This will call the center filter, passing the value of foo as the first argument, and 10 as a second argument. Thus, it is equivalent to:

center(foo, 10)

If no additional arguments are passed, the parentheses can be omitted:

foo|capitalize

This syntax is particularly useful when chaining multiple filters, e.g.:

foo|default('n/a')|lower|trim

One filter, default, and its alias d, cannot be implemented as procedures, because it must inspect its argument as an unevaluated expression - evaluating it before passing it to the filter would cause a "Not In Scope" error when the argument isn't defined, making the entire filter moot. Hence, this filter is only available through filter syntax, not as a procedure.

Tests

Tests are written using the is keyword, much like a binary operator; however, they are special-cased in the language, for two reasons: * They can inspect their argument unevaluated (e.g., the defined test will do this to determine whether the argument is in scope). * Some tests have the same name as a procedure or filter, but their functionality is different in a text context. E.g., lower, when used as a filter of procedure will convert its argument to lowercase, but when used as a test, it will instead check whether the argument is lowercase.

In Jinja, tests may only occur in contexts where a boolean condition is expected (e.g., the ternary operator, or an {% if ... %} statement); Ginger allows tests in any expression context, and treats the result as a boolean value. For example, the following would be perfectly fine in Ginger, but (probably) not work in Jinja:

{% set answers = { false: "odd", true: "even" } %}
Foo is {{ answers[foo is even] }}.

Flow Control Statements

Expand

All statements are delimited using statement brackets: {% ... %}.

{% filter %}

Apply a filter (see above, filter expressions) to a block of template code.

{% filter 'capitalize' %}
Hello, world!
{% endfilter %}

...will output:

HELLO, WORLD!

The filter itself may be specified as an expression (e.g. {% filter capitalize %}), or as a string that will be resolved as a variable (e.g. {%filter capitalize %}. Both are equivalent.

Additional arguments may be passed just like with filter expression syntax:

{% filter center(100) %}
Hello, world!
{% endfilter %}

{% for %}

Loops over a collection (list or dictionary).

In its simplest form, it looks like this:

{% for user in users %}
{{ user }}
{% endfor %}

This will iterate over the elements of a list in the variable users, binding the current element to the variable user within the scope of the iteration body.

Inside of a for-loop block, you can access some special variables:

  • loop.index - The current iteration of the loop. (1 indexed)
  • loop.index0 - The current iteration of the loop. (0 indexed)
  • loop.revindex - The number of iterations from the end of the loop (1 indexed)
  • loop.revindex0 - The number of iterations from the end of the loop (0 indexed)
  • loop.first - True if first iteration.
  • loop.last - True if last iteration.
  • loop.length - The number of items in the sequence.
  • loop.cycle - A helper function to cycle between a list of sequences. See the explanation below.
  • loop.depth - Indicates how deep in a recursive loop the rendering currently is. Starts at level 1
  • loop.depth0 - Indicates how deep in a recursive loop the rendering currently is. Starts at level 0
  • loop.previtem - The item from the previous iteration of the loop. Undefined during the first iteration.
  • loop.nextitem - The item from the following iteration of the loop. Undefined during the last iteration.
  • loop.changed(val) - True if previously called with a different value (or not called at all).

While there are no continue or break statements to alter the flow of a loop from within, it is possible to filter the iteree, by adding an if construct to the loop header:

{% for user in users if user.username is not none %}
{{ user.username }}
{% endfor %}

The same effect can be achieved by wrapping the loop body in an if statement; however, filtering the loop iteree has the advantage that the loop variables will count correctly.

E.g., given a list of users like so:

[ { "username": "tdammers" },
  { "username": none },
  { "username": "jdoe" }
]

This template will work correctly:

{% for user in users if user.username is not none %}
{{ loop.index }}. {{ user.username }}
{% endfor %}

...outputting:

1. tdammers
2. jdoe

Whereas this template:

{% for user in users %}
{% if user.username is not none %}
{{ loop.index }}. {{ user.username }}
{% endif %}
{% endfor %}

...would output:

1. tdammers
3. jdoe

An optional else branch can be added to a loop, which will be used when the iteration body has not been used at all (because the list was empty, or because all items were filtered out):

{% for user in users %}
<p>{{ user.username }}</p>
{% else %}
<p class="no-results">No users found.</p>
{% endfor %}

Loops can also be used recursively. For this, two things are required:

  1. The loop needs to be declared as being recursive: {% for ... in ... recursive %}
  2. The loop variable must be called with an appropriate iteree in order to recurse into it.

Example:

{% for branch in tree recursive %}
<section>
<h3>{{ branch.name }}</h3>
<p>{{ branch.description }}</p>
{% if "children" in branch %}
{{ loop(branch.children) }}
{% endif %}
{% endfor %}

Please note that assignments in loops will be cleared at the end of the iteration and cannot outlive the loop scope.

To work around this, consider using namespace objects, created using the namespace procedure. However, if all you need to do is check the previous and/or next item in the iteration, you can simply use loop.prev and loop.next.

{% if %}

Conditionals. These work much like if then else in a typical imperative language. Three forms exist:

Simple if with no else:

{% if isGreeting %}
Hi!
{% endif %}

if / else:

{% if isArriving %}
Hello!
{% else %}
Goodbye!
{% endif %}

if elif else:

{% if isMorning %}
Good morning!
{% elif isEvening %}
Good night!
{% else %}
Good day!
{% endif %}

{% set %}

Assignment. There are two forms of the set statement.

First form: assign an expression.

{% set name = "tdammers" %}

Second form: assign a block of encoded output.

{% set name %}
tdammers
{% endset %}

Variables set using either construct will be available within the current scope; includes, imports, template inheritance, the {% with %} statement, and {% for %} loops can affect scope.

{% with %}

Creates a nested scope. Any variables set or overwritten within the nested scope will only be reflected inside the nested scope; any variables from the containing scope will be available until overridden, and will revert back to their previous values when leaving the inner scope.

{% set foo = "A" %}
{{ foo }}
{% with %}
{{ foo }}
{% set foo = "B" %}
{{ foo }}
{% endwith %}
{{ foo }}

Will yield:

A
A
B
A

{% macro %}

Defines a macro. Macros are reusable bits of Jinja code, akin to procedures. In fact, macros and procedures are represented as the same thing internally in Ginger, and you can call procedures as macros (using the {% call %} statement), and macros as procedures or filters (using expression-level procedure call or filter syntax).

A macro definition looks like this:

{% macro userInfo(user, extraInfo=none) %}
<section class="userinfo">
<h3>{{ user.username }}</h3>
<p>Role: {{ user.role }}</p>
<p>Status: {% if user.active %}active{% else %}inactive{% endif %}
{% if extraInfo is not none %}
{{ extraInfo }}
{% endif %}
</section>
{% endmacro %}

Macros can be declared to take any number of arguments, the values of which will be bound to variables in the scope of the macro's body. Defaults can be given for each argument, making it optional; it is considered good practice to list required arguments (without defaults) before optional arguments, so that there is no ambiguity when arguments are given positionally (i.e., without explicit argument names).

Inside a macro body, a special variable, caller, is made available if the macro was invoked through a {% call %} statement. In that case, caller will be a procedure that outputs the body of the {% call %} statement that was used to invoke the macro.

{% call %}

Calls a macro (see above) with an additional body, which is passed through the magic caller() procedure.

Given this macro definition:

{% macro sectionize(title) %}
<section>
<h1>{{ title }}</h1>
{{ caller() }}
</section>
{% endmacro %}

...the following will call that macro with a caller() body:

{% call sectionize("Some Section") %}
Lorem ipsum dolor sit amet.
{% endcall %}

This will render as:

<section>
<h1>Some Section</h1>
Lorem ipsum dolor sit amet.
</section>

{% include %}

{% include "foo.html" %}

This will load the template "foo.html", and insert its output at this position, as if the template source were pasted in.

By default, this implies that the included template will have access to the scope of the location where it is included; you can change this by adding without context to the include statement:

{% include "foo.html" without context %}

It is also valid to write with context, but since that is the default, this will do nothing.

Missing templates are an error; if you want to be lenient, you can add ignore missing to the include, which ignore such errors. If both are given, ignore missing must come before with / without context.

{% include "foo.html" ignore missing without context %}

{% import %}

Works much like include, however, there are some key differences:

  • import will not inject any output from the imported template. The imported template will still be evaluated in full, and any macros and top-level variables it defines (using {% macro %} and {% set %}) will be exported, but any output it generates will be discarded.
  • import defaults to without context, i.e., it does not have access to the scope in which the import statement appears.
  • Because the main purpose of import is to pull top-level definitions into the importing scope, import supports syntax flavors that import specific exports (macros / variables) selectively, as well as one that binds the exports to a single variable acting as a quasi-namespace.

To import a template's exports wholesale:

{% import "util.html" %}

To bind an entire template's export to a quasi-namespace dictionary:

{% import "util.html" as util %}

To import specific exports selectively:

{% from "util.html" import abbreviateUsername, decorateUser %}

To import specific exports, renaming them to aliases:

{% from "util.html" import abbreviateUsername as abbrev, decorateUser as deco %}

{% extends %}

Used for template inheritance:

{% extends "parent.html" %}

Indicates that the current template "extends" the template "parent.html". To render the current template, Ginger will take any blocks (see below under "{% block %}") from the current template, and inject them into the corresponding blocks of the parent template.

Child templates should not directly output anything themselves; they should only override blocks ({% block %}) and top-level variables ({% set %}).

{% block %}

Blocks are overridable subsections of a template. The {% block %} statement is used both to define a block and to override it: the first template in an inheritance chain to use a block name defines it, and determines where it appears in the output; subsequent templates in the chain can override its contents, but not where it appears in the output.

Maybe the most common use case for this is to have a "skeleton" template that defines the overall layout of a web page, and a number of child templates that override those parts that are specific to their respective use cases.

Example:

(skeleton.html)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>{% block "title" %}Unnamed Page{% endblock %}</title>
    <link rel="stylesheet" href="/static/style.css">
  </head>
  <body>
    {% include "mainnav.html" %}
    <div class="maincontent">
    {% block content %}
    Nothing to see here.
    {% endblock }
    </div>
  </body>
</html>

(userlist.html)

{% extends "skeleton.html" %}
{% block "title" %}Users{% endblock %}
{% block "content" %}
<h1>Users</h1>
<ul>
{% for user in users %}
  <li>{{ user.username }}</li>
{% endfor %}
</ul>
{% endblock %}

List Of Builtin Globals

Expand

These are available in Jinja, and work (mostly) the same in Ginger.

abs

abs(value : number) → number

Arguments

value

Absolute of a number.

attr

attr(value : dict, attrName : string) → any

Arguments

value
attrName

Get a named attribute from a dict or dict-like object. Unlike [] or dot member access, this will only look at attributes, not items.

batch

batch(value : any, linecount : int, fill_with=none : any) → list

Arguments

value
linecount
Number of items per chunk. Unlimited if not specified.
fill_with
Filler to pad shorter chunks with. If not specified, don't pad.

Split up a list into chunks of length linecount.

capitalize

capitalize(value : string) → string

Arguments

value

Convert value to title case.

center

center(value : string, width=80 : int, fillchar=" " : string) → string

Arguments

value
width
fillchar

Pad string on both sides to center it in the given space

count

count(value : [string | list | dict]) → int

Alias for length

dictsort

dictsort(value : dict, case_sensitive=false : bool, by="key" : string, reverse=false : bool) → list

Arguments

value
case_sensitive
by
One of key, value
reverse

Sort a dict, returning a list of key-value pairs.

e

e(value : any) → encoded

Alias for escape

escape

escape(value : any) → encoded

Arguments

value

Escape the argument.

even

even(value : int) → bool

Arguments

value

Check if value is an even number

filesizeformat

filesizeformat(value : number, binary=false : bool) → string

Arguments

value
binary
If set, use binary units (kiB, MiB, ...) instead of decimal (kB, MB, ...)

Format value as a human-readable file size.

first

first(value : [list | string | bytes]) → any

Arguments

value

Get the first element from a list, or the first character from a string.

float

float(value : any, default=0.0 : any) → float

Arguments

value
default

Convert value to float. If default is given, values that cannot be converted to floats will be replaced with this default value.

groupby

groupby(value : any, attribute : [string | int], default=none : any, case_sensitive=true : bool) → dict

Arguments

value
attribute
Attribute to group by.
default
Default value to use if an object doesn't have the requested attribute.
case_sensitive
Use case-sensitive comparisons for grouping objects.

Group a list of objects by an attribute. The attribute can use dot notation for nested access, e.g. 'address.city'.

int

int(value : any, default=0 : any, base=10 : any) → int

Arguments

value
default
base

Convert value to int. If default is given, values that cannot be converted to integers will be replaced with this default value.

items

items(value : dict) → list

Arguments

value

Convert a dict to a list of its elements without the keys.

join

join(iterable : list, d="" : string, attr=none : any) → string

Arguments

iterable
d
Default value to use to replace empty elements
attr
If given, an attribute to pick from each element

Join an iterable into a string

json

json(value : any, indent=none : any) → string

Alias for tojson

last

last(value : [list | string | bytes]) → any

Arguments

value

Get the last element from a list, or the last character from a string.

length

length(value : [string | list | dict]) → int

Arguments

value

Get the length of a string, list, or dictionary.

list

list(value : any) → list

Arguments

value

Convert value to a list, if possible

lower

lower(value : string) → string

Arguments

value

Convert value to lowercase.

map

map() → list

Alias for builtins:map

max

max(value : list, case_sensitive=false : bool, attr=none : string) → any

Arguments

value
case_sensitive
Treat upper and lowercase strings as distinct.
attr
Get the object with the max value of this attribute.

Get the maximum value from a list

min

min(value : list, case_sensitive=false : bool, attr=none : string) → any

Arguments

value
case_sensitive
Treat upper and lowercase strings as distinct.
attr
Get the object with the min value of this attribute.

Get the minimum value from a list

namespace

namespace() → namespace

Create a namespace object. Namespace objects are mutable dictionary-like objects; the main use case for these is to work around the fact that {% for %} loops, macros, and other constructs establish local scopes, which means that any {% set %} invocations inside those will not propagate to the containing scope.

Using a namespace object, this problem can be solved like in this example:

{% set ns = namespace() %}
{% for x in items %}
  {{ x.bar }}
  {% set ns.foo = x.foo %}
{% endfor %}
{{ ns.foo }}

odd

odd(value : int) → bool

Arguments

value

Checks if value is an odd number.

random

random(value : list) → any

Arguments

value

Pick a random element from a list

reject

reject(value : list, filter=none : [string | filter | test | procedure], attribute=none : [string | none]) → list

Arguments

value
filter
A filter or test to apply to each element to determine whether to reject it or not.
attribute
If specified, the name of an attribute to extract from each element for testing. This argument can only be passed by keyword, not positionally.

Reject by a test or filter, and/or an attribute.

replace

replace(value : string, old : string, new : string, count=none : any) → string

Arguments

value
old
String to search for
new
Replacement
count
Maximum number of replacements.

String search-and-replace.

reverse

reverse(value : [list | string]) → [list | string]

Arguments

value

Reverse a list or string

round

round(value : float, precision=0 : int, method="common" : string) → [int | float]

Arguments

value
precision
method
One of common, ceil, floor.

Round a floating-point value.

safe

safe(value : string) → encoded

Arguments

value

Mark value as pre-encoded HTML.

select

select(value : list, filter=none : [string | filter | test | procedure], attribute=none : [string | none]) → list

Arguments

value
filter
A filter or test to apply to each element to determine whether to select it or not.
attribute
If specified, the name of an attribute to extract from each element for testing. This argument can only be passed by keyword, not positionally.

Select by a test or filter, and/or an attribute.

sort

sort(value : list, reverse=false : bool, case_sensitive=false : bool, attribute=none : any) → list

Arguments

value
reverse
case_sensitive
attribute

split

split(value : string, sep=none : string, maxsplit=none : int) → list

Arguments

value
sep
maxsplit
Maximum number of splits. Unlimited if not specified.

Split a string by a separator.

string

string(value : any) → string

Arguments

value

Convert argument to string

sum

sum(value : list, attr=none : string, start=none : int) → any

Arguments

value
attr
Use this attribute from each object in the list
start
Start at this offset into the list

Get the sum of the values in a list

title

title(value : string) → string

Arguments

value

Convert value to title case.

tojson

tojson(value : any, indent=none : any) → string

Arguments

value
indent

Convert value to JSON

upper

upper(value : string) → string

Arguments

value

Convert value to uppercase.

wordcount

wordcount(value : string) → int

Arguments

value

Counts words in value.

List Of Extension Globals

Expand

These are not available in Jinja

date

date(date : [string | list], format="%c" : string, tz=none : [string | int | list], locale=none : any) → string

Alias for dateformat

dateformat

dateformat(date : [string | list], format="%c" : string, tz=none : [string | int | list], locale=none : any) → string

Arguments

date
May be given as a formatted date, or as a list of `[ year, month, day, hours, minutes, seconds, timezone ]`. Partial lists will be padded with appropriate defaults.
format
tz
Time zone. May be given as a string specifying an offset (±HHMM), an integer offset in minutes, or a list containing 3 elements: offset in minues (int), summer-only (bool), and timezone name (string).
locale
Select a locale. Not yet implemented, ignored.

Format a date/time value. Format strings follow the specification found here: Date.Time.Format.formatTime Accepted input formats: - %Y-%m-%dT%H:%M:%S%Q%Z (2025-11-28T23:54:32.1234UTC) - %Y-%m-%d %H:%M:%S%Q (2025-11-28 23:54:32.1234UTC) - %Y-%m-%d %H:%M:%S%Q%z (2025-11-28 23:54:32.1234+0100) - %Y-%m-%d %H:%M:%S%Q%Z (2025-11-28 23:54:32.1234UTC) - %Y-%m-%d (2025-11-28)

help

help(value : any) → dict

Arguments

value

Get documentation for the given value, if available.

Module 'regex'

regex.match

match(regex : any, haystack : any, opts="" : any) → list

Arguments

regex
haystack
opts

Match a regular expression against a string. Returns an array where the first element is the entire match, and subsequent elements are matches on subexpressions (capture groups).

regex.matches

matches(regex : any, haystack : any, opts="" : any) → list

Arguments

regex
haystack
opts

Match a regular expression against a string. Returns an array of matches, where each match is an array where the first element is the entire match, and subsequent elements are matches on subexpressions (capture groups).

regex.test

test(regex : any, haystack : any, opts="" : any) → bool

Arguments

regex
haystack
opts

Match a regular expression against a string. Returns true if at least one match exists, false otherwise.

strip

strip(value : string, chars=none : string) → string

Arguments

value
chars
If specified: characters to strip.

Strip whitespace or selected characters from both ends of a string.

List Of Builtin Attributes

Expand

Bool

bool.bit_count

bit_count() → int

Bit count (popcount). Counts the number of set bits. Since a boolean only has one bit, this will always be either 0 or 1.

bool.denominator

bool.imag

bool.numerator

bool.real

bool.to_bytes

Int

int.bit_count

bit_count() → int

Bit count (popcount). Counts the number of set bits in an integer.

int.denominator

int.imag

int.numerator

int.real

Float

float.imag

float.real

String

string.capitalize

capitalize() → string

Convert value to title case.

string.casefold

casefold() → string

Convert value to canonical case for case-insensitive comparison

string.center

center(value : string, width=80 : int, fillchar=" " : string) → string

Arguments

value
width
fillchar

Pad string on both sides to center it in the given space

string.count

count(value : string, sub : string, start=0 : int, end=none : int) → int

Arguments

value
sub
Substring to search for
start
end

Count the number of occurrences of a substring.

string.encode

encode(value : string, encoding="utf-8" : string, errors="strict" : any) → encoded

Arguments

value
encoding
Encoding. One of ascii, utf8 (default), utf16le, utf16be, utf32le, utf32be
errors

Encode string into the selected encoding.

string.endswith

endswith(value : string, suffix : string, start=0 : int, end=none : int) → bool

Arguments

value
suffix
start
end

Check whether a string ends with a given suffix.

string.isalnum

isalnum() → bool

Check whether a string is alpha-numeric (a letter or a digit).

string.isalpha

isalpha() → bool

Check whether a string is alphabetic (consists solely of letters).

string.isascii

isascii() → bool

Check whether a string consists solely of 7-bit ASCII characters.

string.isdecimal

isdecimal() → bool

Check whether a string is a decimal number

string.isdigit

isdigit() → bool

Check whether a string consists solely of digits.

string.islower

islower() → bool

Check whether a string is all-lowercase

string.isprintable

isprintable() → bool

Check whether a string contains only printable characters.

string.isspace

isspace() → bool

Check whether a string contains only whitespace.

string.isupper

isupper() → bool

Check whether a string is all-uppercase.

string.join

join(value : string, iterable=[] : list) → string

Arguments

value
iterable

str.join(iterable) joins iterable into a string, using str as a separator.

string.length

string.lower

lower() → string

Convert value to lowercase.

string.lstrip

lstrip(value : any, chars=none : any) → string

Arguments

value
chars
If specified: characters to strip.

Strip whitespace or selected characters from the beginning of a string.

string.replace

replace(value : string, old : string, new : string, count=none : any) → string

Arguments

value
old
String to search for
new
Replacement
count
Maximum number of replacements.

String search-and-replace.

string.rstrip

rstrip(value : any, chars=none : any) → string

Arguments

value
chars
If specified: characters to strip.

Strip whitespace or selected characters from the end of a string.

string.split

split(value : string, sep=none : string, maxsplit=none : int) → list

Arguments

value
sep
maxsplit
Maximum number of splits. Unlimited if not specified.

Split a string by a separator.

string.splitlines

splitlines() → string

Split a string into lines.

string.startswith

startswith(value : string, prefix : string, start=0 : int, end=none : int) → bool

Arguments

value
prefix
start
end

Check whether a string starts with a given prefix.

string.strip

strip(value : string, chars=none : string) → string

Arguments

value
chars
If specified: characters to strip.

Strip whitespace or selected characters from both ends of a string.

string.title

title() → string

Convert value to title case.

string.upper

upper() → string

Convert value to uppercase.

List

Dict

dict.get

get(value : dict, key : scalar, default=none : any) → any

Arguments

value
key
default

Get an item from a dictionary.

dict.items

items() → list

Get a list of key/value pairs from dictionary value as a list

dict.keys

keys() → list

Get a list of all keys in dict value

dict.values

values() → list

Extract the values from dictionary value as a list

List Of Builtin Filters

Expand

These will only work in a filter context, not via procedure call syntax.

d

d(value : any, default : any) → any

Alias for default

default

default(value : any, default : any) → any

Arguments

value
default

Return default if value is false, none, or undefined, value otherwise.

List Of Builtin Tests

Expand

These will only work in a test context (e.g., an is-expression).

Some of these tests shadow globals of the same name but different functionality.

boolean

boolean(value : any) → bool

Arguments

value

Test whether value is a boolean.

callable

callable(value : any) → bool

Arguments

value

Test whether value is callable.

defined

defined(value : any) → bool

Arguments

value

Test whether a variable is defined.

eq

eq(value : any) → bool

Arguments

value

Test whether value is a eq.

escaped

false

false(value : any) → bool

Arguments

value

Test whether value is boolean false

filter

filter(value : any) → bool

Arguments

value

Test whether value is a filter.

float

float(value : any) → bool

Arguments

value

Test whether value is a float.

ge

ge(expr : any, arg : any) → any

Alias for [ >= ](#tests_ >= )

gt

gt(expr : any, arg : any) → any

Alias for [ > ](#tests_ > )

in

in(expr : any, arg : any) → any

Alias for [ in ](#tests_ in )

integer

integer() → bool

Test whether value is an integer.

iterable

iterable(value : any) → bool

Arguments

value

Test whether value is iterable. Lists and list-like native objects are iterable.

le

le(expr : any, arg : any) → any

Alias for [ <= ](#tests_ <= )

lower

lower(value : any) → bool

Arguments

value

Test whether value is an all-lowercase string

lt

lt(expr : any, arg : any) → any

Alias for [ < ](#tests_ < )

mapping

mapping(value : any) → bool

Arguments

value

Test whether value is a mapping. Mappings are dicts and dict-like native objects.

none

none(value : any) → bool

Arguments

value

Test whether value is the none value

number

number(value : any) → bool

Arguments

value

Test whether value is a number (integer or float).

sameas

sequence

sequence(value : any) → bool

Arguments

value

Test whether value is a sequence (i.e., a list).

string

string(value : any) → bool

Arguments

value

Test whether value is a string.

test

test(value : any) → bool

Arguments

value

Test whether value is a test.

true

true(value : any) → bool

Arguments

value

Test whether value is boolean true

undefined

undefined(value : any) → bool

Alias for defined

upper

upper(value : any) → bool

Arguments

value

Test whether value is an all-uppercase string.

Synopsis

Interpreting Templates

ginger Source #

Arguments

:: (Monad m, SplitGen g) 
=> TemplateLoader m

Template loader to use for loading the initial template and any included templates. For most use cases, fileLoader should be appropriate.

-> POptions

Parser options, determining parser behavior.

-> JinjaDialect

Jinja dialect; currently determines which built-in globals to load into the initial namespace.

-> g 
-> Encoder m

Encoder to use for automatic encoding. Use htmlEncoder for HTML templates.

-> Text

Name of the initial template to load. For the fileLoader, this should be a filename, but for other loaders, it can be whatever the loader expects.

-> Map Identifier (Value m)

Variables defined in the initial namespace.

-> m (Either RuntimeError Encoded) 

One-stop function for parsing and interpreting a template.

data GingerT (m :: Type -> Type) a Source #

The Ginger interpreter monad. Provides error reporting / handling via MonadError, an execution context (Context), and an evaluation state (EvalState).

Instances

Instances details
MonadTrans GingerT Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

lift :: Monad m => m a -> GingerT m a #

Monad m => MonadError RuntimeError (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

throwError :: RuntimeError -> GingerT m a #

catchError :: GingerT m a -> (RuntimeError -> GingerT m a) -> GingerT m a #

Monad m => Applicative (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

pure :: a -> GingerT m a #

(<*>) :: GingerT m (a -> b) -> GingerT m a -> GingerT m b #

liftA2 :: (a -> b -> c) -> GingerT m a -> GingerT m b -> GingerT m c #

(*>) :: GingerT m a -> GingerT m b -> GingerT m b #

(<*) :: GingerT m a -> GingerT m b -> GingerT m a #

Functor m => Functor (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

fmap :: (a -> b) -> GingerT m a -> GingerT m b #

(<$) :: a -> GingerT m b -> GingerT m a #

Monad m => Monad (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

(>>=) :: GingerT m a -> (a -> GingerT m b) -> GingerT m b #

(>>) :: GingerT m a -> GingerT m b -> GingerT m b #

return :: a -> GingerT m a #

Monad m => MonadReader (Context m) (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

ask :: GingerT m (Context m) #

local :: (Context m -> Context m) -> GingerT m a -> GingerT m a #

reader :: (Context m -> a) -> GingerT m a #

Monad m => MonadState (EvalState m) (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

get :: GingerT m (EvalState m) #

put :: EvalState m -> GingerT m () #

state :: (EvalState m -> (a, EvalState m)) -> GingerT m a #

class Eval (m :: Type -> Type) a where Source #

Eval represents types that can be evaluated in some 'GingerT m' monadic context.

Methods

eval :: a -> GingerT m (Value m) Source #

Instances

Instances details
Monad m => Eval m Expr Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Expr -> GingerT m (Value m) Source #

Monad m => Eval m Statement Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Statement -> GingerT m (Value m) Source #

Monad m => Eval m Template Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Template -> GingerT m (Value m) Source #

data RuntimeError Source #

Constructors

ArgumentError 

Fields

  • Text

    Callee

  • Text

    Argument (position or name)

  • Text

    Expected argument

  • Text

    Actual argument

TagError 

Fields

  • Text

    Identifier object context

  • Text

    Expected type(s)

  • Text

    Actual type

NonCallableObjectError Text

Object that was attempted to be used as a callable

NotInScopeError Text

Identifier

NotImplementedError Text

The thing that isn't implemented

NumericError 

Fields

  • Text

    Identifier object context

  • Text

    Error description

TemplateFileNotFoundError Text

Template name

TemplateParseError 

Fields

FatalError Text 
PositionedError !SourcePosition !RuntimeError 

Instances

Instances details
Exception RuntimeError Source # 
Instance details

Defined in Language.Ginger.RuntimeError

Show RuntimeError Source # 
Instance details

Defined in Language.Ginger.RuntimeError

Eq RuntimeError Source # 
Instance details

Defined in Language.Ginger.RuntimeError

Applicative m => ToNativeProcedure m (m (Either RuntimeError (Value m))) Source # 
Instance details

Defined in Language.Ginger.Value

Monad m => MonadError RuntimeError (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

throwError :: RuntimeError -> GingerT m a #

catchError :: GingerT m a -> (RuntimeError -> GingerT m a) -> GingerT m a #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => FnToValue (Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

data Context (m :: Type -> Type) Source #

Instances

Instances details
Monad m => MonadReader (Context m) (GingerT m) Source # 
Instance details

Defined in Language.Ginger.Interpret.Type

Methods

ask :: GingerT m (Context m) #

local :: (Context m -> Context m) -> GingerT m a -> GingerT m a #

reader :: (Context m -> a) -> GingerT m a #

defContext :: forall (m :: Type -> Type). Monad m => Context m Source #

data Env (m :: Type -> Type) Source #

Constructors

Env 

Fields

Instances

Instances details
Monoid (Env m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

mempty :: Env m #

mappend :: Env m -> Env m -> Env m #

mconcat :: [Env m] -> Env m #

Semigroup (Env m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

(<>) :: Env m -> Env m -> Env m #

sconcat :: NonEmpty (Env m) -> Env m #

stimes :: Integral b => b -> Env m -> Env m #

Eq (Env m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

(==) :: Env m -> Env m -> Bool #

(/=) :: Env m -> Env m -> Bool #

Ord (Env m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

compare :: Env m -> Env m -> Ordering #

(<) :: Env m -> Env m -> Bool #

(<=) :: Env m -> Env m -> Bool #

(>) :: Env m -> Env m -> Bool #

(>=) :: Env m -> Env m -> Bool #

max :: Env m -> Env m -> Env m #

min :: Env m -> Env m -> Env m #

emptyEnv :: forall (m :: Type -> Type). Env m Source #

defEnv :: forall (m :: Type -> Type). Monad m => Env m Source #

defVars :: forall (m :: Type -> Type). Monad m => Map Identifier (Value m) Source #

defVarsCompat :: forall (m :: Type -> Type). Monad m => Map Identifier (Value m) Source #

AST

data Statement Source #

A statement in the template language.

Constructors

PositionedS !SourcePosition !Statement

Statement tagged with a source position

ImmediateS !Encoded

Bare text written in the template, outside of any curly braces

InterpolationS !Expr

An expression interpolation: {{ expr }}

CommentS !Text

Comment: {# comment text #}

ForS !(Maybe Identifier) !Identifier !Expr !(Maybe Expr) !Recursivity !Statement !(Maybe Statement)

@@ {% for keyVar, valueVar in iteree if loopCondition recursive %} body {% else %} body if empty {% endfor %} @@

IfS !Expr !Statement !(Maybe Statement)
{% if condition %}yes branch{% else %}no branch{% endif %}
MacroS !Identifier ![MacroArg] !Statement
{% macro name(args) %}body{% endmacro %}
CallS !Identifier ![Expr] ![(Identifier, Expr)] !Statement
{% call macroName(args) %}body{% endcall %}
FilterS !Identifier ![Expr] ![(Identifier, Expr)] !Statement
{% filter filterName(args, kwargs) %}body{% endfilter %}
SetS !SetTarget !Expr
{% set name=expr %}
SetBlockS !SetTarget !Statement !(Maybe Expr)
{% set name %}body{% endset %}
IncludeS !Expr !IncludeMissingPolicy !IncludeContextPolicy
{% include includee ignore missing with context %}
ImportS !Expr !(Maybe Identifier) !(Maybe [(Identifier, Maybe Identifier)]) !IncludeMissingPolicy !IncludeContextPolicy
{% import importee as localName item, other_item as other ignore missing with context %}
BlockS !Identifier !Block
{% block name with scope required %}body{% endblock %}
WithS ![(Identifier, Expr)] !Statement
{% with defs %}body{% endwith %}
GroupS ![Statement]

Group of statements; not parsed, but needed for combining statements sequentially.

Instances

Instances details
Arbitrary Statement Source # 
Instance details

Defined in Language.Ginger.AST

Show Statement Source # 
Instance details

Defined in Language.Ginger.AST

Eq Statement Source # 
Instance details

Defined in Language.Ginger.AST

Ord Statement Source # 
Instance details

Defined in Language.Ginger.AST

RenderSyntax Statement Source # 
Instance details

Defined in Language.Ginger.Render

Monad m => Eval m Statement Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Statement -> GingerT m (Value m) Source #

data Expr Source #

An expression. Expressions can occur in interpolations ({{ ... }}), and in various places inside statements.

Constructors

PositionedE !SourcePosition !Expr 
NoneE 
BoolE !Bool 
StringLitE !Text 
IntLitE !Integer 
FloatLitE !Double 
StatementE !Statement 
ListE !(Vector Expr) 
DictE ![(Expr, Expr)] 
UnaryE !UnaryOperator !Expr

@UnaryE op rhs

BinaryE !BinaryOperator !Expr !Expr

@BinaryE op lhs rhs

SliceE !Expr !(Maybe Expr) !(Maybe Expr)

@SliceE slicee start length

DotE !Expr !Identifier

@DotE lhs rhs

IsE !Expr !Expr ![Expr] ![(Identifier, Expr)]
IsE scrutinee test args kwargs
CallE !Expr ![Expr] ![(Identifier, Expr)]
CallE callee args kwargs
FilterE !Expr !Expr ![Expr] ![(Identifier, Expr)]
FilterE arg0 filter args kwargs
TernaryE !Expr !Expr !Expr
TernaryE cond yes no
VarE !Identifier 

Instances

Instances details
Arbitrary Expr Source # 
Instance details

Defined in Language.Ginger.AST

Methods

arbitrary :: Gen Expr #

shrink :: Expr -> [Expr] #

Show Expr Source # 
Instance details

Defined in Language.Ginger.AST

Methods

showsPrec :: Int -> Expr -> ShowS #

show :: Expr -> String #

showList :: [Expr] -> ShowS #

Eq Expr Source # 
Instance details

Defined in Language.Ginger.AST

Methods

(==) :: Expr -> Expr -> Bool #

(/=) :: Expr -> Expr -> Bool #

Ord Expr Source # 
Instance details

Defined in Language.Ginger.AST

Methods

compare :: Expr -> Expr -> Ordering #

(<) :: Expr -> Expr -> Bool #

(<=) :: Expr -> Expr -> Bool #

(>) :: Expr -> Expr -> Bool #

(>=) :: Expr -> Expr -> Bool #

max :: Expr -> Expr -> Expr #

min :: Expr -> Expr -> Expr #

RenderSyntax Expr Source # 
Instance details

Defined in Language.Ginger.Render

Monad m => Eval m Expr Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Expr -> GingerT m (Value m) Source #

data Template Source #

A template consists of an optional parent template (specified in the source using the {% extends %} construct), and a body statement.

Constructors

Template 

Instances

Instances details
Show Template Source # 
Instance details

Defined in Language.Ginger.AST

Eq Template Source # 
Instance details

Defined in Language.Ginger.AST

RenderSyntax Template Source # 
Instance details

Defined in Language.Ginger.Render

Monad m => Eval m Template Source # 
Instance details

Defined in Language.Ginger.Interpret.Eval

Methods

eval :: Template -> GingerT m (Value m) Source #

data Block Source #

A block represents a section of a template that can be overridden in derived templates ("template inheritance").

Constructors

Block 

Instances

Instances details
Show Block Source # 
Instance details

Defined in Language.Ginger.AST

Methods

showsPrec :: Int -> Block -> ShowS #

show :: Block -> String #

showList :: [Block] -> ShowS #

Eq Block Source # 
Instance details

Defined in Language.Ginger.AST

Methods

(==) :: Block -> Block -> Bool #

(/=) :: Block -> Block -> Bool #

Ord Block Source # 
Instance details

Defined in Language.Ginger.AST

Methods

compare :: Block -> Block -> Ordering #

(<) :: Block -> Block -> Bool #

(<=) :: Block -> Block -> Bool #

(>) :: Block -> Block -> Bool #

(>=) :: Block -> Block -> Bool #

max :: Block -> Block -> Block #

min :: Block -> Block -> Block #

Representing Values

data Value (m :: Type -> Type) Source #

A value, as using by the interpreter.

Constructors

ScalarV !Scalar 
ListV !(Vector (Value m)) 
DictV !(Map Scalar (Value m)) 
NativeV !(NativeObject m) 
ProcedureV !(Procedure m) 
TestV !(Test m) 
FilterV !(Filter m) 
MutableRefV !RefID 

Instances

Instances details
Applicative m => ToNativeProcedure m (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => ToNativeProcedure m (m (Either RuntimeError (Value m))) Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => ToNativeProcedure m (m (Value m)) Source # 
Instance details

Defined in Language.Ginger.Value

(Applicative m, ToNativeProcedure m a) => ToNativeProcedure m (Value m -> a) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

toNativeProcedure :: (Value m -> a) -> [(Maybe Identifier, Value m)] -> Context m -> SomePRNG -> m (Either RuntimeError (Value m)) Source #

Monad m => Arbitrary (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

arbitrary :: Gen (Value m) #

shrink :: Value m -> [Value m] #

FromJSON (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

ToJSON (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

IsString (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fromString :: String -> Value m #

Show (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

showsPrec :: Int -> Value m -> ShowS #

show :: Value m -> String #

showList :: [Value m] -> ShowS #

PrintfArg (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Eq (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

(==) :: Value m -> Value m -> Bool #

(/=) :: Value m -> Value m -> Bool #

Ord (Value m) Source # 
Instance details

Defined in Language.Ginger.Value

Methods

compare :: Value m -> Value m -> Ordering #

(<) :: Value m -> Value m -> Bool #

(<=) :: Value m -> Value m -> Bool #

(>) :: Value m -> Value m -> Bool #

(>=) :: Value m -> Value m -> Bool #

max :: Value m -> Value m -> Value m #

min :: Value m -> Value m -> Value m #

RenderSyntax (Value m) Source # 
Instance details

Defined in Language.Ginger.Render

Applicative m => FromValue (Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

ToValue (Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

toValue :: Value m -> Value m Source #

Applicative m => FnToValue (Value m -> Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> Value m) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> Value m -> Value m) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> Value m -> Value m) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> Value m -> m (Value m)) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> Value m -> m (Value m)) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> Value m -> m (Value m)) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> Value m -> m (Value m)) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> m (Either RuntimeError (Value m))) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> Value m -> m (Value m)) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> Value m -> m (Value m)) -> Value m Source #

Applicative m => FnToValue (Value m -> Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => FnToValue (Value m -> Value m -> m (Value m)) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> Value m -> m (Value m)) -> Value m Source #

Applicative m => FnToValue (Value m -> m (Either RuntimeError (Value m))) m Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => FnToValue (Value m -> m (Value m)) m Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fnToValue :: ObjectID -> Maybe ProcedureDoc -> (Value m -> m (Value m)) -> Value m Source #

data Scalar Source #

Instances

Instances details
Arbitrary Scalar Source # 
Instance details

Defined in Language.Ginger.Value

FromJSON Scalar Source # 
Instance details

Defined in Language.Ginger.Value

FromJSONKey Scalar Source # 
Instance details

Defined in Language.Ginger.Value

ToJSON Scalar Source # 
Instance details

Defined in Language.Ginger.Value

ToJSONKey Scalar Source # 
Instance details

Defined in Language.Ginger.Value

IsString Scalar Source # 
Instance details

Defined in Language.Ginger.Value

Methods

fromString :: String -> Scalar #

Show Scalar Source # 
Instance details

Defined in Language.Ginger.Value

Eq Scalar Source # 
Instance details

Defined in Language.Ginger.Value

Methods

(==) :: Scalar -> Scalar -> Bool #

(/=) :: Scalar -> Scalar -> Bool #

Ord Scalar Source # 
Instance details

Defined in Language.Ginger.Value

ToScalar Scalar Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => FromValue Scalar m Source # 
Instance details

Defined in Language.Ginger.Value

ToValue Scalar a Source # 
Instance details

Defined in Language.Ginger.Value

Methods

toValue :: Scalar -> Value a Source #

(Monad m, FromValue a m) => FromValue (Map Scalar a) m Source # 
Instance details

Defined in Language.Ginger.Value

newtype Encoded Source #

Represents an encoded string value, as opposed to a raw (unencoded) string, which we represent as a plain Text.

Constructors

Encoded 

Fields

Instances

Instances details
Arbitrary Encoded Source # 
Instance details

Defined in Language.Ginger.AST

Monoid Encoded Source # 
Instance details

Defined in Language.Ginger.AST

Semigroup Encoded Source # 
Instance details

Defined in Language.Ginger.AST

Show Encoded Source # 
Instance details

Defined in Language.Ginger.AST

Eq Encoded Source # 
Instance details

Defined in Language.Ginger.AST

Methods

(==) :: Encoded -> Encoded -> Bool #

(/=) :: Encoded -> Encoded -> Bool #

Ord Encoded Source # 
Instance details

Defined in Language.Ginger.AST

prettyRuntimeError :: RuntimeError -> String Source #

Pretty-print a RuntimeError. The output is meant to be useful as a user-facing error message.

newtype Identifier Source #

Identifiers are used to represent variable names and object fields.

Constructors

Identifier 

Fields

Instances

Instances details
Arbitrary Identifier Source # 
Instance details

Defined in Language.Ginger.AST

FromJSON Identifier Source # 
Instance details

Defined in Language.Ginger.AST

FromJSONKey Identifier Source # 
Instance details

Defined in Language.Ginger.AST

ToJSON Identifier Source # 
Instance details

Defined in Language.Ginger.AST

ToJSONKey Identifier Source # 
Instance details

Defined in Language.Ginger.AST

IsString Identifier Source # 
Instance details

Defined in Language.Ginger.AST

Show Identifier Source # 
Instance details

Defined in Language.Ginger.AST

Eq Identifier Source # 
Instance details

Defined in Language.Ginger.AST

Ord Identifier Source # 
Instance details

Defined in Language.Ginger.AST

RenderSyntax Identifier Source # 
Instance details

Defined in Language.Ginger.Render

ToScalar Identifier Source # 
Instance details

Defined in Language.Ginger.Value

Applicative m => FromValue Identifier m Source # 
Instance details

Defined in Language.Ginger.Value

ToValue Identifier a Source # 
Instance details

Defined in Language.Ginger.Value

Configuration

type Encoder (m :: Type -> Type) = Text -> m Encoded Source #

Parser and Parser Options

data POptions Source #

Instances

Instances details
Read POptions Source # 
Instance details

Defined in Language.Ginger.Parse

Show POptions Source # 
Instance details

Defined in Language.Ginger.Parse

Eq POptions Source # 
Instance details

Defined in Language.Ginger.Parse

data BlockTrimming Source #

Constructors

NoTrimBlocks 
TrimBlocks 

Instances

Instances details
Bounded BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

Enum BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

Read BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

Show BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

Eq BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

Ord BlockTrimming Source # 
Instance details

Defined in Language.Ginger.Parse

data BlockStripping Source #

Constructors

NoStripBlocks 
StripBlocks 

Instances

Instances details
Bounded BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Enum BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Read BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Show BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Eq BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Ord BlockStripping Source # 
Instance details

Defined in Language.Ginger.Parse

Template Loaders

type TemplateLoader (m :: Type -> Type) = Text -> m (Maybe Text) Source #