ViUR Logics: A Python-style expressional language and template engine
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore
CHANGELOG.md
LICENSE
Makefile
README.md
__init__.py
logics.par
logics.py
parser.py
persons.json
persons.vistache
test.json
utility.py
vistache-test.py
vistache.py

README.md

ViUR logics & vistache

logics is a domain-specific, embeddable expressional language with a Python-style syntax.

vistache is an easy-to-use template engine powered by logics expressions.

About

The initial intention behind logics was to serve a well-known syntax for expressing validity checks across all ViUR modules and execution platforms. This starts from the administration tools to server-side input checking as well as client-side input forms and user-defined template processing.

The first version of logics was intended to allow both direct expression execution and expression compilation into native JavaScript code, to be executed on client-side without the need of a logics interpreter. This feature has been disabled for now, but may be re-implemented in future when needed.

logics is not intended to be a scripting language! Therefore it neither provides direct variable assignment, nor control structures like loops or jumps - except comprehensions.

Moreover, it is a language and tool for...

  • ...expressing validity checks,
  • ...performing custom calculations,
  • ...providing customizable templating features,
  • ...making data-driven decisions in a restricted and secure runtime context.

Usage

logics.py can be used as a command-line tool for invocation and testing.

usage: logics.py [-h] [-D] [-e] [-v var value] [-r] [-V] expression

ViUR Logics Expressional Language

positional arguments:
  expression            The expression to be processed

optional arguments:
  -h, --help            show this help message and exit
  -D, --debug           Print debug output
  -e, --environment     Import environment as variables
  -v var value, --var var value
                        Assign variables
  -r, --run             Run expression using interpreter
  -V, --version         show program's version number and exit

Building

The logics parser is implemented using the UniCC parser generator and its newly established Python support. Install UniCC as instructed in its README, or download a setup for your platform. Then, run make to build the logics parser.

Examples

Literals

"Hello World"
2016
23.5
True
[1,2,3]

Simple arithmetic expressions

23 / 5 + (1337 - 42)

Concatenate current content of a field (variable) with a string literal

myfield + " is my value!"

Add enforced string content lengths of two fields firstname and lastname and test them for a total length greater than 32 characters

len(str(firstname)) + len(str(lastname)) > 32

Check if current content of field (variable) named degree is filled, and mother or father, or current integer value of field age is greater-equal 21 and lower-equal 42.

(degree and degree in ["mother", "father"]) or (int(age) >= 21 and int(age) <= 42)

Comprehensions are supported as well

sum([x for x in [10, 52, 18.4, 99, 874, 13, 86] if x > 25]) # Sum all values higher 25

Logics-based dependency checks in ViUR

The latest versions of ViUR vi supports logics to dynamically change input mask behavior depending on input data.

The logics expressions are triggered on an event base, when input field contents are changed.

The following events are supported so far:

  • logic.visibleIf sets the field visible when the expression returns True
  • logic.readonlyIf sets the field read-only when the expression returns True
  • logic.evaluate sets the field's value according to the provided expression

The expressions are provided by extending skeleton bones to specific expressions on the particular event.

class fieldSkel(Skeleton):
    type = selectBone(
        descr="Type",
        values={
            "none": u"None",
            "text": u"Text (single line)",
            "memo": u"Text (multi-line)",
            "select": u"Selection field"
        },
        required=True, defaultValue="level"
    )
    value = stringBone(
        descr="Default value",
        params={"logic.visibleIf": 'type != "none"'}
    )
    entries = stringBone(
        descr="Possible values",
        params={"logic.visibleIf": 'type == "select"'},
        multiple=True
    )
    required = booleanBone(
        descr="Required",
        params={"logic.visibleIf": 'type in ["text", "memo"]'},
        defaultValue=False
    )
    multiple = booleanBone(
        descr="Multiple entries",
        params={"logic.visibleIf": 'type in ["text", "memo", "select"]'},
        defaultValue=False
    )

Vistache, the template engine

Vistache Editor

Vistache is an extension built on top of logics, providing an easy-to-use template language with a Mustache-like syntax. Likewise the original Mustache, a template is first compiled into an executable representation, then it can be rendered with variable data.

Instead of just outputting variables and performing conditional or iterative blocks, Vistache allows to use full logics expressions as shown in the example below.

Vistache expressions:

  • {{expression}} renders the result of expression
  • {{#expression}}...{{/}} renders the block between {{#expression}} and the {{/}} if the expression validates to true. It also loops over the block when the expression results in a list, with a context-related sub-scoping.
  • {{#expression}}...{{|}}...{{/}} renders the block between the {{#expression}} and the {{|}} if the expression validates to true, otherwise it renders the block between the {{|}} and {{/}}. It also loops over the first block when the expression results in a list, with a context-related sub-scoping.

In case of a loop in the conditional blocks above, a variable loop is also made available in each scope, containing the following members:

  • loop.length is the number of items that are looped,
  • loop.item is the full context-based variable,
  • loop.index is the loop conter starting at 1,
  • loop.index0 is the loop conter starting at 0,
  • loop.first is true on the first loop,
  • loop.last is true on the last loop.

Running the template

{{#persons}}Hello {{firstname}}
	{{#city}} from {{city}}{{/}}!

	{{# dogs and len(dogs) }}
		You have {{len(dogs)}} dog{{ "s" if len(dogs) > 1 else "" }} named
		{{#dogs}}
			{{#loop.last and not loop.first}} and
			{{/}}
			{{loop.item}}
			{{#loop.index < len(dogs) - 1}},
			{{/}}
		{{/}}
	{{|}}
		There is no dog living with you.
	{{/}}
{{/}}

with the JSON object

[
	{
		"firstname": "John",
		"city": "Johannesburg"
	},
	{
		"firstname": "Bernd",
		"dogs": ["Doge"]
	},
	{
		"firstname": "Max",
		"city": "Dortmund",
		"dogs": ["Shugar", "Kira", "Akela"]
	}
]

results in the following output:

Hello John from Johannesburg!
        There is no dog living with you.
Hello Bernd!
        You have 1 dog named Doge
Hello Max from Dortmund!
        You have 3 dogs named Shugar, Kira and Akela

Try it out by calling

python vistache.py -v persons persons.json -r persons.vistache

from a command-line.

Contributing

We take a great interest in your opinion about ViUR. We appreciate your feedback and are looking forward to hear about your ideas. Share your visions or questions with us and participate in ongoing discussions.

Credits

ViUR is developed and maintained by Mausbrand Informationssysteme GmbH, from Dortmund in Germany. We are a software company consisting of young, enthusiastic software developers, designers and social media experts, working on exciting projects for different kinds of customers. All of our newer projects are implemented with ViUR, from tiny web-pages to huge company intranets with hundreds of users.

Help of any kind to extend and improve or enhance this project in any kind or way is always appreciated.

License

Copyright (C) 2012-2018 by Mausbrand Informationssysteme GmbH.

Mausbrand and ViUR are registered trademarks of Mausbrand Informationssysteme GmbH.

You may use, modify and distribute this software under the terms and conditions of the GNU Lesser General Public License (LGPL). See the file LICENSE provided within this package for more information.