libdodo template processor

Template processor supports simple but yet enough powerful language.
It supports includes, variables, conditional statements, loops, namespaces, etc.
The primary goal of the template processor is to separate application code from its presentation.

syntax

template language blocks

Each part of template that the processor will parse is enclosed into special open and close statements.
Text outside the template blocks is not being parsed and is being sent to the output without any modifications.
Text in statements block is always treated as text if it is not a variable. Spaces are trimmed out in the beginning and in the end of the text block.
If text area is enclosed with quotes or double quotes the quotes are being removed from the output and text inside is being pushed to the output without any further modifications.

  • Processing block
    Processor assumes that some language statement is enclosed in this block
    <( - open statement
    )> - close statement
    For example:
       <(for $c in $array)> <(print $c)> <(rof)>
    
  • Non-parsed block
    Processor does not parse the block enclosed with these statements and sends to the output as-is
    <(> - beginning of the non-parsing area
    <)> - end of the non-parsing area
    For example:
    {{{ <(>

<(print a=, $a, b=, $b)>

<(if $a!=$b)>

a != b

<(else)>

a == b

<(fi)>

<)> }}}

  • Comment block
    Comment block is thrown out from the processor output
    <(* - beginning of the comment
    *)> - end of the comment
    For example:
      <(* comment here *)>
    

variables

Names of the variables begin with '$' sign.
For example:

$var
$1var


Variable is resolved only within the processor statement and if it is not enclosed with any quotes. Text in the quotes is not being interpolated and variables are not being resolved in it.
Processor supports 4 types of variables:

  1. string
  2. array
  3. hash
  4. array of hashes


Variable is iterative with 'for' loop and variable member can be accessed directly with '.' operator.
For example:

  1. first symbol of string:
        $string.0
    
  2. second element in array:
        $array.1
    
  3. first symbol of second element in array:
        $array.1.0
    
  4. element named 'one' of hash:
        $hash.one
    
  5. element named 'one' of second element in array of hashes:
        $hashArray.1.one
    


Variable can be used as a key to the member. In this case it must be enclosed in '{}' brackets.
For example:

  1. element named 'one' of second element in array of hashes(variable 'variable' has value 'one'):
        $hashArray.1.{$variable}
    
  2. element named 'one' of second element in array of hashes(array 'hash' has member 'one' which value is 'one'):
        $hashArray.1.{$hash.one}
    

namespaces

Variables have scope of visibility in the statement block.
For example:

<(for $b in $arr2)>
	<(for $b in $b)>
		<(print $b)>
	<(rof)>
<(rof)>
<(assign a = test1)>

<(if true)>
	<(assign a = test2)>
	<(print a= ', $a,' (must be equal to 'test2'))>
<(fi)>
<(print a= ', $a,' (must be equal to 'test1'))>

statements

ns

'ns' statement explicitly defines namespace scope.
For example:

<(assign a = test1)>
<(ns)>
	<(ns)>
		<(assign a = in namespace)>
		<(print a= ', $a,' (must be equal to 'in namespace'))>
	<(sn)>
	<(print a= ', $a,' (must be equal to 'test1'))>
<(sn)>

include

'include' statement allows to load template from external file.
Included template file is processed and the contents of the processed template is inserted at the point of inclusion.
'include' takes string or variable as an argument. Path to template is relative to defined in tpl::processor object instance.
For example:

<(include $template)>

<(include template.tpl)>

if

'if' is a conditional statement that allows or discards processing of the template block.
'else' statement defines template block that is processed if conditional statement in 'if' is false.
'if' allows to use only one comparison per block. There is no logical OR or AND.
Conditional statement for 'if' allows using '==', '!' and '!=' to compare strings, and '==', '!=', '!', '<=', '>=', '<', '>' to compare numeric values.
Unary operator '!' turns statement into false if statement is an empty string or zero for numeric or string that is equal to 'false'.
For example:

<(if $a == $b)>
	$a equal to $b
<(fi)>

<(if $b)>
	$b is not 'false', not empty string nor zero
<(fi)>

<(if ! $a)>
	<(if $a == false)>
		$a is 'false'
	<(else)>
		<(if $a == 0)>
			$a is zero
		<(else)>
			$a is an empty string
		<(fi)>
	<(fi)>
<(else)>
	smth else ...
<(fi)>

for

'for' statement is used to iterate over string, array of objects or hash.
Template processor understands two kinds of 'for' statements:

  • Iterate obtaining values of elements:
       <(for $value in $array)><(rof)>
    
  • Iterate obtaining pairs of (key, value)
    For hash key is a hash key, otherwise it is an index of element in array or string.
       <(for $key => $value in $hash)><(rof)>
    


'break' statement inside 'for' block stops the current loop. If numeric value is specified for 'break' statement, amount of loops specified as 'break' argument would be stopped upwards.
'continue' statement inside 'for' block starts new iteration of the loop.
Special variable '$dodo.iterator' stands as a counter for current loop.
For example:

<(for $value in $array)>
    <(if $dodo.iterator > 10)>
        <(break)>
    <(fi)>
<(rof)>
<(for $key => $value in $hash)>
    <(for $value in $value)>
        <(if $value == needle)>
            <(break 2)>
        <(fi)>
    <(rof)>
<(rof)>

print

'print' statement pushes variable value to the output.
'print' accepts more than one argument. 'print' arguments should be delimited with coma.
For example:

<(print $array.{0}.{$key})>

<(print $array.1.{$hash.{$key}})>

<(print $array.{0}.{$key}, " and ", $array.1.{$hash.{$key}})>