PSP, Cheetah, PTL, ZOPE, etc ...

Tavis Rudd tavis at calrudd.com
Sun Aug 5 16:53:49 EDT 2001


Graham,
grahamd at dscpl.com.au (Graham Dumpleton) wrote:
> For what it is worth, Velocity looks pretty well what I am after. A
> Python clone of it would be quite nice, although tweaks to make better
> use of some stuff in Python would make it better. I guess I will have
> to wait for updated documentation for Cheetah to get an understanding
> of it. I trolled a bit through the CVS version of the documentation but
> still can spot a least one thing which Velocity has which I see as useful.
> Ie., an equivalent of #stop. Is there such a thing in Cheetah? It should
> be simple to do as all it needs to potentially do is throw an exception
> which is caught at the top.

Cheetah has an extended version of #stop that we renamed #raw instead.
Velocity doesn't seem to allow you to #restart after #stop.  Cheetah
does, with "#end raw".

We've implemented equivalents of all Velocity's directives, while
simplifying the syntax a bit and adding alot on the 'framework' side
of things.

Velocity is older, has a larger user-base, and has better examples and
docs at the moment. Cheetah, however, has a number of advantages over
Velocity:
=================================================
* it's written in Python. Thus, it's easier to use and extend.
-------------------------------------------------
* the syntax is cleaner, more flexible and is closer to Python's

Example:
"""
#for $i in range(15)
$i
#end for 
"""
instead of 
"""
#foreach($i in range(15))  
$i
#end
"""
which means the following example is possible Cheetah, but not
Velocity:
"""
#for $key, $val in $myDict
$key, $val
#end for 
"""

-------------------------------------------------
* it has a powerful caching mechanism.  Velocity has no equivalent.

This will be statically cached after the first request:
"""#cache 
$var $var2 $var3
#end cache"""

and this will be refresed every 15 min:
"""#cache 15
$var $var2 $var3
#end cache"""

Or you can use the shorthand syntax on individual $placeholders.  $var
will be re-interpolated for each request, $*var will be statically
cached after the first request,  $*15*var will be re-interpolated
every 15 min, $*0.5*var will be re-interpolated every half minute

-------------------------------------------------
* it's far easier to add data/objects into the namespace where
$placeholder values are extracted from.  Velocity calls this namespace
a 'context'. Contexts are dictionaries/hashtables. You can put
anything you want into a context, BUT you have to use the .put()
method to populate the context as in this example:
"""
VelocityContext context1 = new VelocityContext();
context1.put("name","Velocity");
context1.put("project", "Jakarta");
context1.put("duplicate", "I am in context1");
"""
Cheetah takes a different approach. Rather than require you to
manually populate the 'namespace' like Velocity, Cheetah will accept
any existing Python object or dictionary AS the 'namespace'.
Furthermore, Cheetah allows you to specify a list namespaces that will
be searched in sequence to find a varname-to-value mapping.  This
searchList can be extended at run-time.

If you add 'foo' object to the searchList and the 'foo' has an
attribute called 'bar' you can simply type $bar in the template rather
than $foo.bar. If the second item in the searchList is this dictionary
{'spam':1234, 'parrot':666} then $spam's value will be found in the
dict rather than in the 'foo' object at the start of the searchList.

Cheetah also has an extended version of the #set directive: 
#data
<absolutely any valid Python code>
#end data
The string in the #data directive is exec'd in an empty namespace and
that namespace is then added to the searchList.
-------------------------------------------------
* it has a #block [blockName] ... #end block [blockName] directive
that allows you to delimit sections of your template that can be
reimplemented by sub-classes of the template.

Blocks can be redefined using the #redefine [blockName] ... #end
redefine [blockName] directive or simply by using the Template class'
redefineBlock() or killBlock() methods.

This feature has no equivalent in Velocity and is very useful for
selectively changing part of a template without having to
copy-paste-and-edit the entire thing.

#block directives can be nested to any depth.
-------------------------------------------------
* it has better whitespace handling around #directive tags
-------------------------------------------------
* it uses 'unified dotted notation', whereby Cheetah lets you
subscript objects and dictionaries in the same way, using dotted
notation.  This is far easier for non-programmers to understand and it
insulates you from changes in the API behind the template's
$placeholders.

$a.b.c will work with "a = {'b':{'c':1234}}" or "a = myClass(); a.b =
anotherClass()"
You can still write $a['b']['c'] if you want to.
-------------------------------------------------
* it allows 'auto-calling' of methods and functions embedded as
$placeholders in the template definition.  If this feature is enabled
(the default) then $func and $obj.meth will translated to $func() and
$obj.meth().  If the function or method require args then you still
have to do it like in Python $func('foo', 1234)
-------------------------------------------------
* it has an extension to the #macro syntax that makes it easier to
call
macros that accept large strings as arguments.  For example a macro
that pretty-prints a chunk of source code.
-------------------------------------------------
* it integrates tightly with Webware.  Velocity doesn't integrate as
easily with Turbine.
-------------------------------------------------
* it has a plugin that enables PSP-style coding to be freely mixed in
with the Cheetah syntax.
-------------------------------------------------
* it is easy to add new #directives to Cheetah. You can't do this
easily in Velocity.
-------------------------------------------------
* the tokens that are used to signal the start of $placeholders and
#directives are
configurable. You can set them to any character sequences, not just $
and #.
-------------------------------------------------
* it has an extensive test suite (238 cases and counting)
-------------------------------------------------
===================================================

> At this point I guess the next question in regard to working out the best
> approach to all this, is whether one goes the direction of interpreting
> the page at the time of the request as I think Velocity might do, or to
> pregenerate Python classes to handle the request. 

Velocity builds a parse tree that it walks for each request.  Cheetah
translates into Python code and then lets Python generate the
byte-codes.  The idea is the same in both cases: the parsed code is
cached.  The advantage of the Cheetah was is that any valid Python
expression is valid inside $placeholder( ) argstrings and inside
directives such as #if [expression]. The same is not true of Velocity
and Java.  I'm not sure about the speed implications of these two
methods, but Cheetah is fast.
 
> Can you tell me what happens in the Cheetah/Webware case. If template files
> are changed, is the Python class automatically regenerated and reimported
> into the program? 

Yes, this happens automatically when it is used with Webware.  We're
also in the process of making it monitor file-updates when Cheetah is
used as a standalone tool.

The updated Cheetah docs should be live tonight.

I hope this info helps.
Cheers,
Tavis



More information about the Python-list mailing list