NAME
Text::Xslate::Syntax::Kolon - The default template syntax
SYNOPSIS
use Text::Xslate;
my $tx = Text::Xslate->new(
syntax => 'Kolon', # optional
);
print $tx->render_string(
'Hello, <: $dialect :> world!',
{ dialect => 'Kolon' }
);
DESCRIPTION
Kolon is the default syntax, using <: ... :>
tags and : ...
line code.
SYNTAX
Variable access
Variable access:
<: $var :>
Field access:
<: $var.0 :>
<: $var.field :>
<: $var.accessor :>
<: $var["field"] :>
<: $var[0] :>
Variables may be HASH references, ARRAY references, or objects. Because $var.field
and $var["field"]
are the same semantics, $obj["accessor"]
syntax may be call object methods.
Literals
Special:
: nil # indicates "nothing"
: true # as the integer 1
: false # as the integer 0
String:
: "foo\n" # the same as perl
: 'foo\n' # the same as perl
Number:
: 42
: 3.14
: 0xFF
: 0b1010
Array:
: for [1, 2, 3] -> $i { ... }
Hash:
: foo({ foo => "bar" })
{ ... }
is always parsed as hash literals, so you need not to use prefix +
as Perl sometimes requires:
: {}.kv(); # ok
: +{}.kv(); # also ok
Expressions
Conditional operator (?:
):
: $var.value == nil ? "nil" : $var.value
Relational operators (== != < <= > >=
):
: $var == 10 ? "10" : "not 10"
: $var != 10 ? "not 10" : "10"
Note that ==
and !=
are similar to Perl's eq
and ne
except that $var == nil
is true iff $var is uninitialized, while other relational operators are numerical operators.
Arithmetic operators (+ - * / % min max
):
: $var * 10_000
: ($var % 10) == 0
: 10 min 20 min 30 # 10
: 10 max 20 max 30 # 30
Logical operators (! && || // not and or
)
: $var >= 0 && $var <= 10 ? "ok" : "too smaller or too larger"
: $var // "foo" # as a default value
String operators (~
)
: "[" ~ $var ~ "]" # concatination
Operator precedence is the same as Perl's:
. () []
* / %
+ - ~
< <= > >=
== !=
|
&&
|| // min max
?:
not
and
or
Constants
You can define lexical constants with constant
, which requires a bare name, and my
, which requires a variable name.
: constant FOO = 42;
: my $foo = 42;
These two statements has the same semantics, so you cannot modify $foo
.
: my $foo = 42; $foo = 3.14; # compile error!
Loops
There is for
loops that are like Perl's foreach
.
: # $data must be an ARRAY reference
: for $data -> $item {
[<: $item.field :>]
: }
You can get the iterator index in for
statements as $~ITERATOR_VAR
:
: for $data -> $item {
: if ($~item % 2) == 0 {
Even (0, 2, 4, ...)
: }
: else {
Odd (1, 3, 5, ...)
: }
: }
$~item
is a pseudo object, so you can access its elements via the dot-name syntax.
: for $data -> $i {
: $~i.index # the same as $~i
: $~i.count # the same as $~i + 1
: if ($~i.index % 2) == 0 {
Even
: }
: else {
Odd
: }
: }
Supported iterator elements are index :Int
, count :Int
, body : ArrayRef
, size : Int
, max :Int
, is_first :Bool
, and is_last :Bool
, peek_next :Any
, peek_prev :Any
.
while
loops are also supported in the same semantics as Perl's:
: # $obj might be an iteratable object
: while $dbh.fetch() -> $item {
[<: $item.field :>]
: }
Conditional statements
There are if-else
and given-when
conditional statements.
if-else
:
: if $var == nil {
$var is nil.
: }
: else if $var != "foo" { # elsif is okay
$var is not nil nor "foo".
: }
: else {
$var is "foo".
: }
: if( $var >= 1 && $var <= 10 ) {
$var is 1 .. 10
: }
Note that if
doesn't require parens, so the following code is okay:
: if ($var + 10) == 20 { } # OK
given-when
(also known as switch statement):
: given $var {
: when "foo" {
it is foo.
: }
: when "bar" {
it is bar.
: }
: default {
it is not foo nor bar.
}
: }
You can specify the topic variable.
: given $var -> $it {
: when "foo" {
it is foo.
: }
: when $it == "bar" or $it == "baz" {
it is bar or baz.
: }
: }
Functions and filters
You can register functions via function
or module
options for Text::Xslate->new()
.
Once you have registered functions, you can call them with the ()
operator. The |
operator is supported as a syntactic sugar to ()
.
: f() # without args
: f(1, 2, 3) # with args
: 42 | f # the same as f(42)
Functions are Perl's subroutines, so you can define dynamic functions:
# code
sub mk_indent {
my($prefix) = @_;
return sub {
my($str) = @_;
$str =~ s/^/$prefix/xmsg;
return $str;
}
}
my $tx = Text::Xslate->new(
function => {
indent => \&mk_indent,
},
);
:# template
: $value | indent("> ")
: indent("> ")($value)
There are several builtin functions, which you cannot redefine:
: $var | raw # not to html-escape it
: $var | html # explicitly html-escape it (default)
: $var | dump # dump it with Data::Dumper
NOTE: raw
and html
might be optimized away by the compiler.
Methods
When $var is an object instance, you can call its methods with the ()
operator.
<: $var.method() :>
<: $var.method(1, 2, 3) :>
<: $var.method( foo => [ 1, 2, 3 ] ) :>
There is an autoboxing mechanism that provides primitive types with builtin methods.
For arrays:
<: $array.size() :>
<: $array.join(",") :>
<: $array.reverse() :>
For hashes:
<: $hash.size() :>
<: $hash.keys().join(", ") # sorted by keys :>
<: $hash.values().join(", ") # sorted by keys :>
<: for $hash.kv() -> $pair { # sorted by keys :>
<: # $pair is a pair type with key and value fields -:>
<: $pair.key :> = <: $pair.value :>
<: } :>
You can define more methods with the function
option. See Text::Xslate.
Template inclusion
Template inclusion is a traditional way to extend templates.
: include "foo.tx";
: include "foo.tx" { var1 => value1, var2 => value2, ... };
Xslate templates may be recursively included, but the including depth is limited to 100.
Template cascading
Template cascading is another way to extend templates other than include
.
First, make base templates myapp/base.tx:
: block title -> { # with default
[My Template!]
: }
: block body -> { } # without default
Then extend from base templates with the cascade
keyword:
: cascade myapp::base
: cascade myapp::base { var1 => value1, var2 => value2, ...}
: cascade myapp::base with myapp::role1, myapp::role2
: cascade with myapp::role1, myapp::role2
In derived templates, you may extend templates (e.g. myapp/foo.tx) with block modifiers before
, around
(or override
) and after
.
: # cascade "myapp/base.tx" is also okay
: cascade myapp::base
: # use default title
: around body -> {
My template body!
: }
And, make yet another derived template myapp/bar.tx:
: cascade myapp::foo
: around title -> {
--------------
: super
--------------
: }
: before body -> {
Before body!
: }
: after body -> {
After body!
: }
Then render it as usual.
my $tx = Text::Xslate->new( file => 'myapp/bar.tx' );
$tx->render({});
The result is something like this:
--------------
[My Template!]
--------------
Before body!
My template tody!
After body!
You can also cascade templates just like Moose's roles:
: cascade myapp::base with myapp::role1, myapp::role2
You can omit the base template.
Given a file myapp/hello.tx:
: around hello -> {
--------------
: super
--------------
: }
Then the main template:
: cascade with myapp::hello
: block hello -> {
Hello, world!
: }
Output:
--------------
Hello, world!
--------------
Macro blocks
Macros are supported, which are called in the same way as functions and return a string marked as escaped.
: macro add ->($x, $y) {
: $x + $y;
: }
: add(10, 20)
: macro signeture -> {
This is foo version <: $VERSION :>
: }
: signeture()
: macro factorial -> $x {
: $x == 0 ? 1 : $x * factorial($x-1)
: }
: factorial(1) # as a function
: 1 | factorial # as a filter
Macros are first objects.
<: macro foo -> { "foo" }
macro bar -> { "bar" }
my $dispatcher = {
foo => foo,
bar => bar,
}; -:>
: $dispatcher{$key}()
Macros returns what their body renders. That is, macros themselves output nothing.
Note that you cannot call macros before their definitions.
Comments
:# this is a comment
<:
# this is also a comment
$var
:>
<: $foo # this is ok :>
Comments are closed by a new line or semicolon, so the following template outputs "Hello".
<: # this is a comment; "Hello" :>