Skip to content

Commit eab38ca

Browse files
authored
Merge pull request #11 from alerque/attributes
You can't be Fluent withouth Attributes
2 parents 3b1ff08 + 3bd1f63 commit eab38ca

File tree

4 files changed

+79
-15
lines changed

4 files changed

+79
-15
lines changed

fluent/resource.lua

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ local FluentNode = class({
2828
if type(node) ~= "table" then return nil end
2929
if node:is_a(node_types.Identifier) then
3030
self.id = node
31-
elseif node:is_a(node_types.Pattern) then
32-
self.value = node
31+
elseif node:is_a(node_types.Pattern)
32+
or node:is_a(node_types.Attribute) then
33+
return self:attach(node)
3334
else
3435
if not self.elements then self.elements = {} end
3536
if #self.elements >= 1 then
@@ -80,10 +81,11 @@ node_types.Junk = class({
8081
})
8182

8283
node_types.Message = class({
84+
index = {},
8385
_base = FluentNode,
8486
_init = function (self, node)
85-
self:super(node)
8687
self.attributes = {}
88+
self:super(node)
8789
end,
8890
format = function (self, parameters)
8991
return self.value:format(parameters)
@@ -137,6 +139,15 @@ node_types.Pattern = class({
137139
end
138140
tablex.foreachi(self.elements, strip, striplen)
139141
end,
142+
__mul = function (self, node)
143+
if self:is_a(node_types.Message) or self:is_a(node_types.Attribute) then
144+
self.value = node
145+
return self
146+
elseif node:is_a(node_types.Message) or node:is_a(node_types.Attribute) then
147+
node.value = self
148+
return node
149+
end
150+
end,
140151
format = function (self, parameters)
141152
local function evaluate (node) return node:format(parameters) end
142153
local value = table.concat(tablex.map(evaluate, self.elements))
@@ -270,6 +281,23 @@ node_types.Attribute = class({
270281
_base = FluentNode,
271282
_init = function (self, node)
272283
self:super(node)
284+
end,
285+
__mul = function (self, node)
286+
if self:is_a(node_types.Message) then
287+
table.insert(self.attributes, node)
288+
self.index[node.id.name] = #self.attributes
289+
return self
290+
elseif node:is_a(node_types.Message) then
291+
table.insert(node.attributes, self)
292+
node.index[self.id.name] = #node.attributes
293+
return node
294+
elseif self:is_a(node_types.Pattern) then
295+
node.value = self
296+
return node
297+
elseif node:is_a(node_types.Pattern) then
298+
self.value = node
299+
return self
300+
end
273301
end
274302
})
275303

@@ -333,7 +361,15 @@ local FluentResource = class({
333361
end,
334362

335363
get_message = function (self, identifier)
336-
return self.index[identifier] and self.body[self.index[identifier]]
364+
local attr = string.match(identifier, "%.([(%a[-_%a%d]+)$")
365+
local id = string.match(identifier, "^(%a[-_%a%d]+)")
366+
if not self.index[id] then error("No such entry") end
367+
local entry = self.body[self.index[id]]
368+
if attr then
369+
return entry.attributes[entry.index[attr]].value
370+
else
371+
return entry.value
372+
end
337373
end,
338374

339375
dump_ast = function (self)

spec/fixtures_spec.lua

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('upstream reference fixture', function ()
3838
-- or fname:match("/leading_dots.ftl$")
3939
or fname:match("/literal_expressions.ftl$")
4040
-- or fname:match("/member_expressions.ftl$")
41-
-- or fname:match("/messages.ftl$")
41+
or fname:match("/messages.ftl$")
4242
-- or fname:match("/mixed_entries.ftl$")
4343
-- or fname:match("/multiline_values.ftl$")
4444
or fname:match("/numbers.ftl$")
@@ -50,7 +50,7 @@ describe('upstream reference fixture', function ()
5050
-- or fname:match("/sparse_entries.ftl$")
5151
or fname:match("/tab.ftl$")
5252
-- or fname:match("/term_parameters.ftl$")
53-
-- or fname:match("/terms.ftl$")
53+
or fname:match("/terms.ftl$")
5454
or fname:match("/variables.ftl$")
5555
-- or fname:match("/variant_keys.ftl$")
5656
or fname:match("/whitespace_in_value.ftl$")
@@ -96,7 +96,7 @@ describe('upstream structure fixture', function ()
9696
or fname:match("/attribute_expression_with_wrong_attr.ftl")
9797
-- or fname:match("/attribute_of_private_as_placeable.ftl")
9898
or fname:match("/attribute_of_public_as_selector.ftl")
99-
-- or fname:match("/attribute_starts_from_nl.ftl")
99+
or fname:match("/attribute_starts_from_nl.ftl")
100100
-- or fname:match("/attribute_with_empty_pattern.ftl")
101101
-- or fname:match("/attribute_without_equal_sign.ftl")
102102
-- or fname:match("/blank_lines.ftl")
@@ -105,7 +105,7 @@ describe('upstream structure fixture', function ()
105105
or fname:match("/comment_with_eof.ftl")
106106
-- or fname:match("/crlf.ftl")
107107
-- or fname:match("/dash_at_eof.ftl")
108-
-- or fname:match("/elements_indent.ftl")
108+
or fname:match("/elements_indent.ftl")
109109
or fname:match("/empty_resource.ftl")
110110
or fname:match("/empty_resource_with_ws.ftl")
111111
-- or fname:match("/escape_sequences.ftl")
@@ -130,13 +130,13 @@ describe('upstream structure fixture', function ()
130130
or fname:match("/placeable_without_close_bracket.ftl")
131131
or fname:match("/resource_comment.ftl")
132132
or fname:match("/resource_comment_trailing_line.ftl")
133-
-- or fname:match("/second_attribute_starts_from_nl.ftl")
133+
or fname:match("/second_attribute_starts_from_nl.ftl")
134134
or fname:match("/select_expressions.ftl")
135135
or fname:match("/select_expression_without_arrow.ftl")
136136
or fname:match("/select_expression_without_variants.ftl")
137137
or fname:match("/select_expression_with_two_selectors.ftl")
138138
or fname:match("/simple_message.ftl")
139-
-- or fname:match("/single_char_id.ftl")
139+
or fname:match("/single_char_id.ftl")
140140
or fname:match("/sparse-messages.ftl")
141141
or fname:match("/standalone_comment.ftl")
142142
or fname:match("/standalone_identifier.ftl")
@@ -152,9 +152,9 @@ describe('upstream structure fixture', function ()
152152
-- or fname:match("/variant_with_digit_key.ftl")
153153
-- or fname:match("/variant_with_empty_pattern.ftl")
154154
-- or fname:match("/variant_with_leading_space_in_name.ftl")
155-
or fname:match("/variant_with_symbol_with_space.ftl")
156-
or fname:match("/whitespace_leading.ftl")
157-
or fname:match("/whitespace_trailing.ftl")
155+
-- or fname:match("/variant_with_symbol_with_space.ftl")
156+
-- or fname:match("/whitespace_leading.ftl")
157+
-- or fname:match("/whitespace_trailing.ftl")
158158
) then
159159
describe(object, function ()
160160
local ftl = filetostring(fname)

spec/fluent_spec.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ describe('fluent.bundle', function ()
4040
assert.same("bar qux", en:format("foo", { baz = "qux" }))
4141
end)
4242

43+
it('should parse and format an attribute', function ()
44+
local en = FluentBundle("en-US")
45+
en:add_messages('foo = bar\n .baz = qux')
46+
assert.equals("qux", en:format("foo.baz"))
47+
end)
48+
4349
it('should keep locale instances separate', function ()
4450
local en = FluentBundle("en-US")
4551
local tr = FluentBundle("tr-TR")

spec/fluent_syntax_spec.lua

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,36 @@ describe('fluent.syntax', function ()
5858
local foo = syntax:parsestring('foo = bar {"baz"}')
5959
assert.equals(2, #foo.body[1].value.elements)
6060
assert.equals("TextElement", foo.body[1].value.elements[1].type)
61-
assert.equals("Placeable", foo.body[1].value.elements[2].type)
61+
assert.equals("StringLiteral", foo.body[1].value.elements[2].expression.type)
6262
end)
6363

6464
it('should handle literal number placables', function ()
6565
local foo = syntax:parsestring('foo = bar {-54.3}')
6666
assert.equals(2, #foo.body[1].value.elements)
6767
assert.equals("TextElement", foo.body[1].value.elements[1].type)
68-
assert.equals("Placeable", foo.body[1].value.elements[2].type)
68+
assert.equals("NumberLiteral", foo.body[1].value.elements[2].expression.type)
69+
end)
70+
71+
it('should handle literal variable reference placables', function ()
72+
local foo = syntax:parsestring('foo = bar { $baz }')
73+
assert.equals(2, #foo.body[1].value.elements)
74+
assert.equals("TextElement", foo.body[1].value.elements[1].type)
75+
assert.equals("VariableReference", foo.body[1].value.elements[2].expression.type)
76+
end)
77+
78+
it('should handle message plus attributes', function ()
79+
local foo = syntax:parsestring('foo = bar\n .baz = qux')
80+
assert.equals(1, #foo.body[1].value.elements)
81+
assert.equals(1, #foo.body[1].attributes)
82+
assert.equals("TextElement", foo.body[1].value.elements[1].type)
83+
assert.equals("TextElement", foo.body[1].attributes[1].value.elements[1].type)
84+
end)
85+
86+
it('should handle just attributes', function ()
87+
local foo = syntax:parsestring('foo =\n .baz = qux')
88+
assert.equals("nil", type(foo.body[1].value))
89+
assert.equals(1, #foo.body[1].attributes)
90+
assert.equals("TextElement", foo.body[1].attributes[1].value.elements[1].type)
6991
end)
7092

7193
it('should handle simple comments', function ()

0 commit comments

Comments
 (0)