antlers 0.8.1 → 0.8.2
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/antlers/elements.rb +132 -0
- data/lib/{lexer.rb → antlers/lexer.rb} +8 -23
- data/lib/antlers/parser.rb +43 -0
- data/lib/{version.rb → antlers/version.rb} +1 -1
- data/lib/antlers.rb +12 -5
- data/lib/interfaces/antler_node.rb +18 -1
- data/lib/interfaces/branch_node.rb +1 -2
- data/lib/modules/variables.rb +1 -1
- data/lib/nodes/for_node.rb +15 -2
- data/lib/nodes/form_node.rb +17 -2
- data/lib/nodes/html_node.rb +27 -0
- data/lib/nodes/if_node.rb +14 -2
- data/lib/nodes/prop_node.rb +10 -0
- data/lib/nodes/root_node.rb +10 -0
- data/lib/nodes/slot_node.rb +18 -1
- data/lib/nodes/var_node.rb +10 -0
- data/lib/nodes/yield_node.rb +13 -8
- metadata +20 -5
- data/lib/factories/node_factory.rb +0 -57
- data/lib/parser.rb +0 -59
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0dbec268b4fe0b7966b5f7161c61b16c155695ae10ab9c16d66ea67462348f4
|
|
4
|
+
data.tar.gz: a5ef4b1479077100df98ebf33a16379cf934cecbb980184008b5ecb86c3bcbb0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8e4537ad73ba6356a5ce6a4632da46113374c21e6449ba9f744f9166e47ec93fcb619cab17d536d0b6413145c11e91f726b0a48e6b628af35c3662ec55e2970
|
|
7
|
+
data.tar.gz: 34b6b683e8ca4d3b736efa8684d049064032abf7ca081d2791370e0135b8ff7adc02e67dcf22a3c32dbe616b84302882b5346cc28c0915145e5278252cab5048
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'plugs'
|
|
4
|
+
|
|
5
|
+
module Antlers
|
|
6
|
+
class Elements
|
|
7
|
+
include Plugs
|
|
8
|
+
|
|
9
|
+
plug(:root) do
|
|
10
|
+
plug(:node) do
|
|
11
|
+
lazy do
|
|
12
|
+
require_relative '../nodes/root_node'
|
|
13
|
+
RootNode
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
plug(:html) do
|
|
19
|
+
plug(:node) do
|
|
20
|
+
lazy do
|
|
21
|
+
require_relative '../nodes/html_node'
|
|
22
|
+
HTMLNode
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
plug(:form) do
|
|
28
|
+
plug(:lexeme) do
|
|
29
|
+
lazy do
|
|
30
|
+
require_relative '../lexemes/form_lexeme'
|
|
31
|
+
FormLexeme
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
plug(:node) do
|
|
36
|
+
lazy do
|
|
37
|
+
require_relative '../nodes/form_node'
|
|
38
|
+
FormNode
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
plug(:for) do
|
|
44
|
+
plug(:lexeme) do
|
|
45
|
+
lazy do
|
|
46
|
+
require_relative '../lexemes/for_lexeme'
|
|
47
|
+
ForLexeme
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
plug(:node) do
|
|
52
|
+
lazy do
|
|
53
|
+
require_relative '../nodes/for_node'
|
|
54
|
+
ForNode
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
plug(:if) do
|
|
60
|
+
plug(:lexeme) do
|
|
61
|
+
lazy do
|
|
62
|
+
require_relative '../lexemes/if_lexeme'
|
|
63
|
+
IfLexeme
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
plug(:node) do
|
|
68
|
+
lazy do
|
|
69
|
+
require_relative '../nodes/if_node'
|
|
70
|
+
IfNode
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
plug(:prop) do
|
|
76
|
+
plug(:lexeme) do
|
|
77
|
+
lazy do
|
|
78
|
+
require_relative '../lexemes/prop_lexeme'
|
|
79
|
+
PropLexeme
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
plug(:node) do
|
|
84
|
+
lazy do
|
|
85
|
+
require_relative '../nodes/prop_node'
|
|
86
|
+
PropNode
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
plug(:slot) do
|
|
92
|
+
plug(:lexeme) do
|
|
93
|
+
lazy do
|
|
94
|
+
require_relative '../lexemes/slot_lexeme'
|
|
95
|
+
SlotLexeme
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
plug(:node) do
|
|
100
|
+
lazy do
|
|
101
|
+
require_relative '../nodes/slot_node'
|
|
102
|
+
SlotNode
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
plug(:yield) do
|
|
108
|
+
plug(:lexeme) do
|
|
109
|
+
lazy do
|
|
110
|
+
require_relative '../lexemes/yield_lexeme'
|
|
111
|
+
YieldLexeme
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
plug(:node) do
|
|
116
|
+
lazy do
|
|
117
|
+
require_relative '../nodes/yield_node'
|
|
118
|
+
YieldNode
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
plug(:var) do
|
|
124
|
+
plug(:node) do
|
|
125
|
+
lazy do
|
|
126
|
+
require_relative '../nodes/var_node'
|
|
127
|
+
VarNode
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -1,36 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative 'lexemes/form_lexeme'
|
|
5
|
-
require_relative 'lexemes/if_lexeme'
|
|
6
|
-
require_relative 'lexemes/prop_lexeme'
|
|
7
|
-
require_relative 'lexemes/slot_lexeme'
|
|
8
|
-
require_relative 'lexemes/yield_lexeme'
|
|
9
|
-
require_relative 'support/queries'
|
|
3
|
+
require_relative '../support/queries'
|
|
10
4
|
|
|
11
5
|
module Antlers
|
|
12
6
|
extend Queries
|
|
13
7
|
|
|
14
|
-
class
|
|
15
|
-
|
|
16
|
-
LEXEMES = [
|
|
17
|
-
# FormLexeme must be ordered before ForLexeme for regex to work.
|
|
18
|
-
Antlers::FormLexeme,
|
|
19
|
-
Antlers::ForLexeme,
|
|
20
|
-
Antlers::IfLexeme,
|
|
21
|
-
Antlers::PropLexeme,
|
|
22
|
-
Antlers::SlotLexeme,
|
|
23
|
-
Antlers::YieldLexeme,
|
|
24
|
-
]
|
|
8
|
+
class LexerError < StandardError; end
|
|
25
9
|
|
|
26
10
|
class Lexer
|
|
27
|
-
def initialize
|
|
11
|
+
def initialize(lexeme_types:)
|
|
28
12
|
@delimiters = ['<{', '}>', '{', '}']
|
|
29
|
-
@
|
|
13
|
+
@lexeme_types = lexeme_types
|
|
14
|
+
@keywords = @lexeme_types.flat_map { |lexeme| lexeme.const_get(:KEYWORDS) }
|
|
30
15
|
@cursor = 0
|
|
31
16
|
end
|
|
32
17
|
|
|
33
|
-
def parse(template)
|
|
18
|
+
def parse(template:)
|
|
34
19
|
@cursor = 0
|
|
35
20
|
sequence = []
|
|
36
21
|
|
|
@@ -67,11 +52,11 @@ module Antlers
|
|
|
67
52
|
|
|
68
53
|
name, props, keywords = parse_segment(antlers_segment:)
|
|
69
54
|
|
|
70
|
-
lexeme =
|
|
55
|
+
lexeme = @lexeme_types.find { it.match?(name:, keywords:) }
|
|
71
56
|
return lexeme.lexeme(name:, props:, keywords:) if lexeme
|
|
72
57
|
return var(antlers_segment:, raw: true) if deerheads?(segments:)
|
|
73
58
|
|
|
74
|
-
raise
|
|
59
|
+
raise LexerError, "Unrecognised syntax: '#{antlers_segment}'"
|
|
75
60
|
end
|
|
76
61
|
|
|
77
62
|
def parse_segment(antlers_segment:)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Antlers
|
|
4
|
+
class Parser
|
|
5
|
+
class ParserError < StandardError; end
|
|
6
|
+
|
|
7
|
+
def initialize(namespace: nil, node_types:)
|
|
8
|
+
@namespace = namespace
|
|
9
|
+
@node_types = node_types
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse(sequence:, id: :root_node)
|
|
13
|
+
branch(node: RootNode.new(name: id), sequence:)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def branch(node:, sequence:)
|
|
17
|
+
until sequence.empty?
|
|
18
|
+
segment = sequence.shift
|
|
19
|
+
|
|
20
|
+
child_class = @node_types.find { |n| n.match?(segment:) }
|
|
21
|
+
raise(ParserError, "No node matches #{segment}") unless child_class
|
|
22
|
+
|
|
23
|
+
child = child_class.build(segment:, namespace: @namespace)
|
|
24
|
+
node.children << child
|
|
25
|
+
|
|
26
|
+
if (end_key = child_class::END_KEY)
|
|
27
|
+
sub_branch(node: child, sequence:, end_key:, end_name: child.end_name)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
node
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def sub_branch(node:, sequence:, end_key:, end_name: nil)
|
|
35
|
+
sub_sequence = []
|
|
36
|
+
sub_sequence << sequence.shift until sequence.first.is_a?(Hash) && sequence.first[end_key] == end_name
|
|
37
|
+
# Remove the end tag we just stopped before.
|
|
38
|
+
sequence.shift
|
|
39
|
+
|
|
40
|
+
branch(node:, sequence: sub_sequence)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/antlers.rb
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative '
|
|
3
|
+
require_relative 'antlers/elements'
|
|
4
|
+
require_relative 'antlers/lexer'
|
|
5
|
+
require_relative 'antlers/parser'
|
|
6
|
+
|
|
7
|
+
# These requires allow downstream libraries to build their own antlers nodes.
|
|
8
|
+
require_relative 'interfaces/branch_node'
|
|
9
|
+
require_relative 'interfaces/leaf_node'
|
|
5
10
|
|
|
6
11
|
module Antlers
|
|
12
|
+
DEFAULT_ELEMENTS = [:root, :html, :form, :for, :if, :prop, :slot, :yield, :var]
|
|
13
|
+
|
|
7
14
|
class << self
|
|
8
|
-
def ast(template:, namespace: nil)
|
|
15
|
+
def ast(template:, namespace: nil, elements: Elements[*DEFAULT_ELEMENTS])
|
|
9
16
|
return template unless template.include?('<{') || template.include?('{')
|
|
10
17
|
|
|
11
|
-
sequence = Lexer.new.parse(template)
|
|
12
|
-
Parser.new(namespace:).parse(sequence:)
|
|
18
|
+
sequence = Lexer.new(lexeme_types: elements[:lexeme].to_a).parse(template:)
|
|
19
|
+
Parser.new(namespace:, node_types: elements[:node].to_a).parse(sequence:)
|
|
13
20
|
end
|
|
14
21
|
|
|
15
22
|
def render(ast:, current_binding:, parent_binding: nil, slot_node: nil)
|
|
@@ -4,6 +4,9 @@ module Antlers
|
|
|
4
4
|
class AntlerNode
|
|
5
5
|
attr_reader :name
|
|
6
6
|
|
|
7
|
+
DEF_KEY = nil
|
|
8
|
+
END_KEY = nil
|
|
9
|
+
|
|
7
10
|
def initialize(name:)
|
|
8
11
|
@name = name
|
|
9
12
|
end
|
|
@@ -12,7 +15,21 @@ module Antlers
|
|
|
12
15
|
raise NotImplementedError
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
def end_name
|
|
19
|
+
'level_1'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def match?(segment:)
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build(segment:, namespace:)
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Compare instance as a value object.
|
|
16
33
|
def ==(other) = other.class == self.class
|
|
17
34
|
def eql?(other) = self == other
|
|
18
35
|
def hash = [self.class].hash
|
|
@@ -16,8 +16,7 @@ module Antlers
|
|
|
16
16
|
output = ''
|
|
17
17
|
|
|
18
18
|
@children.each do |child|
|
|
19
|
-
|
|
20
|
-
output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
|
|
19
|
+
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
output
|
data/lib/modules/variables.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Antlers
|
|
|
6
6
|
module Variables
|
|
7
7
|
extend Queries
|
|
8
8
|
|
|
9
|
-
# Evaluation limited to the following for security and to
|
|
9
|
+
# Evaluation limited to the following for security and to stop a templating language becoming a programming language.
|
|
10
10
|
# 1. An instance variable
|
|
11
11
|
# 2. A method call/local variable
|
|
12
12
|
# 3. A method chain
|
data/lib/nodes/for_node.rb
CHANGED
|
@@ -9,6 +9,9 @@ module Antlers
|
|
|
9
9
|
include Props
|
|
10
10
|
include Variables
|
|
11
11
|
|
|
12
|
+
DEF_KEY = :for_def
|
|
13
|
+
END_KEY = :for_end
|
|
14
|
+
|
|
12
15
|
def initialize(name:, items:, value:, key: nil, props: [], children: [])
|
|
13
16
|
super(name:, props:, children:)
|
|
14
17
|
|
|
@@ -28,12 +31,22 @@ module Antlers
|
|
|
28
31
|
current_binding.local_variable_set(@key, key) if @key
|
|
29
32
|
|
|
30
33
|
@children.each do |child|
|
|
31
|
-
|
|
32
|
-
output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
|
|
34
|
+
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
33
35
|
end
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
output
|
|
37
39
|
end
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
def match?(segment:)
|
|
43
|
+
segment[DEF_KEY]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build(segment:, **)
|
|
47
|
+
value, key, items = segment.values_at(DEF_KEY, :key, :in)
|
|
48
|
+
new(name: value, key:, value:, items:)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
38
51
|
end
|
|
39
52
|
end
|
data/lib/nodes/form_node.rb
CHANGED
|
@@ -9,6 +9,9 @@ module Antlers
|
|
|
9
9
|
include Props
|
|
10
10
|
include Variables
|
|
11
11
|
|
|
12
|
+
DEF_KEY = :form_def
|
|
13
|
+
END_KEY = :form_end
|
|
14
|
+
|
|
12
15
|
def initialize(name:, action: nil, method: 'POST', props: [], children: [])
|
|
13
16
|
super(name:, props:, children:)
|
|
14
17
|
|
|
@@ -20,12 +23,24 @@ module Antlers
|
|
|
20
23
|
output = "<form action='#{@action}' method='#{@method}'>"
|
|
21
24
|
|
|
22
25
|
@children.each do |child|
|
|
23
|
-
|
|
24
|
-
output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
|
|
26
|
+
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
output += '</form>'
|
|
28
30
|
output
|
|
29
31
|
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
def match?(segment:)
|
|
35
|
+
segment[DEF_KEY]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def build(segment:, **)
|
|
39
|
+
action, method = segment.values_at(DEF_KEY, :method)
|
|
40
|
+
return new(name: action, action:, method:) if method
|
|
41
|
+
|
|
42
|
+
new(name: action, action:)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
30
45
|
end
|
|
31
46
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../interfaces/leaf_node'
|
|
4
|
+
|
|
5
|
+
module Antlers
|
|
6
|
+
class HTMLNode < LeafNode
|
|
7
|
+
def initialize(html:)
|
|
8
|
+
super(name: nil)
|
|
9
|
+
|
|
10
|
+
@html = html
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def render(**)
|
|
14
|
+
@html
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def match?(segment:)
|
|
19
|
+
segment.is_a?(String)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def build(segment:, **)
|
|
23
|
+
new(html: segment)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/nodes/if_node.rb
CHANGED
|
@@ -9,6 +9,9 @@ module Antlers
|
|
|
9
9
|
include Props
|
|
10
10
|
include Variables
|
|
11
11
|
|
|
12
|
+
DEF_KEY = :if_def
|
|
13
|
+
END_KEY = :if_end
|
|
14
|
+
|
|
12
15
|
def initialize(name:, value:, props: [], children: [])
|
|
13
16
|
super(name:, props:, children:)
|
|
14
17
|
|
|
@@ -20,12 +23,21 @@ module Antlers
|
|
|
20
23
|
|
|
21
24
|
if evaluate(name: @value, current_binding:)
|
|
22
25
|
@children.each do |child|
|
|
23
|
-
|
|
24
|
-
output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
|
|
26
|
+
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
output
|
|
29
31
|
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
def match?(segment:)
|
|
35
|
+
segment[DEF_KEY]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def build(segment:, **)
|
|
39
|
+
new(name: segment[DEF_KEY], value: segment[DEF_KEY])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
30
42
|
end
|
|
31
43
|
end
|
data/lib/nodes/prop_node.rb
CHANGED
|
@@ -30,6 +30,16 @@ module Antlers
|
|
|
30
30
|
render_args(class_proxy:, instance:, event:, props:)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
class << self
|
|
34
|
+
def match?(segment:)
|
|
35
|
+
segment[:prop]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def build(segment:, namespace:)
|
|
39
|
+
new(name: segment[:prop], props: segment[:props], namespace:)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
33
43
|
private
|
|
34
44
|
|
|
35
45
|
def create_instance(class_proxy:, klass:, event:, props:)
|
data/lib/nodes/root_node.rb
CHANGED
data/lib/nodes/slot_node.rb
CHANGED
|
@@ -7,7 +7,10 @@ require_relative '../modules/props'
|
|
|
7
7
|
module Antlers
|
|
8
8
|
class SlotNode < BranchNode
|
|
9
9
|
include Namespace
|
|
10
|
-
include Props #
|
|
10
|
+
include Props # The immediate ancestor which props are passed to.
|
|
11
|
+
|
|
12
|
+
DEF_KEY = :slot_def
|
|
13
|
+
END_KEY = :slot_end
|
|
11
14
|
|
|
12
15
|
attr_accessor :children
|
|
13
16
|
|
|
@@ -30,5 +33,19 @@ module Antlers
|
|
|
30
33
|
|
|
31
34
|
props.empty? ? instance.render(event:) : instance.render(event:, **props)
|
|
32
35
|
end
|
|
36
|
+
|
|
37
|
+
def end_name
|
|
38
|
+
@name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
def match?(segment:)
|
|
43
|
+
segment[DEF_KEY]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build(segment:, namespace:)
|
|
47
|
+
new(name: segment[DEF_KEY], props: segment[:props], namespace:)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
33
50
|
end
|
|
34
51
|
end
|
data/lib/nodes/var_node.rb
CHANGED
|
@@ -25,5 +25,15 @@ module Antlers
|
|
|
25
25
|
|
|
26
26
|
ERB::Util.html_escape(result)
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
def match?(segment:)
|
|
31
|
+
segment[:var] || segment[:raw_var]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build(segment:, **)
|
|
35
|
+
new(value: segment[:var] || segment[:raw_var], raw: !!segment[:raw_var])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
28
38
|
end
|
|
29
39
|
end
|
data/lib/nodes/yield_node.rb
CHANGED
|
@@ -8,20 +8,25 @@ module Antlers
|
|
|
8
8
|
super(name:)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
def render(current_binding: nil, parent_binding
|
|
11
|
+
# Render the children in the binding of the parent.
|
|
12
|
+
def render(current_binding: nil, parent_binding:, slot_node:)
|
|
13
13
|
output = ''
|
|
14
14
|
|
|
15
15
|
slot_node.children.each do |child|
|
|
16
|
-
|
|
17
|
-
if child.respond_to?(:render) # rubocop:disable Style/ConditionalAssignment
|
|
18
|
-
output += child.render(current_binding: parent_binding, parent_binding: nil, slot_node: nil)
|
|
19
|
-
else
|
|
20
|
-
output += child || ''
|
|
21
|
-
end
|
|
16
|
+
output += child.render(current_binding: parent_binding, parent_binding:, slot_node:) || ''
|
|
22
17
|
end
|
|
23
18
|
|
|
24
19
|
output
|
|
25
20
|
end
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def match?(segment:)
|
|
24
|
+
segment[:slot]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build(segment:, **)
|
|
28
|
+
new(name: segment[:slot])
|
|
29
|
+
end
|
|
30
|
+
end
|
|
26
31
|
end
|
|
27
32
|
end
|
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.8.
|
|
4
|
+
version: 0.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -51,6 +51,20 @@ dependencies:
|
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: plugs
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
54
68
|
description: A templating language embedded within HTML that is itself embedded within
|
|
55
69
|
Ruby/RBX
|
|
56
70
|
email:
|
|
@@ -60,7 +74,10 @@ extensions: []
|
|
|
60
74
|
extra_rdoc_files: []
|
|
61
75
|
files:
|
|
62
76
|
- lib/antlers.rb
|
|
63
|
-
- lib/
|
|
77
|
+
- lib/antlers/elements.rb
|
|
78
|
+
- lib/antlers/lexer.rb
|
|
79
|
+
- lib/antlers/parser.rb
|
|
80
|
+
- lib/antlers/version.rb
|
|
64
81
|
- lib/interfaces/antler_node.rb
|
|
65
82
|
- lib/interfaces/branch_node.rb
|
|
66
83
|
- lib/interfaces/leaf_node.rb
|
|
@@ -71,21 +88,19 @@ files:
|
|
|
71
88
|
- lib/lexemes/prop_lexeme.rb
|
|
72
89
|
- lib/lexemes/slot_lexeme.rb
|
|
73
90
|
- lib/lexemes/yield_lexeme.rb
|
|
74
|
-
- lib/lexer.rb
|
|
75
91
|
- lib/modules/namespace.rb
|
|
76
92
|
- lib/modules/props.rb
|
|
77
93
|
- lib/modules/variables.rb
|
|
78
94
|
- lib/nodes/for_node.rb
|
|
79
95
|
- lib/nodes/form_node.rb
|
|
96
|
+
- lib/nodes/html_node.rb
|
|
80
97
|
- lib/nodes/if_node.rb
|
|
81
98
|
- lib/nodes/prop_node.rb
|
|
82
99
|
- lib/nodes/root_node.rb
|
|
83
100
|
- lib/nodes/slot_node.rb
|
|
84
101
|
- lib/nodes/var_node.rb
|
|
85
102
|
- lib/nodes/yield_node.rb
|
|
86
|
-
- lib/parser.rb
|
|
87
103
|
- lib/support/queries.rb
|
|
88
|
-
- lib/version.rb
|
|
89
104
|
homepage: https://github.com/raindeer-rb/antlers
|
|
90
105
|
licenses: []
|
|
91
106
|
metadata:
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../nodes/if_node'
|
|
4
|
-
require_relative '../nodes/for_node'
|
|
5
|
-
require_relative '../nodes/form_node'
|
|
6
|
-
require_relative '../nodes/prop_node'
|
|
7
|
-
require_relative '../nodes/slot_node'
|
|
8
|
-
require_relative '../nodes/var_node'
|
|
9
|
-
require_relative '../nodes/yield_node'
|
|
10
|
-
|
|
11
|
-
module Antlers
|
|
12
|
-
class NodeFactory
|
|
13
|
-
def initialize(namespace:)
|
|
14
|
-
@namespace = namespace
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def if_node(segment:)
|
|
18
|
-
IfNode.new(name: segment[:if_def], value: segment[:if_def])
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def for_node(segment:)
|
|
22
|
-
value, key, items = segment.values_at(:for_def, :key, :in)
|
|
23
|
-
ForNode.new(name: value, key:, value:, items:)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def form_node(segment:)
|
|
27
|
-
action, method = segment.values_at(:form_def, :method)
|
|
28
|
-
return FormNode.new(name: action, action:, method:) if method
|
|
29
|
-
|
|
30
|
-
FormNode.new(name: action, action:)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def prop_node(segment:)
|
|
34
|
-
PropNode.new(name: segment[:prop], props: segment[:props], namespace:)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def slot_node(segment:)
|
|
38
|
-
SlotNode.new(name: segment[:slot_def], props: segment[:props], namespace:)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def var_node(segment:)
|
|
42
|
-
VarNode.new(value: segment[:var])
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def raw_var_node(segment:)
|
|
46
|
-
VarNode.new(value: segment[:raw_var], raw: true)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def yield_node(segment:)
|
|
50
|
-
YieldNode.new(name: segment[:slot])
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private
|
|
54
|
-
|
|
55
|
-
attr_reader :namespace
|
|
56
|
-
end
|
|
57
|
-
end
|
data/lib/parser.rb
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'factories/node_factory'
|
|
4
|
-
require_relative 'nodes/root_node'
|
|
5
|
-
|
|
6
|
-
module Antlers
|
|
7
|
-
class Parser
|
|
8
|
-
def initialize(namespace: nil)
|
|
9
|
-
@factory = NodeFactory.new(namespace:)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def parse(sequence:, id: :root_node)
|
|
13
|
-
branch(node: RootNode.new(name: id), sequence:)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def branch(node:, sequence:) # rubocop:disable Metrics/AbcSize
|
|
17
|
-
until sequence.empty?
|
|
18
|
-
segment = sequence.shift
|
|
19
|
-
|
|
20
|
-
if segment.is_a?(String)
|
|
21
|
-
node.children << segment
|
|
22
|
-
elsif segment[:var]
|
|
23
|
-
node.children << @factory.var_node(segment:)
|
|
24
|
-
elsif segment[:raw_var]
|
|
25
|
-
node.children << @factory.raw_var_node(segment:)
|
|
26
|
-
elsif segment[:prop]
|
|
27
|
-
node.children << @factory.prop_node(segment:)
|
|
28
|
-
elsif segment[:slot]
|
|
29
|
-
node.children << @factory.yield_node(segment:)
|
|
30
|
-
elsif segment[:slot_def]
|
|
31
|
-
slot_node = @factory.slot_node(segment:)
|
|
32
|
-
node.children << slot_node
|
|
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')
|
|
38
|
-
elsif segment[:for_def]
|
|
39
|
-
for_node = @factory.for_node(segment:)
|
|
40
|
-
node.children << for_node
|
|
41
|
-
sub_branch(node: for_node, sequence:, end_key: :for_end, end_name: 'level_1')
|
|
42
|
-
elsif segment[:form_def]
|
|
43
|
-
form_node = @factory.form_node(segment:)
|
|
44
|
-
node.children << form_node
|
|
45
|
-
sub_branch(node: form_node, sequence:, end_key: :form_end, end_name: 'level_1')
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
node
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def sub_branch(node:, sequence:, end_key:, end_name: nil)
|
|
53
|
-
sub_sequence = []
|
|
54
|
-
sub_sequence << sequence.shift until sequence.first.is_a?(Hash) && sequence.first[end_key] == end_name
|
|
55
|
-
|
|
56
|
-
branch(node:, sequence: sub_sequence)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|