Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: third_party/pystache/src/renderengine.py

Issue 2962783004: Adding pystache to third_party (Closed)
Patch Set: Merge branch 'master' into mustache Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/pystache/src/parser.py ('k') | third_party/pystache/src/renderer.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # coding: utf-8
2
3 """
4 Defines a class responsible for rendering logic.
5
6 """
7
8 import re
9
10 from pystache.common import is_string
11 from pystache.parser import parse
12
13
14 def context_get(stack, name):
15 """
16 Find and return a name from a ContextStack instance.
17
18 """
19 return stack.get(name)
20
21
22 class RenderEngine(object):
23
24 """
25 Provides a render() method.
26
27 This class is meant only for internal use.
28
29 As a rule, the code in this class operates on unicode strings where
30 possible rather than, say, strings of type str or markupsafe.Markup.
31 This means that strings obtained from "external" sources like partials
32 and variable tag values are immediately converted to unicode (or
33 escaped and converted to unicode) before being operated on further.
34 This makes maintaining, reasoning about, and testing the correctness
35 of the code much simpler. In particular, it keeps the implementation
36 of this class independent of the API details of one (or possibly more)
37 unicode subclasses (e.g. markupsafe.Markup).
38
39 """
40
41 # TODO: it would probably be better for the constructor to accept
42 # and set as an attribute a single RenderResolver instance
43 # that encapsulates the customizable aspects of converting
44 # strings and resolving partials and names from context.
45 def __init__(self, literal=None, escape=None, resolve_context=None,
46 resolve_partial=None, to_str=None):
47 """
48 Arguments:
49
50 literal: the function used to convert unescaped variable tag
51 values to unicode, e.g. the value corresponding to a tag
52 "{{{name}}}". The function should accept a string of type
53 str or unicode (or a subclass) and return a string of type
54 unicode (but not a proper subclass of unicode).
55 This class will only pass basestring instances to this
56 function. For example, it will call str() on integer variable
57 values prior to passing them to this function.
58
59 escape: the function used to escape and convert variable tag
60 values to unicode, e.g. the value corresponding to a tag
61 "{{name}}". The function should obey the same properties
62 described above for the "literal" function argument.
63 This function should take care to convert any str
64 arguments to unicode just as the literal function should, as
65 this class will not pass tag values to literal prior to passing
66 them to this function. This allows for more flexibility,
67 for example using a custom escape function that handles
68 incoming strings of type markupsafe.Markup differently
69 from plain unicode strings.
70
71 resolve_context: the function to call to resolve a name against
72 a context stack. The function should accept two positional
73 arguments: a ContextStack instance and a name to resolve.
74
75 resolve_partial: the function to call when loading a partial.
76 The function should accept a template name string and return a
77 template string of type unicode (not a subclass).
78
79 to_str: a function that accepts an object and returns a string (e.g.
80 the built-in function str). This function is used for string
81 coercion whenever a string is required (e.g. for converting None
82 or 0 to a string).
83
84 """
85 self.escape = escape
86 self.literal = literal
87 self.resolve_context = resolve_context
88 self.resolve_partial = resolve_partial
89 self.to_str = to_str
90
91 # TODO: Rename context to stack throughout this module.
92
93 # From the spec:
94 #
95 # When used as the data value for an Interpolation tag, the lambda
96 # MUST be treatable as an arity 0 function, and invoked as such.
97 # The returned value MUST be rendered against the default delimiters,
98 # then interpolated in place of the lambda.
99 #
100 def fetch_string(self, context, name):
101 """
102 Get a value from the given context as a basestring instance.
103
104 """
105 val = self.resolve_context(context, name)
106
107 if callable(val):
108 # Return because _render_value() is already a string.
109 return self._render_value(val(), context)
110
111 if not is_string(val):
112 return self.to_str(val)
113
114 return val
115
116 def fetch_section_data(self, context, name):
117 """
118 Fetch the value of a section as a list.
119
120 """
121 data = self.resolve_context(context, name)
122
123 # From the spec:
124 #
125 # If the data is not of a list type, it is coerced into a list
126 # as follows: if the data is truthy (e.g. `!!data == true`),
127 # use a single-element list containing the data, otherwise use
128 # an empty list.
129 #
130 if not data:
131 data = []
132 else:
133 # The least brittle way to determine whether something
134 # supports iteration is by trying to call iter() on it:
135 #
136 # http://docs.python.org/library/functions.html#iter
137 #
138 # It is not sufficient, for example, to check whether the item
139 # implements __iter__ () (the iteration protocol). There is
140 # also __getitem__() (the sequence protocol). In Python 2,
141 # strings do not implement __iter__(), but in Python 3 they do.
142 try:
143 iter(data)
144 except TypeError:
145 # Then the value does not support iteration.
146 data = [data]
147 else:
148 if is_string(data) or isinstance(data, dict):
149 # Do not treat strings and dicts (which are iterable) as lis ts.
150 data = [data]
151 # Otherwise, treat the value as a list.
152
153 return data
154
155 def _render_value(self, val, context, delimiters=None):
156 """
157 Render an arbitrary value.
158
159 """
160 if not is_string(val):
161 # In case the template is an integer, for example.
162 val = self.to_str(val)
163 if type(val) is not unicode:
164 val = self.literal(val)
165 return self.render(val, context, delimiters)
166
167 def render(self, template, context_stack, delimiters=None):
168 """
169 Render a unicode template string, and return as unicode.
170
171 Arguments:
172
173 template: a template string of type unicode (but not a proper
174 subclass of unicode).
175
176 context_stack: a ContextStack instance.
177
178 """
179 parsed_template = parse(template, delimiters)
180
181 return parsed_template.render(self, context_stack)
OLDNEW
« no previous file with comments | « third_party/pystache/src/parser.py ('k') | third_party/pystache/src/renderer.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698