Labmdas

Lambdas are collections.abc.Callable values found in the template rendering scope that are called when referenced, allowing complext context-aware rendering logic to be implemented.

Lambda variables

As part of standard Mustache lambda extension, any collections.abc.Callable variable will be invoked when used as a variable, and its return value will be rendered as a template.

This is the simplest type of lambda.

import mstache

print(mstache.render(
    '{{lambda}} world!',
    {
        'lambda': lambda: '{{hello}}',
        'hello': 'Hello',
        },
    ))
# Hello world!

Lambda blocks

If a lambda is invoked as a block, the content of said block will be passed to the collections.abc.Callable as parameter.

{{#lambda}}content{{/lambda}}

There are currently two different ways of implement lambda blocks.

Explicit render mode

Also known as chevron-style, current default behavior, the lambda collections.abc.Callable will expect two parameters, template and render, and its return value will be included in the template as a value.

This means that any template rendering must happen by explicitly calling the received render function, which works in the current scope and inherits the configuration of the current rendering context, and then returned.

import mstache

print(mstache.render(
    '{{#lambda}}content{{/lambda}} world!',
    {
        'lambda': lambda content, render: (
            # explicit render: return render result
            render('{{' + content + '}}')
            ),
        'content': 'Hello',
        },
    ))
# Hello world!

Implicit render mode

Also known as Mustache-style, enabled by passing lambda_render=None, the lambda collections.abc.Callable will expect a single template parameter, and its return value will be as template, and rendered, before being incuded in the output.

import mstache

print(mstache.render(
    '{{#lambda}}content{{/lambda}} world!',
    {
        'lambda': lambda content: (
            # implicit render: return template
            '{{' + content + '}}'
            ),
        'content': 'Hello',
        },
    lambda_render=None,
    ))
# Hello world!

Virtual properties

Virtual properties are, essentially, generic object property lambdas.

They are useful for when typical template lambdas, which receive template data, can’t effectively cover operations made with objects in the rendering scope.

This was traditionally done by patching JavaScript prototypes, but that kind of object manipulation is considered unsafe in Python.

To mitigate this, mstache.default_getter() can receive a mapping of virtual properties to be made available under any scope, effectively functioning as injected property getters.

While you can provide your own getter function to mstache.render(), it’s simpler to just wrap mstache.default_getter() via functools.partial() to include extra virtual properties, extending those from mstache.default_virtuals.

import functools
import mstache

print(mstache.render(
    '{{text.word_count}} words',
    {'text': 'virtual properties are cool'},
    getter=functools.partial(
        mstache.default_getter,
        virtuals={
            **mstache.default_virtuals,
            'word_count': lambda text: len(text.split()),
            },
        ),
    ))
# 4 words

Please note both AttributeError and TypeError exceptions raised from virtual property functions are appropriately ignored by by mstache.default_getter().