Functions
Stencil has it's own built in expression language designed for template processing. To augment the built in functions and the methods of objects passed into Stencil you can define your own utility functions right inside a template.
At first glance functions look exactly like macros but there is an important distinction. Functions are code that process statement and can return values. Macros are blocks of text that are processed as templates themselves. If a function doesn't return a value, calling it from an output will not output anything.
Basic
Defining a function in Stencil is done with this simple syntax
$func myFunc () { return 'My Function!'; };
$myFunc ();
My Function!
Parameters
Parameters are specified in familiar parentheses format. Remember, Stencil is an untyped language so no types are specified, just names.
$macro myFunc ( greeting, name ) { return greeting + ' ' name + '!'; };
$myFunc('Hello','World');
Hello World!
Parameters can be passed by location (as in the previous example) or by name. You must choose one passing method or the other. You cannot mix methods.
$macro myFunc ( greeting, name ) { return greeting + ' ' + name + '!'; };
$myFunc(greeting='Hello',name='World');
Hello World!
Default Values
Parameters can also have default values. You simply specify an expression after the parameter name. Any parameters not passed will receive their default value or null if no default was defined.
$macro myMacro ( greeting='Hello', name ) { return greeting + ' ' + name + '!'; };
$myMacro(name='World');
Hello World!
Any Parameters
Occasionally you would like to accept any number of parameters and process them all in your macro. This is done by marking a parameter with the '*' sign. Then you can enumerate the parameter keys/values at will.
$macro myFunc (*all) { var text = ''; foreach entry in all { text += entry.key + ' = ' + entry.value + '\n'; } };
$myFunc(one='blue',two='red',three='green');
one = blue; two = red; three = green;
Statements
Functions process statements. As such they can do pretty much any imaginable thing you would like. All the available statements are described below along with an example of the associated syntax.
Return
Exits the function immediately, returning a value to its caller
return 10;
Declaration
Declares a variable in the current function scope;
var text = '';
Assignment
Assigns a value to a variable. The variable must have been previously declared.
text = 'New Value';
If/Else
Choose to execute one of two statements
if value { text = "this"; } else { text = "that"; }
The else statement is optional
if value { text = "this"; }
Foreach/Else
Execute a statement once for each member of a collection
foreach item in items { x += item; }
An optional else statement can be provided for when the collection is empty
foreach item in items { x += item; } else { x = 'None'; }
An optional iteration variable can be declared that provides commonly used
information about the current iteration.
The iteration variable provides the following properties:
- index - iteration # starting from 0
- count - iteration # starting from 1
- even - true if it is an even numbered iteration
- odd - true if it is an odd numbered iteration
- hasNext - true if this is not the last iteration
foreach item,it in items { x += item.name + ' ' + it.count; }
While
Execute a statement while a value is true
while value < 5 { value += 1; }
Switch/Case/Default
Select one of several blocks based on a value
switch value { case 0: x=5; case 1: x=10; default: x=0; }
With
Add properties of one or more expressions to the current scope
with stock,group { x += group; $* for group.title *$ x += name; $* for stock.name *$ x += price; $* for stock.price *$ }
break
Breaks out of the nearest loop
while x < 10 { if x == 3 break; x += 1; }
continue
Continues on to the next iteration of the nearest loop
while x < 10 { x += 1; if x == 3 continue; x += 3; $* this gets skipped *$ }