Fork me on GitHub

Introduction

Cadenza is a text templating language. The reason for pointing out that it is a "text" templating language is so that you realize that it can apply to any kind of text document out there, from the HTML documents you'll likely be using it for to emails, to source code, to anything else - Cadenza doesn't care what kind of text document it's working on.

That said, Cadenza was designed with HTML pages in mind so most of this document will refer to using Cadenza with HTML. If you haven't had a chance to learn any HTML before I'd suggest learning the basics as it's a very easy language to learn and this document will probably make more sense after you have had a chance to do so.

As well, this document discusses the standard Cadenza rendering stack. For developers this means using the Cadenza::Lexer, Cadenza::Parser and Cadenza::TextRenderer classes which are included in the standard Cadenza library. Depending on how your system is set up the details discussed in this document may not apply.

Basics

Cadenza primarily uses two kinds of tags to mark up it's content as a template.

The first kind is used to inject some kind of value into your output document. These are called inject tags and always start with a double left curly bracket {{ and end with a double right curly bracket }}. The stuff that comes between the brackets defines what you want to inject into your document. We will discuss Inject Tags more later.

The second kind of tag is called a control tag. These tags are used to control the path through your template that Cadenza takes to render it.

Control tags always start with a single left curly bracket followed by a percent symbol: {%. Likewise the end of a control tag is the opposite of what they start with: a percent symbol followed by a right curly bracket: %}.

Some control tags come in pairs or even triplets - there's a lot of different kinds! These control tags form what we call a block, which will render differently depending on how the template is set up. Don't worry, we will go into more detail in later sections.

Comments

You can insert comments into your templates by placing them between a left curly brace followed by a number sign {# and a number sign followed by a right curly brace #}. The comment doesn't show up in the output at all!

Here's an example of comments:

>> 123{# this won't be in the output #}abc
=> 123abc

Literals

Literals are constant values that you can use inside your template tags. In Cadenza literals can be either a number or a string.

Numbers

Numbers are any integer or real numerical value.

>> {{ 123 }}
=> 123
>> {{ 3.14159 }}
=> 3.14159

Strings

Strings refer to a "string of characters", you can enter them in by wrapping your words and spaces with either a double quote " or single quote '.

>> {{ 'Hello World!' }}
=> Hello World!
>> {{ "I'm writing Cadenza!" }}
=> I'm writing Cadenza!

Variables

Variables are different from literals because they don't have a constant value (like literals do) but hold the place for some value that changes each time you render your template (they vary). Variables come in the form of a name (also known as an identifier) which represents the value of an object.

Variable names may begin with uppercase or lowercase latin characters (A-Z) or an underscore _ and, after the first character, include arabic numerical digits (0-9). So, for instance, the following are valid identifiers:

{{ foo }}
{{ hello123 }}
{{ _var }}
{{ MyVariable }}

However, the following examples are not:

{# invalid because it starts with a digit #}
{{ 9abc }}

{# invalid because it contains a hyphen #}
{{ foo-bar }}

Variable names are case sensitive when being looked up, meaning that the same name with different capital letters are treated as entirely different variable names. For example: HelloWorld and helloWorld are treated as separate variable names.

Inject tags

Inject tags are used to insert values into your template while rendering. An inject tag generally looks something like this:

{{ name | upper }}

In this example the variable named "name" is injected into the text but is first converted to upper case by using the "upper" filter. Filters are entirely optional, meaning that the most basic inject tag looks like this:

{{ name }}

When you do want to use a filter just insert a pipe character | and then give the name of your filter.

Filters can actually be applied to any value inside a inject tag or a control tag so the following is a valid tag:

{#
   this very crazy example could be used to center the name in spaces
   with padding equal to the largest name.  Example:

   -------
   Stephen
    Mike 
     Ben
   Michael
   -------

   Most of the time your tags shouldn't have to get this complicated 
   however :)
#}
{{ name | center: (names | map: "length" | sort | reverse | limit: 1) }}

If you're wondering what filters are available then you can have a look at the standard filter reference. When using Cadenza, programmers can also write custom filters for you to use, for information about writing custom filters consult the programmer's reference.

As seen above some filters take a list of parameters which change the way they work. When providing parameters add a colon : to the end of your filter name and then give your parameters separated by commas. Here are some examples:

>> {{ name | upper }}
=> JOHN DOE
>> {{ name | upper | cut: "DOE" }}
=> JOHN 
>> {{ name | center: 20 }}
=>       John Doe      
>> {{ name | center: 20, "-" }}
=> ------John Doe------

Variables also sometimes come in the form of a function, which means that each time you call them you may get a different result. These variables are called functional variables. Functional variables can also take a list of parameters which can further modify the result. For example, the load function will insert the text from another template without rendering it:

>> {{ load "partials/lorem-ipsum.cadenza" | wordwrap: 57 }}
=> <p>Lorem ipsum dolor sit amet, consectetur adipiscing
=> elit. Etiam congue dictum nulla, quis posuere ipsum
=> venenatis eu. Maecenas mi justo, commodo porta eleifend
=> vitae, semper quis erat. Aliquam elit ante, commodo in
=> convallis vitae, fermentum sit amet elit. Phasellus
=> fringilla risus scelerisque nibh tempus rhoncus.</p>

For a full list of the functional variables you can use have a look at the standard functional variables reference. You can also define your own functional variables in Cadenza, see the programmer's reference for details.

Arithmetic

When you need to you can perform arithmetic operations on your constants and variables. You can add using the plus symbol (+), subtract using the minus symbol (-), multiply using the asterisk symbol (*) and divide using the slash symbol (/).

Arithmetic is evaluated using the standard order of operations for mathematics (Brackets, Divison & Multiplication, Addition & Subtraction).

Here's an example of some arithmetic being used in inject tags:

>> {{ 123 + 456 }}
=> 579
>> {{ 1 + 2 * 3 - 4 / 5 }}
=> 7
>> {{ (1 + 2) * ((3 - 4) / 5) }}
=> -3
>> {{ "a" * 3 }}
=> aaa
>> {{ (alphabet | length) - 1 }}
=> 25

It can be used anywhere you need to supply a value, for example, in filter parameters:

>> {{ lorem_ipsum | wordwrap: 5 + 30 }}
=> Lorem ipsum dolor sit amet,
=> consectetur adipisicing elit

If Statements

If statements are a kind of control tag that provide you a way to control whether or not Cadenza will render a certain section of your template. To determine this if statements must contain an expression which Cadenza will evaluate.

If statements are constructed like this:

{% if expression %}
   ...
{% else %}
   ...
{% endif %}

You can see that unlike most blocks the if statement can have two blocks separated by an {% else %} tag. The else tag and the block which follows it is optional, so the simplest form of an if statement looks like this:

{% if expression %}
   ...
{% endif %}

Depending on how the expression evaluates the different blocks will be rendered. If the expression evaluates to true then the first block will be rendered:

>> {% if something_true %}
>>    It was true!
>> {% else %}
>>    It was false!
>> {% endif %}
=> 
=>    It was true!
=> 

When the expression evaluates to false then the second block will be rendered:

>> {% if something_false %}
>>    It was true!
>> {% else %}
>>    It was false!
>> {% endif %}
=> 
=>    It was false!
=> 

Of course, if no {% else %} block is provided and the expression evaluates to false then nothing will be rendered at all:

>> {% if something_false %}
>>    It was true!
>> {% endif %}
=> 

Expressions

Expressions are conditions you can use to express some kind of logic in a way that Cadenza can understand.

An expression is made up of a list of terms, each of which has two values which you are comparing using a symbol called a comparator.

{% if a < b %}
{% if 3 > 2 %}
{% if pi == 3.14159 %}

Cadenza supports all of the following comparators:

Comparator Example Description
Equality a == b Evaluates true if a is equal to b
Greater Than a > b Evaluates true if a is greater than b
Less Than a < b Evaluates true if a is less than b
Greater Than or Equal To a >= b Evaluates true if a is greater than b or a equals b
Less Than or Equal To a <= b Evaluates true if a is less than b or a equals b

If you want to use more than one term in an expression then you'll have to include a conjunction. Conjunctions are words which describe what the two terms must evaluate to to be true overall.

{% if a > b and b > c %}
{% if amount == 1 or amount == "one" %}

Cadenza supports the following conjunctions:

Conjunction Example Description
and {% if a and b %} The expression is true if both a and b are true
or {% if a or b %} The expression is true if either a or b are true

When you want to invert the logic in your expressions you can use the not keyword. If you want to invert the whole expression you can use the unless keyword instead of the if keyword.

{# these two expressions are logically equivalent #}
{% if not (a > b and b > c) %}
{% unless a > b and b > c %}

Loops

Sometimes you'll want to continually re-render the same section of template for a set of items. For instance perhaps you'll want a table with a row for each piece of data you're trying to show.

"For statements" allow you to continually output some text for every element in a list. Here's what for statements look like:

<ol>
   {% for error in errors %}
   <li>{{ error }}</li>
   {% endfor %}
</ol>

You can see here that "for statements" are blocks, just like "if statements" are. The general syntax for writing a "for statement" is:

{% for x in y %}
   ...
{% endfor %}

"Y" is a variable we call the Enumerable. The enumerable should be some kind of object which contains or can generate. In programming we usually call this a list or an array.

Regardless, we also have the variable "X" above. "X" is called the enumerator variable and you can name it whatever you want.

By convention, most people will name the Enumerable as the plural form of whatever the enumerable contains and name the Enumerator whatever the singular form of the enumerable. In other words you will often see an enumerable named something like "items" and an enumerator named "item". Of course, this is just a suggestion and you can use whatever names you want.

The enumerator also defines some magic variables on itself which you may find useful when working with a for loop. Here's a list of them:

forloop.counter
Gives you the number of times the loop has been processed.
forloop.counter0
Like counter but assumes the first loop is loop #0, not loop #1.
forloop.first
Gives you a true value if this is the first iteration through a loop.
forloop.last
Gives you a true value if this is the last iteration through a loop.

So, with these variables you could write a HTML table like this:

<table class="centered">
   <thead>
      <tr>
         <th>x</th>
         <th>x.counter</th>
         <th>x.counter0</th>
         <th>x.first</th>
         <th>x.last</th>
      </tr>
   </thead>
   <tbody>
   {% for x in alphabet %}
      <tr>
         <td>{{ x }}</td>
         <td>{{ forloop.counter }}</td>
         <td>{{ forloop.counter0 }}</td>
         <td>{% if forloop.first %}Yes{% else %}No{% endif %}</td>
         <td>{% if forloop.last %}Yes{% else %}No{% endif %}</td>
      </tr>
   {% endfor %}
   </tbody>
</table>

Which will display like this:

x x.counter x.counter0 x.first x.last
A 1 0 Yes No
B 2 1 No No
C 3 2 No No
D 4 3 No No
E 5 4 No No
F 6 5 No No
G 7 6 No No
H 8 7 No No
I 9 8 No No
J 10 9 No No
K 11 10 No No
L 12 11 No No
M 13 12 No No
N 14 13 No No
O 15 14 No No
P 16 15 No No
Q 17 16 No No
R 18 17 No No
S 19 18 No No
T 20 19 No No
U 21 20 No No
V 22 21 No No
W 23 22 No No
X 24 23 No No
Y 25 24 No No
Z 26 25 No Yes

Template Inheritance

One of Cadenza's most useful features is template inheritance. When writing any pure HTML website you'll find you often end up rewriting the same sections of code over and over again (things like your navigation links or footers).

Template inheritance lets you define a "parent" template file with points that can be overridden with new content in your "child" template. To get this working we make use of the extends and block tags.

"Extends" tags

The extend tag is a control tag that has no block, all what you have to do is give it the filename of your parent template as a parameter, like so:

{% extends "path/to/layout.cadenza" %}

Block tags

The block tag is a control tag which has a body of it's own. You give the block a name by passing it a variable name as a paremeter. You can give it any name you want.

{% block content %}
   Lorem Ipsum
{% endblock %}

In a child template the block wont be rendered at all but it's contents will be captured for use in the parent template. In the parent template the block with a matching name will have it's content replaced with the child's content which has the same name. If there is no content in the child then whatever you've put in the layout's block will be rendered instead.

Inside a block there is also a magic variable defined named super. This variable can be used to insert the parent block's content inside the child block's content.

Example: Input documents

partials/layout.cadenza

<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}My Website -{% endblock %}</title>
  </head>
  <body>
    <section>
      <h1>{% block title %}My Website -{% endblock %}</h1>
      {% block content %}No content here{% endblock %}
    </section>
  </body>
</html>

home.cadenza

{% extends "partials/layout.cadenza" %}
{% block title %}{{ super }} Home page{% endblock %}
{% block content %}
Hi! Welcome to my web page!
{% endblock %}

about.cadenza

{% extends "partials/layout.cadenza" %}
{% block title %}{{ super }} About me{% endblock %}
{% block content %}
I'm a software developer at (insert company here), you can email 
me at foo@example.com
{% endblock %}

Example: Rendered documents

home.html

about.html