Browse files

renderer overhaul intentions

  • Loading branch information...
1 parent 4419efc commit 388f9d4185f9a4cbf80f63983295e5018b95a6ba Chris McDonough committed May 24, 2010
Showing with 108 additions and 0 deletions.
  1. +108 −0 TODO.txt
108 TODO.txt
@@ -11,3 +11,111 @@
- Docs about creating a venusian decorator.
+Renderer overhaul
+Currently the division of responsibility between the BFG configurator
+and a BFG renderer implementation is awkward and wrong.
+- Renderer factories have no ability to convert a raw ``renderer=``
+ path (e.g. ``templates/```) into something internally
+ meaningful. Instead, BFG mangles the string into a package-relative
+ spec before it is passed to the renderer factory. This is wrong, as
+ some renderers may not be interested in package-relative specs at
+ all (for instance, loader-style renderers which have a hardcoded set
+ of template locations). The reason, however, that BFG currently
+ does it this way is that the raw renderer path alone does not
+ contain enough information itself to be useful; knowledge of the
+ *package* is also required for package-based renderers to make sense
+ of relative renderer strings (e.g. ``templates/`` could mean
+ the ``templates/`` file within the ``mypackage`` package).
+ To fix this, we need to provide some way to pass the package name to
+ the renderer factory as well as the renderer path. But the package
+ name isn't the only thing an *arbitrary* renderer might need.
+ Another renderer might need, for example, a deployment setting. So
+ we'll need to identify all the crap that *might* be useful to a
+ renderer factory and we'll need to pass all of it into the renderer
+ factory as a garbage barge dictionary; individual renderers will
+ make use of whatever they can from that garbage barge dictionary.
+ Garbage barge dict item candidates: ``package`` (the "current"
+ package), ``config`` (the configurator), ``package_name`` (the
+ current package's ``__name__``), ``settings`` (the deployment
+ settings), ``registry`` (the component registry).
+- A BFG renderer currently returns a *string*. It would be more
+ symmetric if a renderer always returned a Response object. Then the
+ calling machinery inside BFG could treat a view which happened to
+ use a renderer exactly the same as a view which returns a response
+ directly. Maybe. Problem: varying response attributes such as
+ ``content-type``, etc only makes sense when the view callable uses a
+ renderer; not when it doesn't, so there's some asymmetry there.
+ Maybe we make renderers return Responses, but still keep the
+ attribute-inspection stuff inside BFG, only used when we call a view
+ which we know uses a renderer. We *could* always call the attribute
+ inspection stuff, but it would be a slowdown in cases where views
+ really do always return a Response directly.
+- The ``system`` value passed to a renderer is not extensible. It
+ should be extensible on a per-application basis. For example, you
+ might want to add a top-level variable ``c`` to the values passed to
+ all renderers representing a template context to emulate Pylons.
+- ``repoze.bfg.chameleon_zpt.render_template_to_response``, et. al. do
+ not use the same machinery as view renderers. It would be useful if
+ templates rendered with ``render_template_to_response`` had the same
+ ``system`` values available to it as templates renderered via a view
+ renderer.
+To at least partially ameliorate the above, renderer factories should
+be changed to things that have a set of interfaces something like
+ class IRendererFactory(Interface):
+ def __call__(path, info):
+ "" Return an IRenderer."""
+ class IRenderer(Interface):
+ def __call__(value, system):
+ """ Return a Response """
+A semi-pseudocode example:
+ from webob import Response
+ class SampleRendererFactory(object):
+ def __init__(self, **config):
+ self.config = config
+ def __call__(self, path, info):
+ path = do_something_to_evaluate_path_using_info(path, info)
+ search_path = self.config['search_path']
+ debug = self.config['debug']
+ def renderer(value, system):
+ string = do_rendering(search_path, debug, path, value, system)
+ return Response(string)
+ return renderer
+ if __name__ == '__main__':
+ def view1(request):
+ return {'a':1}
+ def view2(request):
+ return {'a':2}
+ renderer_factory = SampleRendererFactory(search_path=['/a', '/b'])
+ package_name = 'some.package'
+ for view, path in [
+ (view1, 'templates/'),
+ (view2, 'templates/'),
+ ]:
+ renderer = renderer_factory(path, dict(package_name=package_name))
+ register_renderer_for_view(renderer, view)
+This is mostly an amelioration for the first and second bullet points
+above. The second two bullet points are not addressed by it.

0 comments on commit 388f9d4

Please sign in to comment.