antlers 0.3.0 → 0.4.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: 57d224246ca8ba02aac3045b0f06904d8cebb0cfdb7f3d518d3c646324a1e3b6
4
- data.tar.gz: e8b7787ccfc284dbb1d370292ba4238576e346c75bc957d5da70067220635ba7
3
+ metadata.gz: 581b3e4990e2c5279c26989e05e545f61a80a3fb8590c8a4bfd058878f2684f8
4
+ data.tar.gz: 5135d9c10a19fa9bb80c79694f998287c1dad614514a6d22c915cfc371d54b71
5
5
  SHA512:
6
- metadata.gz: b4cb6632bbbafb3ec12cc27256b2ae9e2134e3b621e28a7edcfd269bfff828d128cd0f659d7135a734b7792d121477c0ca012c3215a1eef442d3106bb637e89d
7
- data.tar.gz: 0a0f5f6fc83e72a7253a737956c3a4cff5961999722b23b96ad44716b3ad2b2e40ce7742145cea8610f9604467a438a12000a0609cd9408487f85472f362cb3d
6
+ metadata.gz: 4e85dd8fc504c21fe4c71f692203dc695fd60834e2f2f33185c1daf6edbf3e64c4c8eccf29710d899f5beab1c348cac1c9fe6a8350778b7563cd4d879cef78e2
7
+ data.tar.gz: 5b4853ba5e0d0749d4305c57923d6488ddcd5b05892aa2e274dd3683519ae85fcbd9a84b117e9c453a9b1ab256c814cd6f6d35b71db76935e30f0c86d17852ba
@@ -10,7 +10,8 @@ module Antlers
10
10
  class NodeFactory
11
11
  class << self
12
12
  def for_node(segment:)
13
- ForNode.new(name: segment[:for_def], item: segment[:for_def], items: segment[:in])
13
+ value, key, items = segment.values_at(:for_def, :key, :in)
14
+ ForNode.new(name: value, key:, value:, items:)
14
15
  end
15
16
 
16
17
  def prop_node(segment:)
data/lib/lexer.rb CHANGED
@@ -67,12 +67,12 @@ module Antlers
67
67
  end
68
68
 
69
69
  def var?(segments:)
70
- first, middle, last = segments[@cursor..@cursor + 3].map(&:strip)
70
+ first, _, last = segments[@cursor..@cursor + 3].map(&:strip)
71
71
  first == '{' && last == '}'
72
72
  end
73
73
 
74
74
  def for_loop?(keywords:)
75
- keywords.first == 'for:' || keywords.first == ':for'
75
+ ['for:', ':for'].include?(keywords.first)
76
76
  end
77
77
 
78
78
  def slot?(name)
@@ -89,19 +89,18 @@ module Antlers
89
89
 
90
90
  def var(antlers_segment:)
91
91
  # String is already interpolated or not depending on user input on the template layer, now we store it without those template quotes.
92
- if Queries.user_defined_string?(antlers_segment)
93
- antlers_segment = antlers_segment[1..-2]
94
- end
92
+ antlers_segment = antlers_segment[1..-2] if Queries.user_defined_string?(antlers_segment)
95
93
 
96
94
  { var: antlers_segment }
97
95
  end
98
96
 
99
97
  def for_loop(keywords:)
100
- key_values = keywords.count % 2 == 0 ? keywords.each_slice(2).to_h : {}
98
+ key_values = keywords.count.even? ? keywords.each_slice(2).to_h : {}
101
99
 
102
100
  if key_values['for:']
103
- for_def = { for_def: key_values['for:'] }
104
- for_def[:in] = key_values['in:']
101
+ *key, value = key_values['for:'].split(',').map(&:strip)
102
+ for_def = { for_def: value, in: key_values['in:'] }
103
+ for_def[:key] = key.first unless key.empty?
105
104
  return for_def
106
105
  end
107
106
 
data/lib/modules/props.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'low_event'
4
+ require_relative 'variables'
4
5
 
5
6
  module Antlers
6
7
  module Props
8
+ include Variables
9
+
7
10
  attr_accessor :props
8
11
 
9
12
  def initialize(name:, props: {}, **)
@@ -24,13 +27,7 @@ module Antlers
24
27
  evaluated_props = {}
25
28
 
26
29
  props.each do |name, value|
27
- receiver = current_binding.receiver
28
-
29
- if receiver.respond_to?(value.to_sym)
30
- evaluated_props[name] = receiver.send(value.to_sym)
31
- elsif value.start_with?('@')
32
- evaluated_props[name] = receiver.instance_variable_get(value)
33
- end
30
+ evaluated_props[name] = evaluate(name: value, current_binding:)
34
31
  end
35
32
 
36
33
  evaluated_props
@@ -1,19 +1,38 @@
1
1
  module Antlers
2
2
  module Variables
3
- # A variable is deliberately limited in what it can represent.
3
+ # Evaluation limited to the following for security and to prevent a templating language becoming a programming language.
4
4
  # 1. An instance variable
5
5
  # 2. A method call/local variable
6
- # 3. A static string
7
- def evaluate_variable(name:, current_binding:)
8
- if current_binding
9
- return current_binding.receiver.instance_variable_get(name) if name.start_with?('@')
10
- return current_binding.local_variable_get(name) if current_binding.local_variable_defined?(name)
11
- return current_binding.receiver.send(name.to_sym) if current_binding.receiver.respond_to?(name.to_sym)
12
- end
6
+ # 3. A method chain
7
+ # 4. A static string
8
+ def evaluate(name:, current_binding:)
9
+ return @value.to_s unless current_binding
10
+
11
+ name, *chain = name.split('.')
12
+
13
+ result = method_var(name:, current_binding:)
14
+ return method_chain(result:, chain:, current_binding:) if chain.count > 0
15
+ return result if result
13
16
 
14
17
  @value.to_s
15
18
  rescue NameError
16
19
  @value.to_s
17
20
  end
21
+
22
+ private
23
+
24
+ def method_var(name:, current_binding:)
25
+ return current_binding.receiver.instance_variable_get(name) if name.start_with?('@')
26
+ return current_binding.local_variable_get(name) if current_binding.local_variable_defined?(name)
27
+ return current_binding.receiver.send(name.to_sym) if current_binding.receiver.respond_to?(name.to_sym)
28
+
29
+ nil
30
+ end
31
+
32
+ def method_chain(result:, chain:, current_binding:)
33
+ chain.reduce(result) do |result, method_call|
34
+ result.send(method_call.to_sym)
35
+ end
36
+ end
18
37
  end
19
38
  end
@@ -11,18 +11,23 @@ module Antlers
11
11
 
12
12
  attr_accessor :children
13
13
 
14
- def initialize(name:, item:, items:, props: [], children: [])
14
+ def initialize(name:, items:, value:, key: nil, props: [], children: [])
15
15
  super(name:, props:, children:)
16
16
 
17
- @item = item
18
17
  @items = items
18
+ @value = value
19
+ @key = key
19
20
  end
20
21
 
21
22
  def render(current_binding: nil, parent_binding: nil, slot_node: nil, namespace: nil)
22
23
  output = ''
23
24
 
24
- evaluate_variable(name: @items, current_binding:).each do |item|
25
- current_binding.local_variable_set(@item, item)
25
+ evaluate(name: @items, current_binding:).each do |value|
26
+ key, value = value if @key
27
+
28
+ # TODO: Parallelize by creating new bindings and ensuring children have any args they need via RenderEvent.
29
+ current_binding.local_variable_set(@value, value)
30
+ current_binding.local_variable_set(@key, key) if @key
26
31
 
27
32
  @children.each do |child|
28
33
  # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
@@ -11,14 +11,14 @@ module Antlers
11
11
 
12
12
  attr_reader :value
13
13
 
14
- def initialize(name: :var, value:)
14
+ def initialize(value:, name: :var)
15
15
  super(name:)
16
16
 
17
17
  @value = value
18
18
  end
19
19
 
20
20
  def render(current_binding: nil, parent_binding: nil, slot_node: nil, namespace: nil)
21
- ERB::Util.html_escape(evaluate_variable(name: @value, current_binding:) || @value)
21
+ ERB::Util.html_escape(evaluate(name: @value, current_binding:) || @value)
22
22
  end
23
23
  end
24
24
  end
@@ -14,7 +14,11 @@ module Antlers
14
14
 
15
15
  slot_node.children.each do |child|
16
16
  # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
17
- output += (child.respond_to?(:render) ? child.render(current_binding: parent_binding, parent_binding: nil, slot_node: nil, namespace:) : child) || ''
17
+ if child.respond_to?(:render) # rubocop:disable Style/ConditionalAssignment
18
+ output += child.render(current_binding: parent_binding, parent_binding: nil, slot_node: nil, namespace:)
19
+ else
20
+ output += child || ''
21
+ end
18
22
  end
19
23
 
20
24
  output
data/lib/queries.rb CHANGED
@@ -4,7 +4,7 @@ module Antlers
4
4
  module Queries
5
5
  class << self
6
6
  def user_defined_string?(string)
7
- wrapped_in?(string, %q{'}) || wrapped_in?(string, %q{"})
7
+ wrapped_in?(string, "'") || wrapped_in?(string, '"')
8
8
  end
9
9
 
10
10
  def wrapped_in?(string, delimeter)
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Antlers
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  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.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -10,7 +10,7 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: low_event
13
+ name: erb
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
@@ -24,7 +24,7 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0'
26
26
  - !ruby/object:Gem::Dependency
27
- name: erb
27
+ name: low_event
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ">="