On Dec 17, 2007 12:10 PM, Ian Bicking <[EMAIL PROTECTED]> wrote:
> Mike Orr wrote:
> > StringTemplateRenderer.__init__ takes a loader, but
> > StringTemplateRenderer.render doesn't use it.  Isn't it supposed to?
> > Or am I supposed to load the template separately?
>
> It doesn't use it because template_object is an already-loaded object.
> If it allowed for template references (something like #extends) then it
> would use self.loader for that.  Though... maybe template_object should
> just have a loader attribute or method?  That would be a method on
> FileSource in the reference loader.  That would remove the loader from
> the renderer object almost entirely, which would make things a little
> cleaner I think.
>
> > Also, the last line of .render should have 'template_object' instead of 
> > 'tmpl'.
>
> Thanks, fixed.  Do you want commit there?  If so, send me a line from
> htpasswd.

Thanks, I'll do it when I get home.

Right now I've got minimal Mako and Genshi renderers, and a Nose test
for them.  They don't take options yet.

I've also refactored things a bit to straighten out the terminology in
preparation for user docs.  (TemplateProposal doesn't say how to *use*
it.)  I want to focus on:

- Engine: the underlying template engine.

- Renderer: the interface between user code and the underlying engine.
 ("plugin" or "engine" in Buffet 1)  This is sometimes called "engine"
or "template" in TemplateProposal, which is confusing.

- Template (=> FileTemplate), a wrapper for template source code.
TemplateProposal sometimes calls this something Source, but I think
that's more cumbersome without being substantially clearer.  It's
perfectly appropriate for TemplateProposal to define what *it* thinks
a template is, a wrapper around a native template like Renderer is a
wrapper around an underlying engine.

- Loader (=> FileLoader) is an object that knows how to look up a
template by name and return a Template instance.

There are two ways to go with the loader:
    t = loader("mytemplate.html")
    output = renderer.render(t, variables)
Or:
    output = renderer.render("mytemplate.html", variables)  # Uses
loader in Renderer's constructor.

The latter really makes more sense to recommend.  The loader doesn't
know which renderer a template is compatible with.  The user just has
to "know" which template to feed to which renderer.  Why not make
this explicit and let the renderer manage the loader?  That makes the
object orientation more orderly.
Of course, we should allow an externally-loaded template to be passed
in, but that shouldn't be the general recommendation.

In applications, users choose the renderer, then the template.  Or
they leverage the default renderer, which is the same thing.  Nobody
has written code to choose a renderer based on the template.  So
having the renderer manage the loader makes sense.

This brings us to another issue.  In a multi-renderer deployment,
should we recommend a common loader or let each renderer have a
separate loader instance?  This affects Pylons' environment.py as well
as the internal pylons.wsgiapp and pylons.templating.  Some users will
want a different templates directory per engine, which necessitates a
renderer-specific loader.  Others will pull from the preconfigured
'templates' directory.  But even in that case, the templates
themselves are renderer-specific, so the templates are implicitly
grouped by renderer even with a common loader.  And if the user
instructs two renderers with private loaders to both load the same
template file, what harm is done?

This further gets us to template caching.  TemplateProposal provides
cacheable templates but no infrastructure to store them.  This
naturally belongs to the loader.  Even if we don't provide a template
cache, we should at least map out how the user would build one, either
with a Loader subclass or externally.

StringTemplateRenderer passes the template as a string to the
underlying engine.  Is that because string.Template can't load from a
filename, or is it recommended for all renderers?  I wrote
MakoRenderer and GenshiRenderer in their preferred manner (Mako takes
a filename, Genshi a file object).  Of course MakoRenderer barely uses
the Template object at all; it just reads the .real_filename attribute
and ignores the access methods.  This will be the case with most
Renderers if we go the filename route.  But I believe Genshi accepts
only a file object and nothing else.

I think we should support FileLoader and FileTemplate as the standard
loader & template out of the box, and leave Loader and Template as
abstract interfaces.  95% of the time users will want file-based
templates.  Template.open() requires a file-like object if the
template is not file-based, which is fine.

I still don't see how you think we can pass a Loader to an underlying
engine, given that none of the existing engines have hooks for it.
You can pass the appropriate attributes to Mako's TemplateLookup and
Template constructors, but that's it.  Which then brings us to: should
MakoRenderer create a Mako TemplateLookup at instantiation or for each
render, or ignore TemplateLookup completely?

Mako also has its own template caching, but for that we need to pass
in a data directory.  Currently the only way to do that is with an
engine-specific option.  But a Loader with caching could do the
equivalent.

There will be more issues with template options and rendering options,
especially trying to rationalize Pylons' existing built-in options.
I'm tempted to move from this:

    config['buffet.template_options']   # Default options like "kid.encoding".
    config['buffet.template_engines']  # List of {entry point, root
dir, options, alias} dicts.
    config.add_template_engine()        # Front end for previous.

To this:

    config['template_options']['kid']['encoding'] = 'utf8'
    config['template_engines'] => dict keyed by engine name
    config['default_template_engine'] = 'genshi'

Either that or *something* in Pylons or the Renderers should extract
and unprefix the template options so they can be passed directly to
the underlying engines.

I want to move the default configuration for several renderers into
some more appropriate structure grouped by renderer.  I also want to
move pylonsmyghty out of pylons.templates into a separate module or
distribution.  But I'm not going to be able to implement pylonsmyghty
by myself; I couldn't get the unit test to work in Smorgasbord 0.1.
Can we stop supporting Myghty yet?

-- 
Mike Orr <[EMAIL PROTECTED]>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pylons-devel" group.
To post to this group, send email to pylons-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/pylons-devel?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to