Version 13 of TemplaTcl

Updated 2007-05-30 16:03:58 by FF

FF The discussion evolved in ToW Tcl on WebFreeWay has generate some interest, and here is an effort for making a minimal template engine. I would like to use this page for collecting ideas from people. Fell free to change everything, fix bugs and revolutionize the concept - it is the purpose of the page.


 #!/usr/bin/env tclsh

 package require Tcl 8.2
 package require struct

 namespace eval TemplaTcl {
        variable data
        variable mode
        variable modeprev

        proc parse {file} {
                variable data
                variable mode
                variable modeprev
                set mode raw
                mode raw

                # read the template into $rawl - list of chars
                set fh [open $file r]
                set raw [read $fh]
                if {[catch {close $fh} err]} {puts "TemplaTcl: $err"}
                set rawl [split $raw {}]

                ::struct::queue cc

                foreach ch $rawl {
                        # we work char-by-char :|
                        cc put $ch
                        set sz [cc size]

                        # max block to compare (<%=) is 3 chars long:
                        if {$sz >= 3} {
                                set s3 [join [cc peek 3] {}]
                                set s2 [join [cc peek 2] {}]
                                if {$mode == "raw"} {
                                        if {$s3 == "<%="} {
                                                # <%= is a shorthand for puts ...
                                                cc get 3
                                                mode code
                                                buf "puts "
                                                continue
                                        } elseif {$s2 == "<%"} {
                                                # <% indicates begin of a code block
                                                cc get 2
                                                mode code
                                                continue
                                        }
                                } elseif {$mode == "code"} {
                                        if {$s2 == "%>"} {
                                                # and %> is the end of code block
                                                cc get 2
                                                mode raw
                                                continue
                                        }
                                }
                                buf [cc get]
                        }
                }
                # finish working on the queue:
                while {[cc size] > 0} {
                        buf [cc get]
                }
                mode flush
        }

        proc mode {m} {
                # used internally by parse - switches mode and stuff...
                variable data
                variable mode
                variable modeprev

                set newm {}
                switch $m {code - raw {set newm $m}}
                if {$newm != {}} {
                        set modeprev $mode
                        set mode $newm
                        set data(buf:$mode) {}
                }
                if {$m == "flush"} {set modeprev $mode ; set mode _}
                if {$mode != $modeprev} {
                        lappend data(out) [list $modeprev $data(buf:$modeprev)]
                        set data(buf:$modeprev) {}
                }
        }

        proc buf {ch} {
                # used internally by parse - put $ch in the right buffer
                variable data
                variable mode
                append data(buf:$mode) $ch
        }

        proc dump {} {
                # run the template script
                variable data
                set tclBuf ""
                foreach l $data(out) {
                        set t [lindex $l 0]
                        set d [lindex $l 1]
                        switch $t {
                                raw {append tclBuf [list puts $d]\n}
                                code {append tclBuf $d\n}
                        }
                }
                eval $tclBuf
        }
 }