OLD | NEW |
1 # Copyright 2012 Benjamin Kalman | 1 # Copyright 2012 Benjamin Kalman |
2 # | 2 # |
3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
6 # | 6 # |
7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
8 # | 8 # |
9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 25 matching lines...) Expand all Loading... |
36 a get() method. | 36 a get() method. |
37 | 37 |
38 class CustomContext(object): | 38 class CustomContext(object): |
39 def get(self, key): | 39 def get(self, key): |
40 return 10 | 40 return 10 |
41 | 41 |
42 # Any time {{ }} is used, will fill it with 10. | 42 # Any time {{ }} is used, will fill it with 10. |
43 print(Handlebar('hello {{world}}').render(CustomContext()).text) | 43 print(Handlebar('hello {{world}}').render(CustomContext()).text) |
44 """ | 44 """ |
45 | 45 |
| 46 def _SafeStr(obj): |
| 47 return obj if (type(obj) in [str, unicode]) else str(obj) |
| 48 |
46 class ParseException(Exception): | 49 class ParseException(Exception): |
47 """ Exception thrown while parsing the template. | 50 """ Exception thrown while parsing the template. |
48 """ | 51 """ |
49 def __init__(self, error, line): | 52 def __init__(self, error, line): |
50 Exception.__init__(self, "%s (line %s)" % (error, line.number)) | 53 Exception.__init__(self, "%s (line %s)" % (error, line.number)) |
51 | 54 |
52 class RenderResult(object): | 55 class RenderResult(object): |
53 """ Result of a render operation. | 56 """ Result of a render operation. |
54 """ | 57 """ |
55 def __init__(self, text, errors): | 58 def __init__(self, text, errors): |
56 self.text = text; | 59 self.text = text; |
57 self.errors = errors | 60 self.errors = errors |
58 | 61 |
59 class StringBuilder(object): | 62 class StringBuilder(object): |
60 """ Mimics Java's StringBuilder for easy porting from the Java version of | 63 """ Mimics Java's StringBuilder for easy porting from the Java version of |
61 this file to Python. | 64 this file to Python. |
62 """ | 65 """ |
63 def __init__(self): | 66 def __init__(self): |
64 self._buf = [] | 67 self._buf = [] |
65 self._length = 0 | 68 self._length = 0 |
66 | 69 |
67 def __len__(self): | 70 def __len__(self): |
68 return self._length | 71 return self._length |
69 | 72 |
70 def append(self, obj): | 73 def append(self, obj): |
71 string = str(obj) | 74 string = _SafeStr(obj) |
72 self._buf.append(string) | 75 self._buf.append(string) |
73 self._length += len(string) | 76 self._length += len(string) |
74 | 77 |
75 def toString(self): | 78 def toString(self): |
76 return ''.join(self._buf) | 79 return u''.join(self._buf) |
| 80 |
| 81 def __str__(self): |
| 82 return self.toString() |
77 | 83 |
78 class RenderState(object): | 84 class RenderState(object): |
79 """ The state of a render call. | 85 """ The state of a render call. |
80 """ | 86 """ |
81 def __init__(self, globalContexts, localContexts): | 87 def __init__(self, globalContexts, localContexts): |
82 self.globalContexts = globalContexts | 88 self.globalContexts = globalContexts |
83 self.localContexts = localContexts | 89 self.localContexts = localContexts |
84 self.text = StringBuilder() | 90 self.text = StringBuilder() |
85 self.errors = [] | 91 self.errors = [] |
86 self._errorsDisabled = False | 92 self._errorsDisabled = False |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 class EscapedVariableNode(LeafNode): | 348 class EscapedVariableNode(LeafNode): |
343 """ {{foo}} | 349 """ {{foo}} |
344 """ | 350 """ |
345 def __init__(self, id, line): | 351 def __init__(self, id, line): |
346 LeafNode.__init__(self, line) | 352 LeafNode.__init__(self, line) |
347 self._id = id | 353 self._id = id |
348 | 354 |
349 def render(self, renderState): | 355 def render(self, renderState): |
350 value = self._id.resolve(renderState) | 356 value = self._id.resolve(renderState) |
351 if value != None: | 357 if value != None: |
352 self._appendEscapedHtml(renderState.text, str(value)) | 358 self._appendEscapedHtml(renderState.text, _SafeStr(value)) |
353 | 359 |
354 def _appendEscapedHtml(self, escaped, unescaped): | 360 def _appendEscapedHtml(self, escaped, unescaped): |
355 for c in unescaped: | 361 for c in unescaped: |
356 if c == '<': | 362 if c == '<': |
357 escaped.append("<") | 363 escaped.append("<") |
358 elif c == '>': | 364 elif c == '>': |
359 escaped.append(">") | 365 escaped.append(">") |
360 elif c == '&': | 366 elif c == '&': |
361 escaped.append("&") | 367 escaped.append("&") |
362 else: | 368 else: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 renderState.localContexts.insert(0, value) | 419 renderState.localContexts.insert(0, value) |
414 self._content.render(renderState) | 420 self._content.render(renderState) |
415 renderState.localContexts.pop(0) | 421 renderState.localContexts.pop(0) |
416 | 422 |
417 def _VertedSectionNodeShouldRender(value): | 423 def _VertedSectionNodeShouldRender(value): |
418 if value == None: | 424 if value == None: |
419 return False | 425 return False |
420 type_ = type(value) | 426 type_ = type(value) |
421 if type_ == bool: | 427 if type_ == bool: |
422 return value | 428 return value |
423 if type_ == int or type_ == float: | 429 if type_ in [int, float]: |
424 return True | 430 return True |
425 if type_ == str or type_ == unicode: | 431 if type_ in [str, unicode]: |
426 return True | 432 return True |
427 if type_ == list: | 433 if type_ == list: |
428 return len(value) > 0 | 434 return len(value) > 0 |
429 if type_ == dict: | 435 if type_ == dict: |
430 return True | 436 return True |
431 raise TypeError("Unhandled type: " + str(type_)) | 437 raise TypeError("Unhandled type: " + str(type_)) |
432 | 438 |
433 class InvertedSectionNode(DecoratorNode): | 439 class InvertedSectionNode(DecoratorNode): |
434 """ {{^foo}} ... {{/}} | 440 """ {{^foo}} ... {{/}} |
435 """ | 441 """ |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 def render(self, *contexts): | 739 def render(self, *contexts): |
734 """ Renders this template given a variable number of "contexts" to read | 740 """ Renders this template given a variable number of "contexts" to read |
735 out values from (such as those appearing in {{foo}}). | 741 out values from (such as those appearing in {{foo}}). |
736 """ | 742 """ |
737 globalContexts = [] | 743 globalContexts = [] |
738 for context in contexts: | 744 for context in contexts: |
739 globalContexts.append(context) | 745 globalContexts.append(context) |
740 renderState = RenderState(globalContexts, []) | 746 renderState = RenderState(globalContexts, []) |
741 self._topNode.render(renderState) | 747 self._topNode.render(renderState) |
742 return renderState.getResult() | 748 return renderState.getResult() |
OLD | NEW |