Skip to content

Commit b70c841

Browse files
authored
Allow CONCAT(*elements) and CONCAT(elements=[…]) (#45)
CONCAT used to override FTL.BaseNode.traverse and FTL.BaseNode.to_json because of its use of the *elements varargs in __init__. Overriding to_json isn't required because the base mathod already supports lists. For traverse, we allow CONCAT to be constructed with both the *elements varargs (useful when writing migration specs) and with the elements=[…] keyword arg (used by traverse because elements is an attribute of CONCAT instances).
1 parent 01be516 commit b70c841

File tree

4 files changed

+31
-43
lines changed

4 files changed

+31
-43
lines changed

fluent/migrate/transforms.py

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -277,43 +277,16 @@ def createVariant(zipped_enum):
277277

278278

279279
class CONCAT(Transform):
280-
"""Concatenate elements of many patterns."""
280+
"""Create a new Pattern from Patterns, PatternElements and Expressions."""
281281

282-
def __init__(self, *patterns):
283-
self.patterns = list(patterns)
282+
def __init__(self, *elements, **kwargs):
283+
# We want to support both passing elements as *elements in the
284+
# migration specs and as elements=[]. The latter is used by
285+
# FTL.BaseNode.traverse when it recreates the traversed node using its
286+
# attributes as kwargs.
287+
self.elements = list(kwargs.get('elements', elements))
284288

285289
def __call__(self, ctx):
286-
elements = self.flatten_elements(self.patterns)
290+
elements = self.flatten_elements(self.elements)
287291
elements = self.prune_text_elements(elements)
288292
return FTL.Pattern(elements)
289-
290-
def traverse(self, fun):
291-
def visit(value):
292-
if isinstance(value, FTL.BaseNode):
293-
return value.traverse(fun)
294-
if isinstance(value, list):
295-
return fun(map(visit, value))
296-
else:
297-
return fun(value)
298-
299-
node = self.__class__(
300-
*[
301-
visit(value) for value in self.patterns
302-
]
303-
)
304-
305-
return fun(node)
306-
307-
def to_json(self):
308-
def to_json(value):
309-
if isinstance(value, FTL.BaseNode):
310-
return value.to_json()
311-
else:
312-
return value
313-
314-
return {
315-
'type': self.__class__.__name__,
316-
'patterns': [
317-
to_json(value) for value in self.patterns
318-
]
319-
}

fluent/syntax/ast.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,10 @@ def visit(value):
6666
else:
6767
return fun(value)
6868

69+
# Use all attributes found on the node as kwargs to the constructor.
70+
kwargs = vars(self).items()
6971
node = self.__class__(
70-
**{
71-
name: visit(value)
72-
for name, value in vars(self).items()
73-
}
74-
)
72+
**{name: visit(value) for name, value in kwargs})
7573

7674
return fun(node)
7775

tests/migrate/test_concat.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def setUp(self):
157157
<!ENTITY channel.description.end " channel.">
158158
''')
159159

160-
def test_concat_replace(self):
160+
def test_concat_placeable(self):
161161
msg = FTL.Message(
162162
FTL.Identifier('channel-desc'),
163163
value=CONCAT(
@@ -174,6 +174,23 @@ def test_concat_replace(self):
174174
''')
175175
)
176176

177+
def test_concat_expression(self):
178+
msg = FTL.Message(
179+
FTL.Identifier('channel-desc'),
180+
value=CONCAT(
181+
COPY('test.properties', 'channel.description.start'),
182+
EXTERNAL_ARGUMENT('channelname'),
183+
COPY('test.properties', 'channel.description.end'),
184+
)
185+
)
186+
187+
self.assertEqual(
188+
evaluate(self, msg).to_json(),
189+
ftl_message_to_json('''
190+
channel-desc = You are on the { $channelname } channel.
191+
''')
192+
)
193+
177194

178195
@unittest.skipUnless(DTDParser, 'compare-locales required')
179196
class TestConcatReplace(MockContext):

tests/migrate/test_util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ def test_copy_concat(self):
2727
result = node.traverse(lambda x: x)
2828

2929
self.assertEqual(
30-
result.value.patterns[0].key,
30+
result.value.elements[0].key,
3131
'key1'
3232
)
3333
self.assertEqual(
34-
result.value.patterns[1].key,
34+
result.value.elements[1].key,
3535
'key2'
3636
)
3737

0 commit comments

Comments
 (0)