Skip to content

Commit

Permalink
Require braces for interpolation expression everywhere except inside …
Browse files Browse the repository at this point in the history
…the ``string:`` expression type.
  • Loading branch information
malthe committed Jul 25, 2011
1 parent 9c5bb74 commit b5a2160
Show file tree
Hide file tree
Showing 13 changed files with 46 additions and 17 deletions.
12 changes: 12 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Changes
=======

In next release...

Features:

- Expression interpolation (using the ``${...}`` operator and
previously also ``$identifier``) now requires braces everywhere
except inside the ``string:`` expression type.

This change is motivated by a number of legacy templates in which
the interpolation format without braces ``$identifier`` appears as
text.

2.0.2 (2011-07-25)
------------------

Expand Down
3 changes: 0 additions & 3 deletions docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1406,9 +1406,6 @@ included in the output (all inserted text is escaped by default):
${content}
</div>

Note that to insert the value of a symbol, the curly braces can be
omitted entirely: ``Hello, $name!``.

To escape this behavior, prefix the notation with a backslash
character: ``\${...}``.

Expand Down
4 changes: 2 additions & 2 deletions src/chameleon/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ def engine(expression, target):
node = Expression(expression)
return self.translate(node, target)

expression = StringExpr(node.value)
expression = StringExpr(node.value, node.braces_required)
return expression(target, engine)

def visit_Translate(self, node, target):
Expand Down Expand Up @@ -583,7 +583,7 @@ def engine(expression, target):
return self._engine(node, target) + \
convert(target)

expression = StringExpr(node.value)
expression = StringExpr(node.value, node.braces_required)

name = identifier("content")

Expand Down
2 changes: 1 addition & 1 deletion src/chameleon/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Text(Node):
class Interpolation(Text):
"""String interpolation output."""

_fields = "value", "escape"
_fields = "value", "escape", "braces_required"


class Translate(Node):
Expand Down
20 changes: 18 additions & 2 deletions src/chameleon/tales.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,17 @@ class StringExpr(object):
>>> test(StringExpr('Hello ${world}!'))
'Hello world!'
In the default configuration, braces may be omitted if the
expression is an identifier.
>>> test(StringExpr('Hello $world!'))
'Hello world!'
The ``braces_required`` flag changes this setting:
>>> test(StringExpr('Hello $world!', True))
'Hello $world!'
We can escape interpolation using the standard escaping
syntax:
Expand Down Expand Up @@ -382,15 +393,20 @@ class StringExpr(object):
'There are 11 characters in \"hello world\"'
"""

regex = re.compile(
braces_required_regex = re.compile(
r'(?<!\\)\$({(?P<expression>.*)})')

braces_optional_regex = re.compile(
r'(?<!\\)\$({(?P<expression>.*)}|(?P<variable>[A-Za-z][A-Za-z0-9_]*))')

def __init__(self, expression):
def __init__(self, expression, braces_required=False):
# The code relies on the expression being a token string
if not isinstance(expression, Token):
expression = Token(expression, 0)

self.expression = expression
self.regex = self.braces_required_regex if braces_required else \
self.braces_optional_regex

def __call__(self, name, engine):
"""The strategy is to find possible expression strings and
Expand Down
1 change: 0 additions & 1 deletion src/chameleon/tests/inputs/001-variable-scope.pt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<html>
<body tal:define="text 'Hello world!'">
${text}
$text
</body>
<tal:check condition="exists: text">
bad
Expand Down
6 changes: 4 additions & 2 deletions src/chameleon/tests/inputs/006-attribute-interpolation.pt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<html>
<body class="ltr">
<body class="ltr" tal:define="hash string:#">
<img src="${'#'}" alt="copyright (c) ${2010}" />
<img src="${None}" />
<img src="" alt="copyright (c) ${2010}" tal:attributes="src string:$hash" />
<img src="" alt="copyright (c) ${2010}" tal:attributes="src string:${hash}" />
<img src="${None}" alt="$ignored" />
</body>
</html>
1 change: 1 addition & 0 deletions src/chameleon/tests/inputs/007-content-interpolation.pt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
${'Hello world!'}
${literal}
${None}
$leftalone
<div>${None}</div>
</body>
</html>
2 changes: 1 addition & 1 deletion src/chameleon/tests/inputs/063-continuation.pt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div tal:define="foo 1 + \
1">
$foo
${foo}
</div>
1 change: 0 additions & 1 deletion src/chameleon/tests/outputs/001.pt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<html>
<body>
Hello world!
Hello world!
</body>


Expand Down
4 changes: 3 additions & 1 deletion src/chameleon/tests/outputs/006.pt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<html>
<body class="ltr">
<img src="#" alt="copyright (c) 2010" />
<img />
<img src="#" alt="copyright (c) 2010" />
<img src="#" alt="copyright (c) 2010" />
<img alt="$ignored" />
</body>
</html>
1 change: 1 addition & 0 deletions src/chameleon/tests/outputs/007.pt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Hello world!
<div>Hello world!</div>

$leftalone
<div></div>
</body>
</html>
6 changes: 3 additions & 3 deletions src/chameleon/zpt/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ def visit_comment(self, node):
if self._interpolation[-1]:
return nodes.Sequence(
[nodes.Text(node[:4]),
nodes.Interpolation(node[4:-3], self._escape),
nodes.Interpolation(node[4:-3], self._escape, True),
nodes.Text(node[-3:])
])

Expand All @@ -486,7 +486,7 @@ def visit_text(self, node):
self._last = node

if self._interpolation_enabled:
return nodes.Interpolation(node, self._escape)
return nodes.Interpolation(node, self._escape, True)

return nodes.Text(node)

Expand Down Expand Up @@ -543,7 +543,7 @@ def _create_attributes_nodes(self, prepared, I18N_ATTRIBUTES):
# more interpolation expressions, make the attribute
# dynamic
if expr is None and text is not None and '${' in text:
value = nodes.Interpolation(text, True)
value = nodes.Interpolation(text, True, True)

# If this expression is non-trivial, the attribute is
# dynamic (computed)
Expand Down

0 comments on commit b5a2160

Please sign in to comment.