antlers 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/factories/node_factory.rb +9 -0
- data/lib/lexer.rb +25 -5
- data/lib/nodes/if_node.rb +31 -0
- data/lib/nodes/var_node.rb +7 -2
- data/lib/parser.rb +6 -0
- data/lib/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0d88855d8351d4ce9b4ebf2bfeaf0fc05faef8a33a882ffd206fa1c8241ec9e
|
|
4
|
+
data.tar.gz: e72f72db347e9f0f442e0a15cb4dce3f2c7405bf1bd7da6b33ab919a7003785b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f1e6d6f8f512d327ee25068a3286d8f1e557407bf99f4ec274cd8c8e7336ef9c2d9db9980e66d13ce58b8055d07f6908108afcb8cd91d2da65224ac567946d4
|
|
7
|
+
data.tar.gz: 27520e044188ae13cde780d7438286e510dae3874cd2218debf2901a1b3c7e9909847c44ae38ce4353e8b0482afa2516fa47857836070a58e8683934865a58c7
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../nodes/if_node'
|
|
3
4
|
require_relative '../nodes/for_node'
|
|
4
5
|
require_relative '../nodes/form_node'
|
|
5
6
|
require_relative '../nodes/prop_node'
|
|
@@ -13,6 +14,10 @@ module Antlers
|
|
|
13
14
|
@namespace = namespace
|
|
14
15
|
end
|
|
15
16
|
|
|
17
|
+
def if_node(segment:)
|
|
18
|
+
IfNode.new(name: segment[:if_def], value: segment[:if_def])
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
def for_node(segment:)
|
|
17
22
|
value, key, items = segment.values_at(:for_def, :key, :in)
|
|
18
23
|
ForNode.new(name: value, key:, value:, items:)
|
|
@@ -37,6 +42,10 @@ module Antlers
|
|
|
37
42
|
VarNode.new(value: segment[:var])
|
|
38
43
|
end
|
|
39
44
|
|
|
45
|
+
def raw_var_node(segment:)
|
|
46
|
+
VarNode.new(value: segment[:raw_var], raw: true)
|
|
47
|
+
end
|
|
48
|
+
|
|
40
49
|
def yield_node(segment:)
|
|
41
50
|
YieldNode.new(name: segment[:slot])
|
|
42
51
|
end
|
data/lib/lexer.rb
CHANGED
|
@@ -8,12 +8,13 @@ module Antlers
|
|
|
8
8
|
class LexerParseError < StandardError; end
|
|
9
9
|
|
|
10
10
|
class Lexer
|
|
11
|
+
IF_KEYWORDS = ['if:', ':if'].freeze
|
|
11
12
|
FOR_KEYWORDS = ['for:', 'in:', ':for'].freeze
|
|
12
13
|
FORM_KEYWORDS = ['form:', ':form'].freeze
|
|
13
14
|
|
|
14
15
|
def initialize
|
|
15
16
|
@delimiters = ['<{', '}>', '{', '}']
|
|
16
|
-
@keywords = [
|
|
17
|
+
@keywords = [*IF_KEYWORDS, *FORM_KEYWORDS, *FOR_KEYWORDS, 'slot:', ':slot']
|
|
17
18
|
@cursor = 0
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -44,21 +45,23 @@ module Antlers
|
|
|
44
45
|
|
|
45
46
|
def antlers_segment(segments:)
|
|
46
47
|
next_segment = segments[@cursor + 1]
|
|
47
|
-
return nil unless next_segment && (segments[@cursor] == '<{' ||
|
|
48
|
+
return nil unless next_segment && (segments[@cursor] == '<{' || brackets?(segments:))
|
|
48
49
|
|
|
49
50
|
next_segment
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def antlers_lexeme(antlers_segment:, segments:)
|
|
53
|
-
return var(antlers_segment:) if
|
|
54
|
+
return var(antlers_segment:) if brackets?(segments:)
|
|
54
55
|
|
|
55
56
|
name, props, keywords = parse_segment(antlers_segment:)
|
|
56
57
|
|
|
57
58
|
return slot_yield if slot_yield?(keywords:)
|
|
58
59
|
return slot(name:, props:) if slot?(name)
|
|
59
60
|
return prop(name:, props:) if prop?(name)
|
|
61
|
+
return if_block(keywords:) if if_block?(keywords:)
|
|
60
62
|
return for_loop(keywords:) if for_loop?(keywords:)
|
|
61
63
|
return form(keywords:) if form?(keywords:)
|
|
64
|
+
return var(antlers_segment:, raw: true) if deerheads?(segments:)
|
|
62
65
|
|
|
63
66
|
raise LexerParseError, "Unrecognised syntax: '#{antlers_segment}'"
|
|
64
67
|
end
|
|
@@ -87,11 +90,20 @@ module Antlers
|
|
|
87
90
|
|
|
88
91
|
# TODO: Refactor every constant, match and result method into its own class. Loop through every class and return the first match.
|
|
89
92
|
|
|
90
|
-
def
|
|
93
|
+
def brackets?(segments:)
|
|
91
94
|
first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
|
|
92
95
|
first == '{' && last == '}'
|
|
93
96
|
end
|
|
94
97
|
|
|
98
|
+
def deerheads?(segments:)
|
|
99
|
+
first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
|
|
100
|
+
first == '<{' && last == '}>'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def if_block?(keywords:)
|
|
104
|
+
IF_KEYWORDS.include?(keywords.keys.first)
|
|
105
|
+
end
|
|
106
|
+
|
|
95
107
|
def for_loop?(keywords:)
|
|
96
108
|
FOR_KEYWORDS.include?(keywords.keys.first)
|
|
97
109
|
end
|
|
@@ -112,13 +124,21 @@ module Antlers
|
|
|
112
124
|
name && [*'A'..'Z'].include?(name[0])
|
|
113
125
|
end
|
|
114
126
|
|
|
115
|
-
def var(antlers_segment:)
|
|
127
|
+
def var(antlers_segment:, raw: false)
|
|
116
128
|
# String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
|
|
117
129
|
antlers_segment = antlers_segment[1..-2] if Queries.user_defined_string?(antlers_segment)
|
|
118
130
|
|
|
131
|
+
return { raw_var: antlers_segment } if raw
|
|
132
|
+
|
|
119
133
|
{ var: antlers_segment }
|
|
120
134
|
end
|
|
121
135
|
|
|
136
|
+
def if_block(keywords:)
|
|
137
|
+
return { if_def: keywords['if:'] } if keywords.key?('if:')
|
|
138
|
+
|
|
139
|
+
{ if_end: 'level_1' }
|
|
140
|
+
end
|
|
141
|
+
|
|
122
142
|
def for_loop(keywords:)
|
|
123
143
|
if keywords['for:']
|
|
124
144
|
*key, value = keywords['for:'].split(',').map(&:strip)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../interfaces/branch_node'
|
|
4
|
+
require_relative '../modules/props'
|
|
5
|
+
require_relative '../modules/variables'
|
|
6
|
+
|
|
7
|
+
module Antlers
|
|
8
|
+
class IfNode < BranchNode
|
|
9
|
+
include Props
|
|
10
|
+
include Variables
|
|
11
|
+
|
|
12
|
+
def initialize(name:, value:, props: [], children: [])
|
|
13
|
+
super(name:, props:, children:)
|
|
14
|
+
|
|
15
|
+
@value = value
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
19
|
+
output = ''.dup
|
|
20
|
+
|
|
21
|
+
if evaluate(name: @value, current_binding:)
|
|
22
|
+
@children.each do |child|
|
|
23
|
+
# Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
|
|
24
|
+
output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
output
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/nodes/var_node.rb
CHANGED
|
@@ -11,14 +11,19 @@ module Antlers
|
|
|
11
11
|
|
|
12
12
|
attr_reader :value
|
|
13
13
|
|
|
14
|
-
def initialize(value:, name: :var)
|
|
14
|
+
def initialize(value:, name: :var, raw: false)
|
|
15
15
|
super(name:)
|
|
16
16
|
|
|
17
17
|
@value = value
|
|
18
|
+
@raw = raw
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
21
|
-
|
|
22
|
+
result = evaluate(name: @value, current_binding:) || fallback(@value)
|
|
23
|
+
|
|
24
|
+
return result if @raw
|
|
25
|
+
|
|
26
|
+
ERB::Util.html_escape(result)
|
|
22
27
|
end
|
|
23
28
|
end
|
|
24
29
|
end
|
data/lib/parser.rb
CHANGED
|
@@ -21,6 +21,8 @@ module Antlers
|
|
|
21
21
|
node.children << segment
|
|
22
22
|
elsif segment[:var]
|
|
23
23
|
node.children << @factory.var_node(segment:)
|
|
24
|
+
elsif segment[:raw_var]
|
|
25
|
+
node.children << @factory.raw_var_node(segment:)
|
|
24
26
|
elsif segment[:prop]
|
|
25
27
|
node.children << @factory.prop_node(segment:)
|
|
26
28
|
elsif segment[:slot]
|
|
@@ -29,6 +31,10 @@ module Antlers
|
|
|
29
31
|
slot_node = @factory.slot_node(segment:)
|
|
30
32
|
node.children << slot_node
|
|
31
33
|
sub_branch(node: slot_node, sequence:, end_key: :slot_end, end_name: slot_node.name)
|
|
34
|
+
elsif segment[:if_def]
|
|
35
|
+
if_node = @factory.if_node(segment:)
|
|
36
|
+
node.children << if_node
|
|
37
|
+
sub_branch(node: if_node, sequence:, end_key: :if_end, end_name: 'level_1')
|
|
32
38
|
elsif segment[:for_def]
|
|
33
39
|
for_node = @factory.for_node(segment:)
|
|
34
40
|
node.children << for_node
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: antlers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -70,6 +70,7 @@ files:
|
|
|
70
70
|
- lib/modules/variables.rb
|
|
71
71
|
- lib/nodes/for_node.rb
|
|
72
72
|
- lib/nodes/form_node.rb
|
|
73
|
+
- lib/nodes/if_node.rb
|
|
73
74
|
- lib/nodes/prop_node.rb
|
|
74
75
|
- lib/nodes/root_node.rb
|
|
75
76
|
- lib/nodes/slot_node.rb
|