NAME

Top Close Open

Template::TT3::Manual::Commands - keyword commands

INTRODUCTION

Top Close Open

This is a rough draft of the documentation that will describe the various keyword commands that are available in TT3. It is incomplete and incorrect in places. Please don't trust anything you read.

COMMANDS

Top Close Open

block

Top Close Open

Defines a content block. Can be used in "anonymous block" form:

block;
    ...;
end;

You can assign a block to a variable to capture the content.

content = block;
    ...;
end;

You can also create named blocks

block foo;
    ...;
end;

fill foo;

NOTE: named blocks aren't implemented yet

Defines a content block like 'block', but it has the same runtime semantics as Perl's 'do' block. That is, it returns *only* the result of the last expression in the block;

a = do { b c d };     # same as: a = d

is is like = but expects a block on the RHS instead of an expression. In pseudo-grammar terms:

 = 
 is   

Thus is is the same thing as:

 = block; ; end 

Here's an example:

a is;                 # same as: a = block; ...; end
   ...;
end;

as is similar to is but with its arguments in a different order.

as  
 as 

Example:

as foo;               # same as: foo is; ...; end
    ...;
end;

It works nicely in side-effect form:

fill foo              # same as: content = fill foo
  as content   

fill

Top Close Open

The new name for PROCESS

fill template.html    # same as TT2: PROCESS template.html

NOTE: 'fill' isn't implemented yet. The parser will recognise the command, but it generates a "TODO: not working yet" message at runtime instead of actually filling the requested template.

with

Top Close Open

with creates a local variable scope for a block.

    x=1; y=2; z=3;

    # create a block with local variables
    with x=10 y=20;
       "x is $x\n";       # x is 10
       "y is $y\n";       # y is 20
       z = 30;            # local change only
       "z is $z\n";       # z is 30
    end;

    # original values 
    "x is $x\n";          # x is 1
    "y is $y\n";          # y is 2
    "z is $z\n";          # z is 3

with also works in side-effect form:

fill template.html    # same as TT2: INCLUDE template.html x=10 y=20
with x=10 y=20

NOTE: 'with' isn't implemented yet

just

Top Close Open

just is similar to with but it create a local scope that only contains the variables specified.

    x=1; y=2;

    just x=5;
        "x is $x\n";      # x is 5
        if y;
            # not reached - y is not defined in this inner scope
        end;
        z = 20;           # local change only
    end;

    if z;
        # not reached - z is not defined in this outer scope
    end;

The parameters are optional. You can use the 'just' keyword by itself to create an empty variable scope:

just;
    ...no variables are defined here...
end;

NOTE: 'just' isn't implemented yet

into

Top Close Open

into is the new name for WRAPPER.

    block foo;
       "Hello $content";
    end

    into foo;             # Hello World
       "World";
    end;

Note that into is equivalent to the following:

fill foo with content as;
    "World";
end;

into also works in side-effect notation

fill site/content
info site/layout

NOTE: 'into' isn't implemented yet

if / elsif / else - conditional branches

if a;                       # simple test
   ...;
end

if a < 10 and b > 20;       # arbitrarily complex expression
   ...;
end

if a;
    ...;
elsif b;
    ...;
else;
    ...;
end;

'if' can also be used in side-effect notation

fill site/debug if user.developer;

NOTE: 'if' is implemented but 'elsif' and 'else' are TODO

for

Top Close Open

Used to loop through lists

for a in b;         # iterate over contents of list b, or just b if not a list
    ...;
end

for a in [b,c,d];   # inline list definition
    ...;
end

for a in 1..10;     # ranges generate lists to iterate over
    ...;
end;

for a in 1 to 10;   # 'to' is an alias for '..'
    ...;
end

for a in 10 to 20 by 2;     # 'by' allows you to specify step
    ...;
end

TT3 allows you to put 'elsif' and 'else' clauses onto 'for' blocks. These are evaluated if the list is empty. This example iterates over the items in a shopping basket. If there are no items in the basket we display one of two messages, depending on the user being logged in or not.

for item in basket.items;
    fill basket/item_summary
elsif user.logged_id;
    "There are no items in your basket."
else;
    "Please login to view the items in your basket."
end

The above is short-hand for:

if basket.size;
    for item in basket.items;
        fill basket/item_summary;
    end;
elsif user.logged_id;
    "There are no items in your basket."
else;
    "Please login to view the items in your basket."
end

There should be some way to create lockstep iterators. e.g. instead of writing this:

n = 1;
for user in user;
   "$n: $user.name";
   n++;
end;

You should be able to create two iterators and run them in lockstep. I'm not sure about the best keyword to use, so I'm going with 'join' for now.

for user in user 
  join n in 1 by 1
    "$n: $user.name";

NOTE: 'for' is only partially implemented

from

Top Close Open

'from' defines a data target for a block. Any variables accessed in the block will be matched from the target data.

stuff = {
   foo = 10
   bar = 20
}

from stuff;
    "foo is " foo;      # 'foo' is actually 'stuff.foo'
    "bar is " bar;      # 'bar' is actually 'stuff.bar'
end;

I'm not decided 100% on what should happen if the data doesn't define a particular item. I'm currently thinking that it should fall back on looking for a regular variable.

stuff = {
   foo = 10
   bar = 20
}
baz = 10;

from stuff;
    "foo is " foo;      # 'foo' is actually 'stuff.foo'
    "bar is " bar;      # 'bar' is actually 'stuff.bar'
    "baz is " baz;      # 'baz' is just 'baz'
end;

If you want to temporarily mask all the other variables you can use 'just'

just from stuff;
    ...
end;

Which is just short-hand for:

just;                   # new, empty variable scope
  from stuff;           # define data target
    ...
  end;
end;

This also works quite nicely in side effect form:

fill user/info from user;
fill user/info just from user;

NOTE: 'from' isn't implemented yet

encode

Top Close Open

Use this to encode a block of text. It's similar to TT2 FILTER, but it uses any of the codecs accessible by Badger::Codecs.

[% encode html %]
   ...
[% end %]

[% encode base64 %]
   ...
[% end %]

decode

Top Close Open

This does the opposite of encode.

[% decode html %]
   ...
[% end %]

[% decode base64 %]
   ...
[% end %]

dot

Top Close Open

This implements a low-precedence, block oriented form of the dot operator.

[% dot length -%]     # same as 'Blah blah blah'.length
Blah blah blah
[%- end %]

In TT2 we had separate filters and text vmethods. In TT3 we just have text vmethods. The 'dot' keyword takes the place of the FILTER keyword, allowing you to define a block of text and then pipe it through any text virtual method.

You can pass arguments and chain multiple dotops together.

[% dot chunk(3).join(', ') -%]
foobarbaz             # outputs: foo, bar, baz
[%- end %]

It also works in side effect form. Because it's low precedence (the same precedence as all command keywords), you can use it like this:

[% fill foo dot html %]

This is the same thing as:

[% (fill foo).html %]

But obviously not the same thing as:

[% fill foo.html %]     # 'foo.html' is a filename

THINKING OUT LOUD

Top Close Open

Looking at an earlier example:

if basket.size;
    for item in basket.items;
        fill basket/item_summary;
    end;
elsif user.logged_id;
    "There are no items in your basket."
else;
    "Please login to view the items in your basket."
end

That can be written with braces if you prefer.

if basket.size {
    for item in basket.items {
        fill basket/item_summary;
    }
}
elsif user.logged_id {
    "There are no items in your basket."
}
else {
    "Please login to view the items in your basket."
}

Or the minimalist approach:

if basket.size
    for item in basket.items
        fill basket/item_summary;
elsif user.logged_id
    "There are no items in your basket."
else
    "Please login to view the items in your basket."

Hmmm... wait, not that's not right. The 'elsif' will get attached to the inner 'for'. Ho hum. This is a good example of why a flexible language can be a bad thing. Flexibility == ambiguity. I can image things like that tripping people up often, myself included.

Possible solutions:

Don't add 'elsif' and 'else' to 'for'. People aren't expecting 'for' to have them, so the natural expectation is that 'elsif' binds to 'if'. That's why the above example looks right, but is wrong. If 'elsif' didn't bind to 'for' then the above would work because 'for' would reject the 'elsif' terminator, consider itself finished and pass control back to 'if' to pick up the 'elsif'

Don't allow follow-on keywords after single expressions.

if x y;                 # OK
if x y; else z;         # NOT OK 

Don't allow follow-on keywords after single expressions unless they follow immediately, without any terminator.

if x y; else z;         # NOT OK - semi-colon terminates single expression
if x y else z;          # MAYBE OK - lack of semi-colon indicates continuation.

Well that makes our example correct again:

if basket.size
    for item in basket.items
        fill basket/item_summary;     # semi-colon ends 'for' expression
elsif user.logged_id
    ...
else
    ...

But I'm concerned that a single-semi-colon can change the meaning of an expression. It wouldn't be so bad if one form or the other was illegal because we would get an immediate parse error. But when both forms are legal syntax there is no warning.

if basket.size
    for item in basket.items
        fill basket/item_summary     # no semi-colon 
    elsif user.logged_id
        ...
    else
        ...

Perhaps I'm worrying too much. The above is the stripped down minimalist view that (common sense dictates) should only be used for simple cases. Given that the user has the choice of using explicit block form with semi-colons (if x; y; end) *OR* braces (if x { y }) then I probably don't need to feel too bad if they burn themselves using by deliberately using the ambiguous form.

Hmm...

AUTHOR

Top Close Open

Andy Wardley http://wardley.org/

COPYRIGHT

Top Close Open

Copyright (C) 1996-2009 Andy Wardley. All Rights Reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


http://tt3.template-toolkit.org/docs/Template/TT3/Manual/Commands.pod last modified 2009-12-24 12:09:20