
Python Template Language (PTL)
==============================

The good news is that PTL's syntax is almost exactly like Python.  The
differences are a single different keyword, and expressions inside
templates have their values kept, not discarded.  Here's a sample
template:

template foo (x, y = 5):
      "This is a chunk of static text."
      greeting = "hello world" # statement, no PTL output
      print 'Input values:', x, y
      z = x + y
      """You can plug in variables like x (%s)
in a variety of ways.""" % x

      "\n\n"
      "Whitespace is important in generated text, \n"
      "and z = "
      str(z)
      ", but y is "
      y
      "."

Templates are the PTL analogue to Python functions.  Templates are
defined using the 'template' keyword, obviously, and they can't have
docstrings, but otherwise they follow Python's syntactic rules:
indentation indicates scoping, single-quoted and triple-quoted strings
can be used, the same rules for continuing lines apply, and so forth.
PTL also tries to follow the semantics of normal Python code as far as
is possible, so templates can have parameters, and the parameters can
have default values, be treated as keyword arguments, etc.

The difference between a template and a regular Python function is
that inside a template the result of expressions get saved as the
result of that template.  Look at the first part of the example again:

template foo (x, y = 5):
      "This is a chunk of static text."
      greeting = "hello world" # statement, no PTL output
      print 'Input values:', x, y
      z = x + y
      """You can plug in variables like x (%s)
in a variety of ways.""" % x

Calling this template with foo(1,2) results in the following output:

	This is a chunk of static text.You can plug in variables like x (1)\n
	in a variety of ways.

Normally when Python evaluates expressions inside functions, it just
discards their values, but in PTL the value is converted to a string
using str() and appended to the output for the template.  There's a
single exception to this rule: None is the only value that's ever
ignored, adding nothing to the output.  (If this wasn't the case,
calling methods or functions that return None would require assigning
their value to a variable.  You'd have to write 'dummy = list.sort()'
in PTL code, which would be strange and confusing.)

The initial string in a template isn't treated as a docstring, but is
just incorporated in the generated output; therefore, templates can't
have docstrings.  No whitespace is ever automatically added to the
output, resulting in "...text.You can ..." from the example.  You'd
have to add an extra space to one of the string literals to correct
this.

The assignment to the 'greeting' local variable is a statement, not an
expression, so it doesn't return a value and produces no output.  The
output from the 'print' statement will be printed as usual, but won't
go into the string generated by the template.  Quixote directs
standard output into Quixote's debugging log; if you're using PTL on
its own, you should consider doing something similar.  'print' should
never be used to generate output returned to the browser, only for
adding debugging traces to a template.

Inside templates, you can use all of Python's control-flow statements:

template numbers(n):
        for i in range(n):
                i
                " " # PTL does not add any whitespace

numbers(5) will produce the output "1 2 3 4 5 ".  You can also have
conditional logic or exception blocks:

template international_hello(language):
        if language == "english":
            "hello"
        elif language == "french":
            "bonjour"
        else:
            raise ValueError, "I don't speak %s" % language

PTL templates are kept in files with the extension .ptl.  Like Python
files, they are byte-compiled on import, and the byte-code is written
to a compiled file with the extension '.ptlc'.  To import PTL files,
an import hook needs to be installed first.

from quixote import imphooks
imphooks.install()

(Note: if you're using the ZODB, always do 'import ZODB' before
installing the import hook.  There's some interaction which causes
importing the TimeStamp module to fail when the PTL import hook is
installed; we haven't debugged the problem.)

Once the import hook is installed, PTL files can be imported as if
they were Python modules.  If all the example templates shown here
were put into a file named 'foo.ptl', you could then write Python code
that did this:

from foo import numbers
def f(): return numbers(10)

You may want to keep this little function in your PYTHONSTARTUP file:

def ptl():
	try:
		import ZODB
	except ImportError:
		pass
        from quixote import imphooks
	imphooks.install()
	del imphooks

This is useful if you want to interactively play with a PTL module.


-- 
A.M. Kuchling    <akuchlin@mems-exchange.org>
Neil Schemenauer <nascheme@mems-exchange.org>
Greg Ward        <gward@mems-exchange.org>
