since version 1.0.0
The for
macro can be used to repeat text with different parameters.
It can be used similar to the for
loop in programming languages, but it can also have multiple variables.
The actual values can be listed comma separated in the macro or they can also come from some other list holding macro.
The two forms of the macro are
{@for variable in (a,b,c,...,d)= content to be repeated
containing variable}
and
{@for (v1,v2,...,vN) in (a|w|...|1,b|q|...|2,c|r|...|5,d|t|...|9)= content to be repeated
containing v1 v2 and v3}
When the values are held by a macro as a list the keyword from
is used instead of the keyword in
.
{@for variable from MACRO= content to be repeated}
where the macro MACRO
should be defined before the for
macro.
-
since 1.5.0 multi-argument
for
-
since 1.6.3 backtick string separator value list
-
since 1.7.3 options between
[
and]
-
since 1.7.8 option
evalist
-
since 2.7.0 option
join
The macro for
uses the content of the macro as a template.
The result of the macro is a string, which is the concatenation of the content for each loop.
The content can contain the loop variables, and each time the variables are replaced with the values.
For example
{@for x in (a,b,c)=it is $x
}
will result in
it is $a
it is $b
it is $c
When using multiple variables, the values are separated by the |
character as in the example
{@for (x,y,z) in (a|b|c,d|e|f,g|h|i)=it is $x $y $z
}
which will result in
it is $a $b $c
it is $d $e $f
it is $g $h $i
Note
|
The values a|b|c , d|e|f , and g|h|i are string tuples and multiple loop variables do not mean nested loops.
|
If the values themselves contain commas, or |
characters then other strings can also be used to separate the values.
The default separator is the comma character, but it can be changed using the option sep
or separator
.
There are other parameter options, (parops) that can be used to control the behavior of the loop.
The options are
-
$forsep
,separator
,sep
can define the separator if it is different from the default, which is,
comma. The value is used as a regular expression giving very versatile possibilities. -
$forsubsep
,subseparator
,subsep
can define the subseparator if it is different from the default, which is|
pipe. It is used when there are multiple variables in the loop. Similarly to the separator, the value is used as a regular expression. -
trimForValues
,trim
is a boolean paror. If it is present andtrue
, then the values are trimmed, the spaces are removed from the beginning and the end. -
skipForEmpty
,skipEmpty
is a boolean parameter. If it is present andtrue
, then the empty values are skipped. -
lenient
is a boolean parameter. If it is present andtrue
, then the number of the values in the value list is not checked against the number of the variables. -
evaluateValueList
,evalist
is a boolean parameter. If it is present andtrue
, then the value list is evaluated as a macro before spling it up to values. -
$forjoin
,join
is used to join the values when the values are joined together. The default is the empty string.
The macro:
{@for [sep=:]$a in (a:b:c)=is $a
}
will result
is a
is b
is c
Another example:
{@for [trim sep=":"] $a in ( a : b :c )=is >>$a<<
}
{@for [sep=":"] $a in ( a : b :c )=is >>$a<<
}
will result in the output:
is >>a<<
is >>b<<
is >>c<<
is >> a <<
is >> b <<
is >>c <<
The number of the actual values separated by |
character should be the same as the number of the variables in the for loop.
If this is not the case, then the macro evaluation will throw a bad syntax exception.
This can be suppressed with the option lenient
.
If the option lenient
is used, then extra values are ignored and missing values are presented as empty strings.
Note that this same option controls how user defined macro arguments are paired to the parameters.
Starting with version 1.5.3 you can fine-tune how a for
loop treats the empty elements.
By default, the empty elements in a for loop value list represent empty strings.
The loop body will be rendered with these values replacing the loop variable with an empty string.
In a situation like that the use of the option lenient
is also necessary if the loop has multiple variables.
In that case, and empty value cannot be split into multiple strings.
It is one empty string, and if there are multiple variables, then an error will occur unless the option lenient
is used.
For example
{#for (k,z) in ()=wukz}
it will not work because the empty string cannot be split into two strings. It results in one empty string when it is split. On the other hand, the following code will work
{@for [lenient] (k,z) in ()=wukz}
and it will result
wu
as both k
and z
are empty strings.
This default behavior can be altered using the option skipForEmpty
.
If this option is used the for
loop will skip the empty values.
The previous example with this option:
{@for [skipEmpty] (k,z) in ()=wukz}\
will evaluate to an empty string.
Also note that in this case there is no need to use the option lenient
.
That is because the empty value is skipped and there is no issue splitting it up into a lesser number of values than the number of the loop variables.
The example above contains one loop value, and that loop value is an empty string.
There can be multiple empty values in a for loop and empty and non-empty values can be mixed.
The option skipForEmpty
and the alias skipEmpty
works in any of those cases.
For example:
{@for [skipEmpty] k in (,)=wuk}
will also result an empty string and
{#for k in (,k)=wuk{@options skipForEmpty}}
will result
wuk
Sometimes the values for the for
loop come from some macro.
In that case the for
macro should start with the #
character, otherwise the macro will not be evaluated to the list of values.
For example:
{@define list=x,y,z}{@for z in ({list})={@define z=zz}}{?x}{?y}{?z}
will result
{@define {list}={list}{list}}
That is because the content of the macro for
is not evaluated before the for
loop is executed as we used the @
character.
It is also to note that the result of the for loop is not evaluated.
We will have to attend to that later.
First we have to solve the issue that the macro list
is not evaluated.
To do that, we need to use the #
character in front of the for
loop.
{@define list=x,y,z}{#for z in ({list})={@define z=zz}}{?x}{?y}{?z}
will result an empty string:
The reason is that the content of the for
macro is evaluated before executing the macro itself.
That way the macro reference {list}
will become x,y,z
, but the same time the part, which is after the =
is also evaluated.
The evaluation will define the macro z
to be zz
, but this macro is within the scope of the for
macro.
As soon as the for
macro execution is finished the definition of z
is lost.
What we want is to protect the body of the for
macro from evaluation before for
the macro is executed, and we want it to execute after.
{@define list=x,y,z}{!#for z in ({list})={@ident {@define z=zz}}}{?x}{?y}{?z}
will result
xxyyzz
The macro {@ident …}
is evaluated, and its result is the content of the macro, and it is not evaluated further before the evaluation of the macro for
.
The macro for
gets evaluated and, then the output is evaluated because the macro is preceeded with the !
character, which is a shorthand for the core built-in macro eval
.
This evaluation defines x
, y
and z
.
Because the case that we want to evaluate the list part of the for
loop but not the body part is so common there is an option that helps with this.
The option evaluateValueList
(alias evalist
) instructs the macro for
to evaluate the value list before iterating through it.
{@define list=x,y,z}{!@for [evaluateValueList] z in ({list})={@define z=zz}}{?x}{?y}{?z}
will result
xxyyzz
In version 2.5.0 and later you can use a bare macro name between the parentheses, as
{@define list=x,y,z}{!@for [evaluateValueList] z in (list)={@define z=zz}}{?x}{?y}{?z}
will result the same output:
xxyyzz
We still need the !
character in front of the for
but we could get rid of the ident
macro and the extra level of nesting.
Note
|
The use of The consequence is that using In situations like that you can use the special list separator that we discuss in the next paragraph. |
Sometimes you may need to do a for loop over values that contain the )
character.
With the conventional form of the for
macro it was not possible, because the first )
character terminates the list of the values.
Jamal 1.6.3 introduced a new, backward compatible format for the for
macro.
Instead of the (
and )
characters it is possible to use an arbitrary string to denote the end of the values.
When the first character after the keyword in
(after optional spaces) is the backtick character, then the string till the next backtick character will be used to denote the end of the values.
The starting and ending backtick should also be part of the string closing the values.
For example, the following
{@for x in `END`a),b),c),d)`END`=x }
will result
a) b) c) d)
Note that this alternative format can only be used for the values list and not for the variables.
The variables of the for loop should always be listed between (
and )
characters.