antlers 1.0.0 → 1.1.1
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/api.rb +1 -0
- data/lib/antlers/lexer.rb +4 -2
- data/lib/antlers/parser.rb +7 -1
- data/lib/antlers/version.rb +1 -1
- data/lib/antlers.rb +9 -13
- data/lib/interfaces/antler_node.rb +8 -1
- data/lib/interfaces/branch_node.rb +2 -2
- data/lib/interfaces/lexeme.rb +1 -1
- data/lib/lexemes/form_lexeme.rb +1 -4
- data/lib/lexemes/var_lexeme.rb +1 -4
- data/lib/modules/props.rb +1 -6
- data/lib/modules/variables.rb +17 -15
- data/lib/nodes/for_node.rb +3 -3
- data/lib/nodes/form_node.rb +12 -4
- data/lib/nodes/if_node.rb +3 -3
- data/lib/nodes/prop_node.rb +5 -4
- data/lib/nodes/root_node.rb +1 -1
- data/lib/nodes/slot_node.rb +2 -2
- data/lib/nodes/var_node.rb +3 -9
- data/lib/nodes/yield_node.rb +2 -2
- metadata +1 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c1e20787d49349b0f3df0f6df128650c7214ec53cd697ec66840d6f3884d9e8
|
|
4
|
+
data.tar.gz: 3048610d15b4fe61ff67123aba2b6f81a5ef9019e4ac03dea657995c30501b17
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc0ff003117d8d08b22146b15a32f32288aef44191ba401080db525ed3125e6a7cc38fd278b64eb96eda1659d7b608cbf41f4b9a1879c8641eecf0f3fa4fc83d
|
|
7
|
+
data.tar.gz: e0a5d0d1c71721a4727b3f6134a1eafb40b75b34cff799cc5f2d94677cbf84b6e41dad3b6d8ad5bee5293ca1b1de10969d8e6af1d8cc19c6889b0dc0dbaca71b
|
data/lib/antlers/api.rb
CHANGED
data/lib/antlers/lexer.rb
CHANGED
|
@@ -73,7 +73,7 @@ module Antlers
|
|
|
73
73
|
|
|
74
74
|
while (keyword = keywords.shift)
|
|
75
75
|
keyword.strip!
|
|
76
|
-
value = keyword.end_with?(':') && value?(keywords.first
|
|
76
|
+
value = keyword.end_with?(':') && value?(keywords.first) ? keywords.shift.strip : nil
|
|
77
77
|
key_values[keyword] = value
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -81,7 +81,9 @@ module Antlers
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def value?(string)
|
|
84
|
-
|
|
84
|
+
# Support keywords without a value like "<{ form: }>" whose value will become an empty string.
|
|
85
|
+
string = string.to_s.strip
|
|
86
|
+
!string.empty? && !(string.start_with?(':') || string.end_with?(':'))
|
|
85
87
|
end
|
|
86
88
|
|
|
87
89
|
def brackets?(segments:)
|
data/lib/antlers/parser.rb
CHANGED
|
@@ -36,7 +36,13 @@ module Antlers
|
|
|
36
36
|
|
|
37
37
|
def sub_branch(node:, sequence:, end_key:, end_name: nil)
|
|
38
38
|
sub_sequence = []
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
until sequence.first.is_a?(Hash) && sequence.first[end_key] == end_name
|
|
41
|
+
raise ParserError, "Missing end tag for #{node.class}" if sequence.empty?
|
|
42
|
+
|
|
43
|
+
sub_sequence << sequence.shift
|
|
44
|
+
end
|
|
45
|
+
|
|
40
46
|
# Remove the end tag we just stopped before.
|
|
41
47
|
sequence.shift
|
|
42
48
|
|
data/lib/antlers/version.rb
CHANGED
data/lib/antlers.rb
CHANGED
|
@@ -4,21 +4,17 @@ require_relative 'antlers/elements'
|
|
|
4
4
|
require_relative 'antlers/lexer'
|
|
5
5
|
require_relative 'antlers/parser'
|
|
6
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'
|
|
10
|
-
|
|
11
7
|
module Antlers
|
|
12
|
-
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
DEFAULT_ELEMENTS = %i[root html form for if prop slot yield var].freeze
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
12
|
+
def ast(template:, namespace: nil, elements: Elements[*DEFAULT_ELEMENTS])
|
|
13
|
+
sequence = Lexer.new(lexeme_types: elements[:lexeme]).parse(template:)
|
|
14
|
+
Parser.new(namespace:, node_types: elements[:node]).parse(sequence:, template:)
|
|
15
|
+
end
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
17
|
+
def render(ast:, current_binding:, parent_binding: nil, slot_node: nil, metadata: {})
|
|
18
|
+
ast.render(current_binding:, parent_binding:, slot_node:, metadata:)
|
|
23
19
|
end
|
|
24
20
|
end
|
|
@@ -11,7 +11,7 @@ module Antlers
|
|
|
11
11
|
@name = name
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil, namespace: nil)
|
|
14
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, namespace: nil, metadata: {})
|
|
15
15
|
raise NotImplementedError
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -19,6 +19,13 @@ module Antlers
|
|
|
19
19
|
'level_1'
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Support sending an event to render_template hook when lowevent available. See lownode as an example implementation.
|
|
23
|
+
def possible_render_event(props:)
|
|
24
|
+
Low::Events::RenderEvent.new(action: :render, props:) if defined?(LowEvent)
|
|
25
|
+
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
22
29
|
class << self
|
|
23
30
|
def match?(segment:)
|
|
24
31
|
raise NotImplementedError
|
|
@@ -12,11 +12,11 @@ module Antlers
|
|
|
12
12
|
@children = children
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
15
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
16
16
|
output = ''
|
|
17
17
|
|
|
18
18
|
@children.each do |child|
|
|
19
|
-
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
19
|
+
output += child.render(current_binding:, parent_binding:, slot_node:, metadata:) || ''
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
output
|
data/lib/interfaces/lexeme.rb
CHANGED
data/lib/lexemes/form_lexeme.rb
CHANGED
|
@@ -14,10 +14,7 @@ module Antlers
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def lexeme(keywords:, **)
|
|
17
|
-
if keywords.key?('form:')
|
|
18
|
-
action = keywords['form:'] ? keywords['form:'][1...-1] : nil
|
|
19
|
-
return { form_def: action }
|
|
20
|
-
end
|
|
17
|
+
return { form_def: keywords['form:'] } if keywords.key?('form:')
|
|
21
18
|
|
|
22
19
|
{ form_end: 'level_1' }
|
|
23
20
|
end
|
data/lib/lexemes/var_lexeme.rb
CHANGED
|
@@ -9,15 +9,12 @@ module Antlers
|
|
|
9
9
|
extend Queries
|
|
10
10
|
extend self
|
|
11
11
|
|
|
12
|
-
# Variables are special and are matched by the lexer.
|
|
12
|
+
# Variables are special and are matched by the lexer in a hard-coded fashion.
|
|
13
13
|
def match?(**)
|
|
14
14
|
false
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def lexeme(segment:, raw:, **)
|
|
18
|
-
# String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
|
|
19
|
-
segment = segment[1..-2] if Queries.user_defined_string?(segment)
|
|
20
|
-
|
|
21
18
|
return { raw_var: segment } if raw
|
|
22
19
|
|
|
23
20
|
{ var: segment }
|
data/lib/modules/props.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'low_event'
|
|
4
3
|
require_relative 'variables'
|
|
5
4
|
|
|
6
5
|
module Antlers
|
|
@@ -17,17 +16,13 @@ module Antlers
|
|
|
17
16
|
|
|
18
17
|
private
|
|
19
18
|
|
|
20
|
-
def create_render_event(props:)
|
|
21
|
-
Low::Events::RenderEvent.new(action: :render, props:)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
19
|
def evaluate_props(props:, current_binding:)
|
|
25
20
|
return {} if props.nil?
|
|
26
21
|
|
|
27
22
|
evaluated_props = {}
|
|
28
23
|
|
|
29
24
|
props.each do |name, value|
|
|
30
|
-
evaluated_props[name] = evaluate(
|
|
25
|
+
evaluated_props[name] = evaluate(value:, current_binding:)
|
|
31
26
|
end
|
|
32
27
|
|
|
33
28
|
evaluated_props
|
data/lib/modules/variables.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'erb'
|
|
3
4
|
require_relative '../support/queries'
|
|
4
5
|
|
|
5
6
|
module Antlers
|
|
@@ -7,28 +8,29 @@ module Antlers
|
|
|
7
8
|
extend Queries
|
|
8
9
|
|
|
9
10
|
# Evaluation limited to the following for security and to stop a templating language becoming a programming language.
|
|
10
|
-
# 1.
|
|
11
|
-
# 2.
|
|
12
|
-
# 3. A method
|
|
13
|
-
# 4. A
|
|
14
|
-
def evaluate(
|
|
15
|
-
|
|
11
|
+
# 1. A static string
|
|
12
|
+
# 2. An instance variable
|
|
13
|
+
# 3. A method call/local variable
|
|
14
|
+
# 4. A method chain
|
|
15
|
+
def evaluate(value:, current_binding:, escape: true)
|
|
16
|
+
result = result(value:, current_binding:)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
return ERB::Util.html_escape(result) if escape
|
|
19
|
+
|
|
20
|
+
result
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def result(value:, current_binding:)
|
|
24
|
+
return value[1..-2] if Queries.user_defined_string?(value)
|
|
25
|
+
return value unless current_binding
|
|
26
|
+
|
|
27
|
+
name, *chain = value.split('.')
|
|
18
28
|
|
|
19
29
|
result = method_var(name:, current_binding:)
|
|
20
30
|
return method_chain(result:, chain:) if chain.count > 0
|
|
21
31
|
return result if result
|
|
22
32
|
|
|
23
33
|
nil
|
|
24
|
-
rescue StandardError
|
|
25
|
-
nil
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def fallback(value)
|
|
29
|
-
return value[1..-2] if Queries.user_defined_string?(value)
|
|
30
|
-
|
|
31
|
-
value
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
private
|
data/lib/nodes/for_node.rb
CHANGED
|
@@ -20,10 +20,10 @@ module Antlers
|
|
|
20
20
|
@key = key
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
23
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
24
24
|
output = ''
|
|
25
25
|
|
|
26
|
-
evaluate(
|
|
26
|
+
evaluate(value: @items, current_binding:, escape: false).each do |value|
|
|
27
27
|
key, value = value if @key
|
|
28
28
|
|
|
29
29
|
# TODO: Parallelize by creating new bindings and ensuring children have any args they need via RenderEvent.
|
|
@@ -31,7 +31,7 @@ module Antlers
|
|
|
31
31
|
current_binding.local_variable_set(@key, key) if @key
|
|
32
32
|
|
|
33
33
|
@children.each do |child|
|
|
34
|
-
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
34
|
+
output += child.render(current_binding:, parent_binding:, slot_node:, metadata:) || ''
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
data/lib/nodes/form_node.rb
CHANGED
|
@@ -19,20 +19,28 @@ module Antlers
|
|
|
19
19
|
@method = method
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
23
|
-
output = "<form action='#{
|
|
22
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
23
|
+
output = "<form action='#{action(current_binding:)}' method='#{@method}'>"
|
|
24
24
|
|
|
25
25
|
@children.each do |child|
|
|
26
|
-
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
26
|
+
output += child.render(current_binding:, parent_binding:, slot_node:, metadata:) || ''
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
output += '</form>'
|
|
30
30
|
output
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def action(current_binding:)
|
|
36
|
+
return if @action.nil?
|
|
37
|
+
|
|
38
|
+
evaluate(value: @action, current_binding:)
|
|
39
|
+
end
|
|
40
|
+
|
|
33
41
|
class << self
|
|
34
42
|
def match?(segment:)
|
|
35
|
-
segment
|
|
43
|
+
segment.is_a?(Hash) && segment.key?(DEF_KEY)
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def build(segment:, **)
|
data/lib/nodes/if_node.rb
CHANGED
|
@@ -18,12 +18,12 @@ module Antlers
|
|
|
18
18
|
@value = value
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
21
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
22
22
|
output = ''.dup
|
|
23
23
|
|
|
24
|
-
if evaluate(
|
|
24
|
+
if evaluate(value: @value, current_binding:, escape: false)
|
|
25
25
|
@children.each do |child|
|
|
26
|
-
output += child.render(current_binding:, parent_binding:, slot_node:) || ''
|
|
26
|
+
output += child.render(current_binding:, parent_binding:, slot_node:, metadata:) || ''
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
data/lib/nodes/prop_node.rb
CHANGED
|
@@ -15,12 +15,12 @@ module Antlers
|
|
|
15
15
|
@namespace = namespace
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
# Classes referenced via "<{ MyNode }>" must implement class/instance and render/render_template methods (See
|
|
19
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
18
|
+
# Classes referenced via "<{ MyNode }>" must implement class/instance and render/render_template methods (See lownode).
|
|
19
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
20
20
|
props = evaluate_props(props: @props, current_binding:)
|
|
21
|
-
event =
|
|
21
|
+
event = possible_render_event(props:)
|
|
22
22
|
|
|
23
|
-
# TODO: Get
|
|
23
|
+
# TODO: Get dirload to load constants defined in "<{ MyNode }>" syntax so that we can resolve namespace/params on class load.
|
|
24
24
|
klass = class_constant(namespace: @namespace&.split('::') || [], name: @name)
|
|
25
25
|
class_proxy = Lowkey[klass.to_s].first[klass.to_s]
|
|
26
26
|
|
|
@@ -44,6 +44,7 @@ module Antlers
|
|
|
44
44
|
|
|
45
45
|
def create_instance(class_proxy:, klass:, event:, props:)
|
|
46
46
|
initialize_params = class_proxy.instance_methods[:initialize]&.tagged_params(:keyword)&.map(&:name) || []
|
|
47
|
+
|
|
47
48
|
return klass.new(event:, **props) if initialize_params.include?(:event) && initialize_params.count > 1
|
|
48
49
|
return klass.new(**props) if initialize_params.count > 1
|
|
49
50
|
return klass.new(event:) if initialize_params.include?(:event)
|
data/lib/nodes/root_node.rb
CHANGED
data/lib/nodes/slot_node.rb
CHANGED
|
@@ -20,9 +20,9 @@ module Antlers
|
|
|
20
20
|
@namespace = namespace
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
23
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
24
24
|
props = evaluate_props(props: @props, current_binding:)
|
|
25
|
-
event =
|
|
25
|
+
event = possible_render_event(props:)
|
|
26
26
|
|
|
27
27
|
# TODO: Get LowLoad to load constants defined in "<{ MyNode }>" syntax so that we can resolve namespace/params on class load.
|
|
28
28
|
klass = class_constant(namespace: @namespace&.split('::') || [], name:)
|
data/lib/nodes/var_node.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'erb'
|
|
4
|
-
|
|
5
3
|
require_relative '../interfaces/leaf_node'
|
|
6
4
|
require_relative '../modules/variables'
|
|
7
5
|
|
|
@@ -18,12 +16,8 @@ module Antlers
|
|
|
18
16
|
@raw = raw
|
|
19
17
|
end
|
|
20
18
|
|
|
21
|
-
def render(current_binding: nil, parent_binding: nil, slot_node: nil)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return result if @raw
|
|
25
|
-
|
|
26
|
-
ERB::Util.html_escape(result)
|
|
19
|
+
def render(current_binding: nil, parent_binding: nil, slot_node: nil, metadata: {})
|
|
20
|
+
evaluate(value: @value, current_binding:, escape: !@raw)
|
|
27
21
|
end
|
|
28
22
|
|
|
29
23
|
class << self
|
|
@@ -32,7 +26,7 @@ module Antlers
|
|
|
32
26
|
end
|
|
33
27
|
|
|
34
28
|
def build(segment:, **)
|
|
35
|
-
new(value: segment[:var] || segment[:raw_var], raw:
|
|
29
|
+
new(value: segment[:var] || segment[:raw_var], raw: !segment[:raw_var].nil?)
|
|
36
30
|
end
|
|
37
31
|
end
|
|
38
32
|
end
|
data/lib/nodes/yield_node.rb
CHANGED
|
@@ -9,11 +9,11 @@ module Antlers
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
# Render the children in the binding of the parent.
|
|
12
|
-
def render(current_binding: nil,
|
|
12
|
+
def render(parent_binding:, slot_node:, current_binding: nil, metadata: {})
|
|
13
13
|
output = ''
|
|
14
14
|
|
|
15
15
|
slot_node.children.each do |child|
|
|
16
|
-
output += child.render(current_binding: parent_binding, parent_binding:, slot_node:) || ''
|
|
16
|
+
output += child.render(current_binding: parent_binding, parent_binding:, slot_node:, metadata:) || ''
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
output
|
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: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -23,20 +23,6 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: low_event
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0'
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: lowkey
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|