antlers 0.8.2 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0dbec268b4fe0b7966b5f7161c61b16c155695ae10ab9c16d66ea67462348f4
4
- data.tar.gz: a5ef4b1479077100df98ebf33a16379cf934cecbb980184008b5ecb86c3bcbb0
3
+ metadata.gz: f16d22b587d7dbdc07a0a51fc19032271be9347e90eb09c77541a56099f8088f
4
+ data.tar.gz: b1437b4cac8a748fc23fc6eaf06c07e5d3111d63d5100651afb9195f488dacfb
5
5
  SHA512:
6
- metadata.gz: e8e4537ad73ba6356a5ce6a4632da46113374c21e6449ba9f744f9166e47ec93fcb619cab17d536d0b6413145c11e91f726b0a48e6b628af35c3662ec55e2970
7
- data.tar.gz: 34b6b683e8ca4d3b736efa8684d049064032abf7ca081d2791370e0135b8ff7adc02e67dcf22a3c32dbe616b84302882b5346cc28c0915145e5278252cab5048
6
+ metadata.gz: ecc5de204a45f9cda60f03aeefc49aee735fc9aa3da5fd20b1d12959497bfb4683ab299bd64d4ae8795b3296ab9e018c8b8eb70672f3788aeeeaf8355f03d07e
7
+ data.tar.gz: 0b14edede169971914c9958f4b3369c361271566d36c883dd3c1774ef968e8299d2d95c58a90e921ea2bbae5d70f4a2634c8ce00217e058c2ee6c71a9ec3a42f
@@ -8,10 +8,8 @@ module Antlers
8
8
 
9
9
  plug(:root) do
10
10
  plug(:node) do
11
- lazy do
12
- require_relative '../nodes/root_node'
13
- RootNode
14
- end
11
+ require_relative '../nodes/root_node'
12
+ RootNode
15
13
  end
16
14
  end
17
15
 
@@ -127,6 +125,13 @@ module Antlers
127
125
  VarNode
128
126
  end
129
127
  end
128
+
129
+ plug(:lexeme) do
130
+ lazy do
131
+ require_relative '../lexemes/var_lexeme'
132
+ VarLexeme
133
+ end
134
+ end
130
135
  end
131
136
  end
132
137
  end
data/lib/antlers/lexer.rb CHANGED
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../support/queries'
3
+ require_relative '../lexemes/var_lexeme'
4
4
 
5
5
  module Antlers
6
- extend Queries
7
-
8
6
  class LexerError < StandardError; end
9
7
 
10
8
  class Lexer
11
9
  def initialize(lexeme_types:)
12
- @delimiters = ['<{', '}>', '{', '}']
13
- @lexeme_types = lexeme_types
10
+ @lexeme_types = lexeme_types.to_a
11
+ @var_lexeme = @lexeme_types.find { it == VarLexeme }
12
+
13
+ @delimiters = ['<{', '}>']
14
+ @delimiters = [*@delimiters, '{', '}'] if @var_lexeme
15
+
14
16
  @keywords = @lexeme_types.flat_map { |lexeme| lexeme.const_get(:KEYWORDS) }
15
17
  @cursor = 0
16
18
  end
@@ -23,8 +25,8 @@ module Antlers
23
25
  segments = template.split(/(#{Regexp.union(@delimiters)})/).map(&:strip)
24
26
 
25
27
  until segments[@cursor].nil?
26
- if (antlers_segment = antlers_segment(segments:))
27
- sequence << antlers_lexeme(antlers_segment:, segments:)
28
+ if (segment = antlers_segment(segments:))
29
+ sequence << antlers_lexeme(segment:, segments:)
28
30
  # Skipping: ['{', 'expression', '}']
29
31
  # Skipping: ['<{', 'name + props + keywords', '}>']
30
32
  @cursor += 3
@@ -47,20 +49,21 @@ module Antlers
47
49
  next_segment
48
50
  end
49
51
 
50
- def antlers_lexeme(antlers_segment:, segments:)
51
- return var(antlers_segment:) if brackets?(segments:)
52
+ def antlers_lexeme(segment:, segments:)
53
+ name, props, keywords = parse_antlers_segment(segment:)
52
54
 
53
- name, props, keywords = parse_segment(antlers_segment:)
55
+ return @var_lexeme.lexeme(segment:, raw: false) if @var_lexeme && brackets?(segments:)
54
56
 
55
57
  lexeme = @lexeme_types.find { it.match?(name:, keywords:) }
56
58
  return lexeme.lexeme(name:, props:, keywords:) if lexeme
57
- return var(antlers_segment:, raw: true) if deerheads?(segments:)
58
59
 
59
- raise LexerError, "Unrecognised syntax: '#{antlers_segment}'"
60
+ return @var_lexeme.lexeme(segment:, raw: true) if @var_lexeme && deerheads?(segments:)
61
+
62
+ raise LexerError, "Unrecognised syntax: '#{segment}'"
60
63
  end
61
64
 
62
- def parse_segment(antlers_segment:)
63
- name_and_props, *keywords = antlers_segment.split(/(#{Regexp.union(@keywords)})/)
65
+ def parse_antlers_segment(segment:)
66
+ name_and_props, *keywords = segment.split(/(#{Regexp.union(@keywords)})/)
64
67
  name, *props = name_and_props.split(' ')
65
68
  [name, props, parse_keywords(keywords:)]
66
69
  end
@@ -81,8 +84,6 @@ module Antlers
81
84
  !(string.start_with?(':') || string.end_with?(':'))
82
85
  end
83
86
 
84
- # TODO: Refactor every constant, match and result method into its own class. Loop through every class and return the first match.
85
-
86
87
  def brackets?(segments:)
87
88
  first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
88
89
  first == '{' && last == '}'
@@ -92,14 +93,5 @@ module Antlers
92
93
  first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
93
94
  first == '<{' && last == '}>'
94
95
  end
95
-
96
- def var(antlers_segment:, raw: false)
97
- # String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
98
- antlers_segment = antlers_segment[1..-2] if Queries.user_defined_string?(antlers_segment)
99
-
100
- return { raw_var: antlers_segment } if raw
101
-
102
- { var: antlers_segment }
103
- end
104
96
  end
105
97
  end
@@ -4,12 +4,15 @@ module Antlers
4
4
  class Parser
5
5
  class ParserError < StandardError; end
6
6
 
7
- def initialize(namespace: nil, node_types:)
7
+ def initialize(node_types:, namespace: nil)
8
+ @node_types = node_types.to_a
8
9
  @namespace = namespace
9
- @node_types = node_types
10
+ @template = nil
10
11
  end
11
12
 
12
- def parse(sequence:, id: :root_node)
13
+ def parse(sequence:, template: nil, id: :root_node)
14
+ @template = template
15
+
13
16
  branch(node: RootNode.new(name: id), sequence:)
14
17
  end
15
18
 
@@ -20,7 +23,7 @@ module Antlers
20
23
  child_class = @node_types.find { |n| n.match?(segment:) }
21
24
  raise(ParserError, "No node matches #{segment}") unless child_class
22
25
 
23
- child = child_class.build(segment:, namespace: @namespace)
26
+ child = child_class.build(segment:, namespace: @namespace, template: @template)
24
27
  node.children << child
25
28
 
26
29
  if (end_key = child_class::END_KEY)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Antlers
4
- VERSION = '0.8.2'
4
+ VERSION = '0.9.0'
5
5
  end
data/lib/antlers.rb CHANGED
@@ -13,10 +13,8 @@ module Antlers
13
13
 
14
14
  class << self
15
15
  def ast(template:, namespace: nil, elements: Elements[*DEFAULT_ELEMENTS])
16
- return template unless template.include?('<{') || template.include?('{')
17
-
18
- sequence = Lexer.new(lexeme_types: elements[:lexeme].to_a).parse(template:)
19
- Parser.new(namespace:, node_types: elements[:node].to_a).parse(sequence:)
16
+ sequence = Lexer.new(lexeme_types: elements[:lexeme]).parse(template:)
17
+ Parser.new(namespace:, node_types: elements[:node]).parse(sequence:, template:)
20
18
  end
21
19
 
22
20
  def render(ast:, current_binding:, parent_binding: nil, slot_node: nil)
@@ -6,8 +6,31 @@ module Antlers
6
6
 
7
7
  def match?(name: nil, keywords: {}) = false
8
8
 
9
- def lexeme(name:, props:, keywords:)
9
+ def lexeme(name:, props:, keywords:, segment: nil, raw: false)
10
10
  raise NotImplementedError
11
11
  end
12
+
13
+ private
14
+
15
+ def props(props)
16
+ odd_props = props.join(' ').split(/(=)|\s/)
17
+
18
+ return {} unless odd_props.any?
19
+
20
+ props = {}
21
+ until odd_props.empty?
22
+ prop = odd_props.shift
23
+ value = nil
24
+
25
+ if odd_props.first == '='
26
+ odd_props.shift
27
+ value = odd_props.shift
28
+ end
29
+
30
+ props[prop.to_sym] = value
31
+ end
32
+
33
+ props
34
+ end
12
35
  end
13
36
  end
@@ -16,28 +16,5 @@ module Antlers
16
16
  prop[:props] = props(props) unless props.empty?
17
17
  prop
18
18
  end
19
-
20
- private
21
-
22
- def props(props)
23
- odd_props = props.join(' ').split(/(=)|\s/)
24
-
25
- return {} unless odd_props.any?
26
-
27
- props = {}
28
- until odd_props.empty?
29
- prop = odd_props.shift
30
- value = nil
31
-
32
- if odd_props.first == '='
33
- odd_props.shift
34
- value = odd_props.shift
35
- end
36
-
37
- props[prop.to_sym] = value
38
- end
39
-
40
- props
41
- end
42
19
  end
43
20
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../interfaces/lexeme'
4
+ require_relative '../support/queries'
5
+
6
+ module Antlers
7
+ module VarLexeme
8
+ include Lexeme
9
+ extend Queries
10
+ extend self
11
+
12
+ # Variables are special and are matched by the lexer.
13
+ def match?(**)
14
+ false
15
+ end
16
+
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
+ return { raw_var: segment } if raw
22
+
23
+ { var: segment }
24
+ end
25
+ end
26
+ end
@@ -35,7 +35,7 @@ module Antlers
35
35
  segment[:prop]
36
36
  end
37
37
 
38
- def build(segment:, namespace:)
38
+ def build(segment:, namespace:, **)
39
39
  new(name: segment[:prop], props: segment[:props], namespace:)
40
40
  end
41
41
  end
@@ -14,7 +14,7 @@ module Antlers
14
14
 
15
15
  attr_accessor :children
16
16
 
17
- def initialize(name:, namespace:, props: [], children: [], **)
17
+ def initialize(name:, namespace:, props: {}, children: [], **)
18
18
  super(name:, props:, children:)
19
19
 
20
20
  @namespace = namespace
@@ -43,7 +43,7 @@ module Antlers
43
43
  segment[DEF_KEY]
44
44
  end
45
45
 
46
- def build(segment:, namespace:)
46
+ def build(segment:, namespace:, **)
47
47
  new(name: segment[DEF_KEY], props: segment[:props], namespace:)
48
48
  end
49
49
  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.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -87,6 +87,7 @@ files:
87
87
  - lib/lexemes/if_lexeme.rb
88
88
  - lib/lexemes/prop_lexeme.rb
89
89
  - lib/lexemes/slot_lexeme.rb
90
+ - lib/lexemes/var_lexeme.rb
90
91
  - lib/lexemes/yield_lexeme.rb
91
92
  - lib/modules/namespace.rb
92
93
  - lib/modules/props.rb