TemplateRecall

DDG: After seeing a lot of template approaches where the template becomes more and more bloated with programming logic I was reading an article about Template::Recall, Reverse Callback Templating , by James Robsen. Here is its Tcl counterpart written as an Itcl-class:


#  Created By    : Dr. Detlef Groth
#  Created       : Mon Mar 17 13:56:04 2008
#
#  Description        
#
#  History
#        
package require Itcl
itcl::class TemplateRecall {
    public variable template_path ""
    private variable TemplateText ""
    private variable Templ 
    constructor {args} {
        eval configure $args
        if {$template_path eq ""} {
            error "Option -template_path not given"
        }
        if [catch {open $template_path r} infh] {
            puts stderr "Cannot open $template_path: $infh"
            exit
        } else {
            set TemplateText [read $infh]
            close $infh
        }
        array set Templ [list]
    }
    method render {template args} {
        if {![info exists Templ($template)]} {
            foreach line [split $TemplateText "\n"] {
                if {[regexp {\[ *=+ ([^\s]+) +=+ *\]} $line -> lastTempl]} {
                    continue
                } elseif {[info exists lastTempl]} {
                    append Templ($lastTempl) "$line\n"
                }
            }
        }
        set cpTempl $Templ($template)
        set cpTempl [regsub -all {\['} $cpTempl "'''''"]
                     set cpTempl [regsub -all {']} $cpTempl "'''''"]
 
        foreach {var repl} $args {
            set var [regsub {^-} $var ""]
            set cpTempl [regsub -all "'{5} +$var +'{5}" $cpTempl $repl]
        }
        return $cpTempl
    }
}

if {0} {
set goods [list "oxfords,Brown leather,\$85,0" \
          "hiking,All sizes,\$55,7" \
          "tennis shoes,Women's sizes,\$35,15" \
          "flip flops,Colors of the rainbow,\$7,90" ]

TemplateRecall tr -template_path template1.html
puts [tr render header -title MyStore -date [clock format [clock seconds]]]
foreach good $goods {
   set attr [split $good ,]
   set q [lindex $attr 3]
   if { $q == 0} {
       set q "Out Of stock"
   } 
   puts [tr render product_row -shoe [lindex $attr 0] -details [
       lindex $attr 1] -price [lindex $attr 2] -quantity $q]
}    
puts [tr render footer]
}

Here is the template-file template1.html:

[ =================== header ===================]
<html>
<head>
    <title>my site - [' title ']</title>
</head>
<body>
<h4>The date is [' date ']</h4>
<table border="1">
    <tr>
        <th>Shoe</th>
        <th>Details</th>
        <th>Price</th>
        <th>Quantity</th>
    </tr>
[ =================== product_row =================== ]
    <tr>
        <td>[' shoe ']</td>
        <td>[' details ']</td>
        <td>[' price ']</td>
        <td>[' quantity ']</td>
    </tr>
[= footer =]
</table>
</body>
</html>

Here is the output of the test:

<html>
<head>
    <title>my site - MyStore</title>
</head>
<body>

<h4>The date is Mon Mar 17 15:23:45 +0100 2008</h4>
<table border="1">
    <tr>
        <th>Shoe</th>
        <th>Details</th>
        <th>Price</th>
        <th>Quantity</th>
    </tr>
 
    <tr>
        <td>oxfords</td>
        <td>Brown leather</td>
        <td>$85</td>
        <td>Out Of stock</td>
    </tr>
 
    <tr>
        <td>hiking</td>
        <td>All sizes</td>
        <td>$55</td>
        <td>7</td>
    </tr>
 
    <tr>
        <td>tennis shoes</td>
        <td>Women's sizes</td>
        <td>$35</td>
        <td>15</td>
    </tr>
 
    <tr>
        <td>flip flops</td>
        <td>Colors of the rainbow</td>
        <td>$7</td>
        <td>90</td>
    </tr>
 
</table>
</body>
</html>

Discussion

Enter your comments here.