summaryrefslogtreecommitdiffstats
path: root/third_party/handlebar
diff options
context:
space:
mode:
authorcduvall@chromium.org <cduvall@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-16 16:52:38 +0000
committercduvall@chromium.org <cduvall@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-16 16:52:38 +0000
commite39f7ef422fd565807c642d23d3ca208d2e09d50 (patch)
tree4e767485bb3e1fa2eb503fafef5b421138d52706 /third_party/handlebar
parent7ec212442755bf33e30e9557f9d4b297f7fdafda (diff)
downloadchromium_src-e39f7ef422fd565807c642d23d3ca208d2e09d50.zip
chromium_src-e39f7ef422fd565807c642d23d3ca208d2e09d50.tar.gz
chromium_src-e39f7ef422fd565807c642d23d3ca208d2e09d50.tar.bz2
Extensions Docs Server: Handlebar update
Updated Handlebar to the newest version and changed some templates to take advantage of the else feature. BUG=131095 Review URL: https://chromiumcodereview.appspot.com/10704212 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146815 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/handlebar')
-rw-r--r--third_party/handlebar/README.chromium4
-rw-r--r--third_party/handlebar/handlebar.py136
2 files changed, 77 insertions, 63 deletions
diff --git a/third_party/handlebar/README.chromium b/third_party/handlebar/README.chromium
index 8eceaf7..0cdf182 100644
--- a/third_party/handlebar/README.chromium
+++ b/third_party/handlebar/README.chromium
@@ -2,8 +2,8 @@ Name: Handlebar, logic-less templating system
Short Name: handlebar
URL: https://github.com/kalman/templates
Version: 0
-Date: July 3, 2012
-Revision: commit 401c52a7d3e7496bb94cd12794865bba4dfe9374
+Date: July 13, 2012
+Revision: commit d69e6b7e2bcad0f9defd446ab531e875ebf56499
License: Apache License, Version 2.0
Security Critical: no
diff --git a/third_party/handlebar/handlebar.py b/third_party/handlebar/handlebar.py
index cfd761f..c1b1525 100644
--- a/third_party/handlebar/handlebar.py
+++ b/third_party/handlebar/handlebar.py
@@ -62,12 +62,15 @@ class StringBuilder(object):
"""
def __init__(self):
self._buf = []
+ self._length = 0
def __len__(self):
- return len(self._buf)
+ return self._length
def append(self, obj):
- self._buf.append(str(obj))
+ string = str(obj)
+ self._buf.append(string)
+ self._length += len(string)
def toString(self):
return ''.join(self._buf)
@@ -88,7 +91,7 @@ class RenderState(object):
def getFirstContext(self):
if len(self.localContexts) > 0:
return self.localContexts[0]
- elif len(self.globalContexts) > 0:
+ if len(self.globalContexts) > 0:
return self.globalContexts[0]
return None
@@ -135,16 +138,16 @@ class Identifier(object):
return self._resolveFromContext(renderState.getFirstContext())
resolved = self._resolveFromContexts(renderState.localContexts)
- if not resolved:
+ if resolved == None:
resolved = self._resolveFromContexts(renderState.globalContexts)
- if not resolved:
+ if resolved == None:
renderState.addError("Couldn't resolve identifier ", self._path)
return resolved
def _resolveFromContexts(self, contexts):
for context in contexts:
resolved = self._resolveFromContext(context)
- if resolved:
+ if resolved != None:
return resolved
return None
@@ -153,7 +156,7 @@ class Identifier(object):
for next in self._path:
# Only require that contexts provide a get method, meaning that callers
# can provide dict-like contexts (for example, to populate values lazily).
- if not result or not getattr(result, "get", None):
+ if result == None or not getattr(result, "get", None):
return None
result = result.get(next)
return result
@@ -246,7 +249,7 @@ class IndentedNode(DecoratorNode):
self._indent(renderState.text)
for i, c in enumerate(contentRenderState.text.toString()):
renderState.text.append(c)
- if c == '\n' and i < len(renderState.text) - 1:
+ if c == '\n' and i < len(contentRenderState.text) - 1:
self._indent(renderState.text)
renderState.text.append('\n')
@@ -345,7 +348,7 @@ class EscapedVariableNode(LeafNode):
def render(self, renderState):
value = self._id.resolve(renderState)
- if value:
+ if value != None:
self._appendEscapedHtml(renderState.text, str(value))
def _appendEscapedHtml(self, escaped, unescaped):
@@ -368,7 +371,7 @@ class UnescapedVariableNode(LeafNode):
def render(self, renderState):
value = self._id.resolve(renderState)
- if value:
+ if value != None:
renderState.text.append(value)
class SectionNode(DecoratorNode):
@@ -380,13 +383,11 @@ class SectionNode(DecoratorNode):
def render(self, renderState):
value = self._id.resolve(renderState)
- if not value:
+ if value == None:
return
type_ = type(value)
- if value == None:
- pass
- elif type_ == list:
+ if type_ == list:
for item in value:
renderState.localContexts.insert(0, item)
self._content.render(renderState)
@@ -407,24 +408,26 @@ class VertedSectionNode(DecoratorNode):
self._id = id
def render(self, renderState):
- value = self._id.resolve(renderState)
- if value and _VertedSectionNodeShouldRender(value):
+ value = self._id.resolve(renderState.inSameContext().disableErrors())
+ if _VertedSectionNodeShouldRender(value):
renderState.localContexts.insert(0, value)
self._content.render(renderState)
renderState.localContexts.pop(0)
def _VertedSectionNodeShouldRender(value):
- type_ = type(value)
if value == None:
return False
- elif type_ == bool:
+ type_ = type(value)
+ if type_ == bool:
return value
- elif type_ == int or type_ == float:
- return value > 0
- elif type_ == str or type_ == unicode:
- return value != ''
- elif type_ == list or type_ == dict:
+ if type_ == int or type_ == float:
+ return True
+ if type_ == str or type_ == unicode:
+ return True
+ if type_ == list:
return len(value) > 0
+ if type_ == dict:
+ return True
raise TypeError("Unhandled type: " + str(type_))
class InvertedSectionNode(DecoratorNode):
@@ -435,8 +438,8 @@ class InvertedSectionNode(DecoratorNode):
self._id = id
def render(self, renderState):
- value = self._id.resolve(renderState)
- if not value or not _VertedSectionNodeShouldRender(value):
+ value = self._id.resolve(renderState.inSameContext().disableErrors())
+ if not _VertedSectionNodeShouldRender(value):
self._content.render(renderState)
class JsonNode(LeafNode):
@@ -448,7 +451,7 @@ class JsonNode(LeafNode):
def render(self, renderState):
value = self._id.resolve(renderState)
- if value:
+ if value != None:
renderState.text.append(json.dumps(value, separators=(',',':')))
class PartialNode(LeafNode):
@@ -492,6 +495,10 @@ class PartialNode(LeafNode):
self._args = {}
self._args[key] = valueId
+# List of tokens in order of longest to shortest, to avoid any prefix matching
+# issues.
+TokenValues = []
+
class Token(object):
""" The tokens that can appear in a template.
"""
@@ -500,12 +507,21 @@ class Token(object):
self.name = name
self.text = text
self.clazz = clazz
+ TokenValues.append(self)
+
+ def elseNodeClass(self):
+ if self.clazz == VertedSectionNode:
+ return InvertedSectionNode
+ if self.clazz == InvertedSectionNode:
+ return VertedSectionNode
+ raise ValueError(self.clazz + " can not have an else clause.")
OPEN_START_SECTION = Data("OPEN_START_SECTION" , "{{#", SectionNode)
OPEN_START_VERTED_SECTION = Data("OPEN_START_VERTED_SECTION" , "{{?", VertedSectionNode)
OPEN_START_INVERTED_SECTION = Data("OPEN_START_INVERTED_SECTION", "{{^", InvertedSectionNode)
OPEN_START_JSON = Data("OPEN_START_JSON" , "{{*", JsonNode)
OPEN_START_PARTIAL = Data("OPEN_START_PARTIAL" , "{{+", PartialNode)
+ OPEN_ELSE = Data("OPEN_ELSE" , "{{:", None)
OPEN_END_SECTION = Data("OPEN_END_SECTION" , "{{/", None)
OPEN_UNESCAPED_VARIABLE = Data("OPEN_UNESCAPED_VARIABLE" , "{{{", UnescapedVariableNode)
CLOSE_MUSTACHE3 = Data("CLOSE_MUSTACHE3" , "}}}", None)
@@ -515,24 +531,6 @@ class Token(object):
CLOSE_MUSTACHE = Data("CLOSE_MUSTACHE" , "}}" , None)
CHARACTER = Data("CHARACTER" , "." , None)
-# List of tokens in order of longest to shortest, to avoid any prefix matching
-# issues.
-_tokenList = [
- Token.OPEN_START_SECTION,
- Token.OPEN_START_VERTED_SECTION,
- Token.OPEN_START_INVERTED_SECTION,
- Token.OPEN_START_JSON,
- Token.OPEN_START_PARTIAL,
- Token.OPEN_END_SECTION,
- Token.OPEN_UNESCAPED_VARIABLE,
- Token.CLOSE_MUSTACHE3,
- Token.OPEN_COMMENT,
- Token.CLOSE_COMMENT,
- Token.OPEN_VARIABLE,
- Token.CLOSE_MUSTACHE,
- Token.CHARACTER
-]
-
class TokenStream(object):
""" Tokeniser for template parsing.
"""
@@ -557,12 +555,12 @@ class TokenStream(object):
if self._remainder == '':
return None
- for token in _tokenList:
+ for token in TokenValues:
if self._remainder.startswith(token.text):
self.nextToken = token
break
- if self.nextToken == None:
+ if not self.nextToken:
self.nextToken = Token.CHARACTER
self.nextContents = self._remainder[0:len(self.nextToken.text)]
@@ -592,7 +590,7 @@ class Handlebar(object):
tokens = TokenStream(template)
self._topNode = self._parseSection(tokens)
if not self._topNode:
- raise ParseException("Template is empty")
+ raise ParseException("Template is empty", tokens.nextLine)
if tokens.hasNext():
raise ParseException("There are still tokens remaining, "
"was there an end-section without a start-section:",
@@ -604,17 +602,16 @@ class Handlebar(object):
while tokens.hasNext() and not sectionEnded:
token = tokens.nextToken
- node = None
if token == Token.CHARACTER:
startLine = tokens.nextLine
string = tokens.advanceOverNextString()
- node = StringNode(string, startLine, tokens.nextLine)
+ nodes.append(StringNode(string, startLine, tokens.nextLine))
elif token == Token.OPEN_VARIABLE or \
token == Token.OPEN_UNESCAPED_VARIABLE or \
token == Token.OPEN_START_JSON:
id = self._openSectionOrTag(tokens)
- node = token.clazz(id, tokens.nextLine)
+ nodes.append(token.clazz(id, tokens.nextLine))
elif token == Token.OPEN_START_PARTIAL:
tokens.advance()
id = Identifier(tokens.advanceOverNextString(excluded=' '),
@@ -631,18 +628,30 @@ class Handlebar(object):
tokens.nextLine))
tokens.advanceOver(Token.CLOSE_MUSTACHE)
- node = partialNode
- elif token == Token.OPEN_START_SECTION or \
- token == Token.OPEN_START_VERTED_SECTION or \
+ nodes.append(partialNode)
+ elif token == Token.OPEN_START_SECTION:
+ id = self._openSectionOrTag(tokens)
+ section = self._parseSection(tokens)
+ self._closeSection(tokens, id)
+ if section:
+ nodes.append(SectionNode(id, section))
+ elif token == Token.OPEN_START_VERTED_SECTION or \
token == Token.OPEN_START_INVERTED_SECTION:
id = self._openSectionOrTag(tokens)
section = self._parseSection(tokens)
+ elseSection = None
+ if tokens.nextToken == Token.OPEN_ELSE:
+ self._openElse(tokens, id)
+ elseSection = self._parseSection(tokens)
self._closeSection(tokens, id)
if section:
- node = token.clazz(id, section)
+ nodes.append(token.clazz(id, section))
+ if elseSection:
+ nodes.append(token.elseNodeClass()(id, elseSection))
elif token == Token.OPEN_COMMENT:
self._advanceOverComment(tokens)
- elif token == Token.OPEN_END_SECTION:
+ elif token == Token.OPEN_END_SECTION or \
+ token == Token.OPEN_ELSE:
# Handled after running parseSection within the SECTION cases, so this is a
# terminating condition. If there *is* an orphaned OPEN_END_SECTION, it will be caught
# by noticing that there are leftover tokens after termination.
@@ -651,9 +660,6 @@ class Handlebar(object):
raise ParseException("Orphaned " + tokens.nextToken.name,
tokens.nextLine)
- if node:
- nodes.append(node)
-
for i, node in enumerate(nodes):
if isinstance(node, StringNode):
continue
@@ -669,8 +675,8 @@ class Handlebar(object):
if nextNode:
nextNode.trimStartingNewLine()
elif isinstance(node, LeafNode) and \
- (previousNode == None or previousNode.endsWithEmptyLine()) and \
- (nextNode == None or nextNode.startsWithNewLine()):
+ (not previousNode or previousNode.endsWithEmptyLine()) and \
+ (not nextNode or nextNode.startsWithNewLine()):
indentation = 0
if previousNode:
indentation = previousNode.trimEndingSpaces()
@@ -713,7 +719,15 @@ class Handlebar(object):
nextString = tokens.advanceOverNextString()
if nextString != '' and nextString != str(id):
raise ParseException(
- "Start section " + str(id) + " doesn't match end section " + nextString)
+ "Start section " + str(id) + " doesn't match end " + nextString)
+ tokens.advanceOver(Token.CLOSE_MUSTACHE)
+
+ def _openElse(self, tokens, id):
+ tokens.advanceOver(Token.OPEN_ELSE)
+ nextString = tokens.advanceOverNextString()
+ if nextString != '' and nextString != str(id):
+ raise ParseException(
+ "Start section " + str(id) + " doesn't match else " + nextString)
tokens.advanceOver(Token.CLOSE_MUSTACHE)
def render(self, *contexts):