1 # -*- test-case-name: twisted.web.test.test_template -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
5 from zope.interface import implements
7 from twisted.web.iweb import IRenderable
9 from twisted.web.error import MissingRenderMethod, UnexposedMethodError
10 from twisted.web.error import MissingTemplateLoader
15 Helper for exposing methods for various uses using a simple decorator-style
18 Instances of this class can be called with one or more functions as
19 positional arguments. The names of these functions will be added to a list
20 on the class object of which they are methods.
22 @ivar attributeName: The attribute with which exposed methods will be
25 def __init__(self, doc=None):
29 def __call__(self, *funcObjs):
31 Add one or more functions to the set of exposed functions.
33 This is a way to declare something about a class definition, similar to
34 L{zope.interface.implements}. Use it like this::
36 magic = Expose('perform extra magic')
38 def twiddle(self, x, y):
44 Later you can query the object::
47 magic.get(aFoo, 'twiddle')(x=1, y=2)
49 The call to C{get} will fail if the name it is given has not been
50 exposed using C{magic}.
52 @param funcObjs: One or more function objects which will be exposed to
55 @return: The first of C{funcObjs}.
58 raise TypeError("expose() takes at least 1 argument (0 given)")
60 fObj.exposedThrough = getattr(fObj, 'exposedThrough', [])
61 fObj.exposedThrough.append(self)
66 def get(self, instance, methodName, default=_nodefault):
68 Retrieve an exposed method with the given name from the given instance.
70 @raise UnexposedMethodError: Raised if C{default} is not specified and
71 there is no exposed method with the given name.
73 @return: A callable object for the named method assigned to the given
76 method = getattr(instance, methodName, None)
77 exposedThrough = getattr(method, 'exposedThrough', [])
78 if self not in exposedThrough:
79 if default is self._nodefault:
80 raise UnexposedMethodError(self, methodName)
86 def _withDocumentation(cls, thunk):
88 Slight hack to make users of this class appear to have a docstring to
89 documentation generators, by defining them with a decorator. (This hack
90 should be removed when epydoc can be convinced to use some other method
93 return cls(thunk.__doc__)
96 # Avoid exposing the ugly, private classmethod name in the docs. Luckily this
97 # namespace is private already so this doesn't leak further.
98 exposer = Expose._withDocumentation
103 Decorate with L{renderer} to use methods as template render directives.
109 def twiddle(self, request, tag):
110 return tag('Hello, world.')
112 <div xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
113 <span t:render="twiddle" />
116 Will result in this final output::
119 <span>Hello, world.</span>
125 class Element(object):
127 Base for classes which can render part of a page.
129 An Element is a renderer that can be embedded in a stan document and can
130 hook its template (from the loader) up to render methods.
132 An Element might be used to encapsulate the rendering of a complex piece of
133 data which is to be displayed in multiple different contexts. The Element
134 allows the rendering logic to be easily re-used in different ways.
136 Element returns render methods which are registered using
137 L{twisted.web.element.renderer}. For example::
141 def items(self, request, tag):
144 Render methods are invoked with two arguments: first, the
145 L{twisted.web.http.Request} being served and second, the tag object which
146 "invoked" the render method.
148 @type loader: L{ITemplateLoader} provider
149 @ivar loader: The factory which will be used to load documents to
150 return from C{render}.
152 implements(IRenderable)
155 def __init__(self, loader=None):
156 if loader is not None:
160 def lookupRenderMethod(self, name):
162 Look up and return the named render method.
164 method = renderer.get(self, name, None)
166 raise MissingRenderMethod(self, name)
170 def render(self, request):
172 Implement L{IRenderable} to allow one L{Element} to be embedded in
173 another's template or rendering output.
175 (This will simply load the template from the C{loader}; when used in a
176 template, the flattening engine will keep track of this object
177 separately as the object to lookup renderers on and call
178 L{Element.renderer} to look them up. The resulting object from this
179 method is not directly associated with this L{Element}.)
183 raise MissingTemplateLoader(self)