Welcome, guest | Sign In | My Account | Store | Cart
import re


class Templite(object):
    delimiter
= re.compile(r"\$\{(.*?)\}\$", re.DOTALL)
   
   
def __init__(self, template):
       
self.tokens = self.compile(template)
   
   
@classmethod
   
def from_file(cls, file):
       
"""
        loads a template from a file. `file` can be either a string, specifying
        a filename, or a file-like object, supporting read() directly
        """

       
if isinstance(file, basestring):
            file
= open(file)
       
return cls(file.read())
   
   
@classmethod
   
def compile(cls, template):
        tokens
= []
       
for i, part in enumerate(cls.delimiter.split(template)):
           
if i % 2 == 0:
               
if part:
                    tokens
.append((False, part.replace("$\\{", "${")))
           
else:
               
if not part.strip():
                   
continue
                lines
= part.replace("}\\$", "}$").splitlines()
                margin
= min(len(l) - len(l.lstrip()) for l in lines if l.strip())
                realigned
= "\n".join(l[margin:] for l in lines)
                code
= compile(realigned, "<templite %r>" % (realigned[:20],), "exec")
                tokens
.append((True, code))
       
return tokens
   
   
def render(__self, __namespace = None, **kw):
       
"""
        renders the template according to the given namespace.
        __namespace - a dictionary serving as a namespace for evaluation
        **kw - keyword arguments which are added to the namespace
        """

       
namespace = {}
       
if __namespace: namespace.update(__namespace)
       
if kw: namespace.update(kw)
       
       
def emitter(*args):
           
for a in args: output.append(str(a))
       
def fmt_emitter(fmt, *args):
            output
.append(fmt % args)
       
namespace["emit"] = emitter
       
namespace["emitf"] = fmt_emitter
       
        output
= []
       
for is_code, value in __self.tokens:
           
if is_code:
               
eval(value, namespace)
           
else:
                output
.append(value)
       
return "".join(output)
   
   
# shorthand
    __call__
= render

---------
example
:
---------
>>> from templite import Templite
>>>
>>> demo = r"""
... <html>
...     <body>
...         ${
...         def say_hello(arg):
...             emit("
hello ", arg, "<br>")
...         }$
...
...         <table>
...             ${
...                 for i in range(10):
...                     emit("<tr><td>
")
...                     say_hello(i)
...                     emit("
</tr></td>\n")
...             }$
...         </table>
...
...         ${emit("
hi")}$
...
...         tralala ${if x > 7:
...             say_hello("
big x")}$ lala
...
...         $\{this is escaped starting delimiter
...
...         ${emit("
this }\$ is an escaped ending delimiter")}$
...
...         ${# this is a python comment }$
...
...     </body>
... </html>
... """

>>>
>>> t = Templite(demo)
>>> print t(x = 8)

<html>
   
<body>


       
<table>
           
<tr><td> hello 0<br> </tr></td>
<tr><td> hello 1<br> </tr></td>
<tr><td> hello 2<br> </tr></td>
<tr><td> hello 3<br> </tr></td>
<tr><td> hello 4<br> </tr></td>
<tr><td> hello 5<br> </tr></td>
<tr><td> hello 6<br> </tr></td>
<tr><td> hello 7<br> </tr></td>
<tr><td> hello 8<br> </tr></td>
<tr><td> hello 9<br> </tr></td>

       
</table>

        hi

        tralala hello big x<br> lala

        ${this is escaped starting delimiter

        this }$ is an escaped ending delimiter



    </
body>
</html>

>>>

History

  • revision 3 (17 years ago)
  • previous revisions are not available