Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^2: Yet Another Templating System

by ruzam (Curate)
on Apr 28, 2006 at 18:00 UTC ( [id://546330]=note: print w/replies, xml ) Need Help??


in reply to Re: Yet Another Templating System
in thread Yet Another Templating System

OK, well, as I suspected there's definitely strong opinions associated with template systems.

Here's what I've got going then.

The basic premise is that the main Perl code is going to do all the work of preparing the data. The template system is simply a means to put it into the page. To that end I guess my style most closely matches Template-Toolkit, even down to the use of '[%' and '%]' which we both seem to have chosen independantly, go figure. I didn't want to take HTML::Template's approach of wrapping things up in tags (that are easily lost in the rest of the HTML, not to mention harder to search for and just plain wordy)

A $session object is created (my session object does all the usual session management stuff, config files, login, session verification, etc). The $session is used by the page script, which then stuffs it full of what ever data it digs up, in what ever format it needs to be stored as. At the end of the script the $session object is passed into the template processing to generate the page.

A simple session data example might look like this:
$session = { data1 => 'test1', # scalar data2 => ['array0', 'array1'], # array ref data3 => { # hash ref data1 => 'test4', data2 => ['array50', 'array51'], data3 => { data_x => 'data2_array_count', data_y => 2, } } };

A simple template to display this sesion might look like this:
data1: [%data1%]<br> data2: <br> [%data2:%] &nbsp; [%$_%]<br> [%:data2%] data3: <br> [%data3:%] &nbsp; data1: [%$_.data1%]<br> &nbsp; data2: <br> [%$_.data2:%] &nbsp;&nbsp; [%$_%]<br> [%:$_.data2%] &nbsp; data3: <br> [%$_.data3:%] &nbsp;&nbsp; data_x: [%$_.data_x%] data_y: [%$_.data_y%]<br> [%:$_data3%] [%:data3%] [%data4:%] There's nothing in this data and the entire block will simply be left +out of the output. [%:data4%] Here's a direct reference to a nested key<br> data2 array count is: [%data3.data3.data_y%]<br> <br> Since data_x and data_y are unique here's another way to get to them:< +br> [%data3.data3:%] data_x: [%data_x%]<br> data_y: [%data_y%]<br> [%:data3.data3%] <br> And yet another:<br> [%data3:%] data_x: [%$_.data3.data_x%]<br> data_y: [%$_.data3.data_y%]<br> [%:data3%]

The key points are:
- CGI->header() takes care of wrapping the template inside a body
- Every substitution is enclosed by [% %]
- Substitution key relates directly to the key/value pairs in $session
- Nested levels can be reached prefixing the key path to the level ie [%level1key.level2key.level3key%]
(Of course this presumes that you can't have a '.' in a key name to do this)
- A block starts when the substitution key ends with a ':', the block ends with the first matching key that starts with a ':'
- Inside a block, something magic happens. A symolic key '$_' takes on a reference to the value of the block key. If the value is a hash, $_ becomes a reference to that hash. If the value is an array, then the block is repeated for each item in the array with $_ becoming a reference to each item in turn.
- In addition to the symbolic '$_' key, there's also a symbolic '$i' key which holds the value of the current array index (of an array block).
- keys are searched first at the top most level, then at the block level (if your keys are unique, you can skip the '$_.' prefix inside blocks)
- Any value (block) not found or defined is simply left out


This is the short version. I also have several other macros in my template to do other things:
[%value:template%] - include another template named 'value'
(anyplace you can put a 'value' in a macro, you can also use 'key.var' to use the value of a key instead)
[%key:ift%] something [%key:else%] something else [%:key] - if 'true' else conditions (else is optional)
[%key:iff%] - Same as 'ift', only if 'false'
[%key:ifeq:value%],[%key:iflt:value%],[%key:ifgt:value%] - comparison tests, same as 'ift' (string)
[%key:if.eq:value%],[%key:if.lt:value%],[%key:if.gt:value%] - comparison tests, same as 'ift' (numeric)
[%key:table:cols][%key:row%][%key:col%][%key:cell%][%:key%] - given an array, turn it into a table with 'cols' columns. row, col and cell are all optional (the <table> tag itself is supplied by the template)

I've tried to keep the template substitution as close to the source Perl data as possible and streamlined for most common usage. It's not very pretty to look at, but it's logical and precise (imho) for a Perl developer. I have a school admin application I'm working on that neatly displays a very complex schedule table with a very minimal template.

I guess I should also add that this is part of a larger 'web application framework' I'm working on, so I've also built in support for template stylesheet themes, icon/image paths, javascript libraries, template view levels, and multi-language directories.

So, does it warrent further discussion or should I just keep it to myself?

Replies are listed 'Best First'.
Re^3: Yet Another Templating System
by perrin (Chancellor) on Apr 28, 2006 at 20:44 UTC
    Everything you've said so far is covered by Template Toolkit, albeit with minor syntax adjustments. You could even modify the TT syntax to parse your template if you wanted to. That would be a very interesting learning experience in writing parser grammars.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://546330]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (9)
As of 2024-04-16 09:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found