[Web-SIG] Standardized template API
ianb at colorstudy.com
Wed Feb 1 00:01:36 CET 2006
Phillip J. Eby wrote:
> At 02:03 PM 1/31/2006 -0500, Clark C. Evans wrote:
>> I'd stick with the notion of a "template_name" that is neither the
>> template file nor the template body. Then you'd want a template factory
>> method that takes the name and produces the template body (complied if
>> necessary). This needs to be once indirect since a template may refer
>> to other sub-templates. This way your template could be stored
>> in-memory, on-disk, or in a database, or even remotely using an HTTP
>> cashe. The actual storage mechanism for the template source code should
>> not be part of this interface.
> I'd go even further than this, to note that frameworks need to be able
> to cache "compiled" versions of templates. The template "engine" should
> be able to return a "compiled" template that the framework can use to do
> rendering in future.
The plugin instance itself can manage the caching. I believe current
implementations do that (at least TurboCheetah does). Is there anything
the framework can do for caching that the plugin instance can't?
> Note too that frameworks such as Zope 3 and peak.web have concepts like
> localization and "skinning" that require the ability to switch out the
> actual provider of a named template or "view", and in at least the case
> of peak.web this can be polymorphic. That is, one "skin" could
> implement template "foo" using Kid and another one using ZPT. So the
> name of a template needs to be independent of its implementation
> language, or the ability to plug in different engines is moot.
> (Currently, TurboGears embeds the chosen template language in code,
> which means a deployer can't skin the application effectively.)
I believe that custom find_template implementations could handle these
cases. Maybe there also needs to be a relative_to_template_name
argument to find_template, so that it can resolve template names
relative to the calling template (so, for instance, you can use relative
names to the template you inherit from).
> Finally, I'd note that an increasingly common use case for template
> storage is likely to be via pkg_resources lookup, so that applications
> can be deployed as eggs. Ideally, future versions of Zope 3 and
> peak.web would perhaps allow one egg to provide skins or "layers" for
> views defined in other eggs, so that users can plug in third-party skins
> for applications.
If find_template returns a template object instead of a filename, this
would be easier. As it is it could produce an actual filename (with
pkg_resources.resource_filename), but that seems unnecessary as I think
> Actually, if we're going to come up with something really useful here,
> it would probably be a good idea to expand the scope from just defining
> templates, to defining a "resource access" protocol to cover both static
> resource files and templates that may need to be localized or skinned.
> That would be a much bigger win, IMO, since it would put more control in
> the hands of deployers and customizers, instead of just making it
> possible for developers to use whatever template language they fancy. :)
That seems to be an extension of find_template, which isn't specified
much in this proposal. But we could specify that, I suppose:
def find_resource(resource_type, resource_name, relative_to=None):
Return a resource_type kind of resource, with the given name. If
relative_to (a resource name) is given and relative names are
supported, then do so.
def load_resource(resource_name, finder, resource_filename=None,
Returns the resource. resource_name is an opaque identifier,
but should be kept. finder is an implementation of
find_resource. The resource content can be identified with a
string or filename [other kinds?]. If both are given, filename
can be used for debugging output, but string should be used as
the actual content. If the resource refers to other resources
then the finder should be used for retrieving those resources.
def __init__(extra_vars_func=None, options=None):
Create a template plugin instance. extra_vars_func is a
function that returns a dictionary of "standard" variables
for the environment. options is a dictionary of options
for the template (e.g., compiler settings) with no defined
Return an instance of the template. No interface for the
return value is defined, but the return value can be used
Note that some templating languages don't work well with
render(), so the returned resource may be the more useful
interface, and frameworks should allow users to get at this
return value directly.
def render(template_instance, vars, format="html", fragment=False):
Render the template instance (as returned by load_resource)
to a string [unicode?]. vars is typically a dictionary (-like
object) of variables for use in substitution. format may be
"xhtml", "plain", etc., but plugins may ignore that value.
"fragment" indicates if an incomplete document should be created
(e.g., with no DOCTYPE); again templates may ignore this.
[instead of transform, can we have this not necessarily return
strings, e.g., format="elementtree"?]
So now you'd use it like:
tmpl_plugin = CheetahPlugin()
tmpl = my_finder(tmpl_plugin, 'foo.tmpl')
print tmpl_plugin.render(tmpl, locals())
Where before it would be:
tmpl_plugin = CheetahPlugin()
print tmpl_plugin.render(locals(), template='foo.tmpl')
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
More information about the Web-SIG