rbexy 1.1.0 → 2.0.0.beta5

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -1
  3. data/README.md +19 -1
  4. data/lib/rbexy.rb +26 -9
  5. data/lib/rbexy/ast_transformer.rb +21 -0
  6. data/lib/rbexy/cache_component.rb +17 -0
  7. data/lib/rbexy/component.rb +35 -21
  8. data/lib/rbexy/component_resolver.rb +60 -0
  9. data/lib/rbexy/configuration.rb +18 -1
  10. data/lib/rbexy/lexer.rb +21 -14
  11. data/lib/rbexy/nodes.rb +15 -135
  12. data/lib/rbexy/nodes/abstract_attr.rb +12 -0
  13. data/lib/rbexy/nodes/abstract_element.rb +13 -0
  14. data/lib/rbexy/nodes/abstract_node.rb +58 -0
  15. data/lib/rbexy/nodes/component_element.rb +69 -0
  16. data/lib/rbexy/nodes/component_prop.rb +29 -0
  17. data/lib/rbexy/nodes/declaration.rb +15 -0
  18. data/lib/rbexy/nodes/expression.rb +15 -0
  19. data/lib/rbexy/nodes/expression_group.rb +55 -0
  20. data/lib/rbexy/nodes/html_attr.rb +13 -0
  21. data/lib/rbexy/nodes/html_element.rb +48 -0
  22. data/lib/rbexy/nodes/newline.rb +9 -0
  23. data/lib/rbexy/nodes/raw.rb +23 -0
  24. data/lib/rbexy/nodes/root.rb +19 -0
  25. data/lib/rbexy/nodes/text.rb +15 -0
  26. data/lib/rbexy/nodes/util.rb +9 -0
  27. data/lib/rbexy/parser.rb +22 -16
  28. data/lib/rbexy/rails.rb +2 -0
  29. data/lib/rbexy/rails/component_template_resolver.rb +59 -4
  30. data/lib/rbexy/rails/controller_helper.rb +0 -6
  31. data/lib/rbexy/rails/engine.rb +3 -7
  32. data/lib/rbexy/rails/rbx_dependency_tracker.rb +37 -0
  33. data/lib/rbexy/refinements.rb +5 -0
  34. data/lib/rbexy/refinements/array.rb +9 -0
  35. data/lib/rbexy/refinements/array/find_map.rb +13 -0
  36. data/lib/rbexy/refinements/array/insert_between_types.rb +26 -0
  37. data/lib/rbexy/refinements/array/map_type_when_neighboring_type.rb +26 -0
  38. data/lib/rbexy/runtime.rb +15 -23
  39. data/lib/rbexy/template.rb +12 -0
  40. data/lib/rbexy/version.rb +1 -1
  41. data/rbexy.gemspec +1 -0
  42. metadata +43 -11
  43. data/example.rb +0 -113
  44. data/lib/rbexy/component_providers/namespaced_rbexy_provider.rb +0 -20
  45. data/lib/rbexy/component_providers/rbexy_provider.rb +0 -21
  46. data/lib/rbexy/component_providers/view_component_provider.rb +0 -21
  47. data/lib/rbexy/component_tag_builder.rb +0 -19
  48. data/lib/rbexy/hash_mash.rb +0 -15
  49. data/lib/rbexy/view_context_helper.rb +0 -19
@@ -1,139 +1,19 @@
1
1
  module Rbexy
2
2
  module Nodes
3
- module Util
4
- def self.safe_string(str)
5
- str.gsub('"', '\\"')
6
- end
7
-
8
- def self.safe_tag_name(name)
9
- name.gsub(".", "__")
10
- end
11
- end
12
-
13
- class Template
14
- attr_reader :children
15
-
16
- def initialize(children)
17
- @children = children
18
- end
19
-
20
- def compile
21
- "#{children.map(&:compile).map { |c| "@output_buffer << rbexy_prep_output(#{c})"}.join(";")};@output_buffer"
22
- end
23
- end
24
-
25
- class Text
26
- attr_reader :content
27
-
28
- def initialize(content)
29
- @content = content
30
- end
31
-
32
- def compile
33
- "\"#{Util.safe_string(content)}\""
34
- end
35
- end
36
-
37
- class ExpressionGroup
38
- attr_reader :statements
39
-
40
- def initialize(statements)
41
- @statements = statements
42
- end
43
-
44
- def compile
45
- statements.map(&:compile).join
46
- end
47
- end
48
-
49
- class Expression
50
- attr_reader :content
51
-
52
- def initialize(content)
53
- @content = content
54
- end
55
-
56
- def compile
57
- content
58
- end
59
- end
60
-
61
- class XmlNode
62
- attr_reader :name, :members, :children
63
-
64
- def initialize(name, members, children)
65
- @name = name
66
- @members = members || []
67
- @children = children
68
- end
69
-
70
- def compile
71
- base_tag = "rbexy_tag.#{Util.safe_tag_name(name)}(#{compile_members})"
72
- tag = if children.length > 0
73
- [
74
- "#{base_tag} { capture {",
75
- children.map(&:compile).map { |c| "@output_buffer << rbexy_prep_output(#{c})" }.join(";"),
76
- "} }"
77
- ].join
78
- else
79
- base_tag
80
- end + ".html_safe"
81
-
82
- if Rbexy.configuration.enable_context
83
- [
84
- "(",
85
- "rbexy_context.push({});",
86
- "#{tag}.tap { rbexy_context.pop }",
87
- ")"
88
- ].join
89
- else
90
- tag
91
- end
92
- end
93
-
94
- def compile_members
95
- members.each_with_object("") do |member, result|
96
- case member
97
- when ExpressionGroup
98
- result << "**#{member.compile},"
99
- when SilentNewline
100
- result << member.compile
101
- else
102
- result << "#{member.compile},"
103
- end
104
- end
105
- end
106
- end
107
-
108
- class XmlAttr
109
- attr_reader :name, :value
110
-
111
- def initialize(name, value)
112
- @name = name
113
- @value = value
114
- end
115
-
116
- def compile
117
- "\"#{name}\": #{value.compile}"
118
- end
119
- end
120
-
121
- class SilentNewline
122
- def compile
123
- "\n"
124
- end
125
- end
126
-
127
- class Declaration
128
- attr_reader :content
129
-
130
- def initialize(content)
131
- @content = content
132
- end
133
-
134
- def compile
135
- "\"#{Util.safe_string(content)}\".html_safe"
136
- end
137
- end
3
+ autoload :Util, "rbexy/nodes/util"
4
+ autoload :AbstractNode, "rbexy/nodes/abstract_node"
5
+ autoload :Root, "rbexy/nodes/root"
6
+ autoload :Raw, "rbexy/nodes/raw"
7
+ autoload :Text, "rbexy/nodes/text"
8
+ autoload :ExpressionGroup, "rbexy/nodes/expression_group"
9
+ autoload :Expression, "rbexy/nodes/expression"
10
+ autoload :AbstractElement, "rbexy/nodes/abstract_element"
11
+ autoload :HTMLElement, "rbexy/nodes/html_element"
12
+ autoload :ComponentElement, "rbexy/nodes/component_element"
13
+ autoload :AbstractAttr, "rbexy/nodes/abstract_attr"
14
+ autoload :HTMLAttr, "rbexy/nodes/html_attr"
15
+ autoload :ComponentProp, "rbexy/nodes/component_prop"
16
+ autoload :Newline, "rbexy/nodes/newline"
17
+ autoload :Declaration, "rbexy/nodes/declaration"
138
18
  end
139
19
  end
@@ -0,0 +1,12 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class AbstractAttr < AbstractNode
4
+ attr_accessor :name, :value
5
+
6
+ def initialize(name, value)
7
+ @name = name
8
+ @value = value
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class AbstractElement < AbstractNode
4
+ attr_accessor :name, :members, :children
5
+
6
+ def initialize(name, members, children)
7
+ @name = name
8
+ @members = members || []
9
+ @children = children
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class AbstractNode
4
+ PrecompileRequired = Class.new(StandardError)
5
+
6
+ attr_reader :compile_context
7
+
8
+ def precompile
9
+ [self]
10
+ end
11
+
12
+ def compile
13
+ raise PrecompileRequired, "#{self.class.name} must be precompiled first"
14
+ end
15
+
16
+ def inject_compile_context(context)
17
+ @compile_context = context
18
+ children.each { |c| c.inject_compile_context(context) } if respond_to?(:children)
19
+ members.each { |c| c.inject_compile_context(context) } if respond_to?(:members)
20
+ end
21
+
22
+ def transform!
23
+ return unless ast_transformer
24
+ ast_transformer.transform(self, compile_context)
25
+ children.each(&:transform!) if respond_to?(:children)
26
+ members.each(&:transform!) if respond_to?(:members)
27
+ end
28
+
29
+ private
30
+
31
+ def ast_transformer
32
+ compile_context.ast_transformer
33
+ end
34
+
35
+ def compact(nodes)
36
+ compacted = []
37
+ curr_raw = nil
38
+
39
+ nodes.each do |node|
40
+ if node.is_a?(Newline) && curr_raw
41
+ curr_raw.merge(Raw.new("\n"))
42
+ elsif node.is_a?(Raw)
43
+ if !curr_raw
44
+ curr_raw ||= Raw.new("")
45
+ compacted << curr_raw
46
+ end
47
+ curr_raw.merge(node)
48
+ else
49
+ curr_raw = nil
50
+ compacted << node
51
+ end
52
+ end
53
+
54
+ compacted
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,69 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class ComponentElement < AbstractElement
4
+ attr_reader :template
5
+
6
+ OUTPUT = "@output_buffer.safe_concat(%s);"
7
+ EXPR_STRING = "%s.html_safe"
8
+
9
+ def initialize(*args, template: OUTPUT)
10
+ super(*args)
11
+ @template = template
12
+ end
13
+
14
+ def precompile
15
+ [ComponentElement.new(name, precompile_members, precompile_children)]
16
+ end
17
+
18
+ def compile
19
+ templates = Rbexy.configuration.component_rendering_templates
20
+
21
+ tag = templates[:component] % {
22
+ component_class: name,
23
+ view_context: "self",
24
+ kwargs: compile_members,
25
+ children_block: children.any? ? templates[:children] % { children: children.map(&:compile).join } : ""
26
+ }
27
+
28
+ if Rbexy.configuration.enable_context
29
+ tag = "(rbexy_context.push({});#{tag}.tap{rbexy_context.pop})"
30
+ end
31
+
32
+ template % tag
33
+ end
34
+
35
+ def compile_members
36
+ members.each_with_object("") do |member, result|
37
+ case member
38
+ when ExpressionGroup
39
+ result << "**#{member.compile}.transform_keys { |k| ActiveSupport::Inflector.underscore(k).to_sym },"
40
+ when Newline
41
+ result << member.compile
42
+ else
43
+ result << "#{member.compile},"
44
+ end
45
+ end.gsub(/,\z/, "")
46
+ end
47
+
48
+ private
49
+
50
+ def precompile_members
51
+ members.map do |node|
52
+ if node.is_a? ExpressionGroup
53
+ ExpressionGroup.new(
54
+ node.members,
55
+ inner_template: ExpressionGroup::SUB_EXPR,
56
+ outer_template: ExpressionGroup::SUB_EXPR
57
+ )
58
+ else
59
+ node
60
+ end
61
+ end.map(&:precompile).flatten
62
+ end
63
+
64
+ def precompile_children
65
+ compact(children.map(&:precompile).flatten)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,29 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class ComponentProp < AbstractAttr
4
+ def precompile
5
+ [ComponentProp.new(name, precompile_value)]
6
+ end
7
+
8
+ def compile
9
+ key = ActiveSupport::Inflector.underscore(name)
10
+ "#{key}: #{value.compile}"
11
+ end
12
+
13
+ private
14
+
15
+ def precompile_value
16
+ node = value.precompile.first
17
+
18
+ case node
19
+ when Raw
20
+ Raw.new(node.content, template: Raw::EXPR_STRING)
21
+ when ExpressionGroup
22
+ ExpressionGroup.new(node.members, outer_template: ExpressionGroup::SUB_EXPR, inner_template: node.inner_template)
23
+ else
24
+ node
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class Declaration < AbstractNode
4
+ attr_accessor :content
5
+
6
+ def initialize(content)
7
+ @content = content
8
+ end
9
+
10
+ def precompile
11
+ [Raw.new(Util.escape_string(content))]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class Expression < AbstractNode
4
+ attr_accessor :content
5
+
6
+ def initialize(content)
7
+ @content = content
8
+ end
9
+
10
+ def compile
11
+ content
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class ExpressionGroup < AbstractNode
4
+ using Rbexy::Refinements::Array::MapTypeWhenNeighboringType
5
+ using Rbexy::Refinements::Array::InsertBetweenTypes
6
+
7
+ attr_accessor :members
8
+ attr_reader :outer_template, :inner_template
9
+
10
+ OUTPUT_UNSAFE = "@output_buffer.concat(Rbexy::Runtime.expr_out(%s));"
11
+ OUTPUT_SAFE = "@output_buffer.safe_concat(Rbexy::Runtime.expr_out(%s));"
12
+ SUB_EXPR = "%s"
13
+ SUB_EXPR_OUT = "Rbexy::Runtime.expr_out(%s)"
14
+
15
+ def initialize(members, outer_template: OUTPUT_UNSAFE, inner_template: "%s")
16
+ @members = members
17
+ @outer_template = outer_template
18
+ @inner_template = inner_template
19
+ end
20
+
21
+ def precompile
22
+ [ExpressionGroup.new(precompile_members, outer_template: outer_template, inner_template: inner_template)]
23
+ end
24
+
25
+ def compile
26
+ outer_template % (inner_template % members.map(&:compile).join)
27
+ end
28
+
29
+ private
30
+
31
+ def precompile_members
32
+ precompiled = compact(members.map(&:precompile).flatten)
33
+
34
+ transformed = precompiled.map do |node|
35
+ case node
36
+ when Raw
37
+ Raw.new(node.content, template: Raw::EXPR_STRING)
38
+ when ComponentElement
39
+ ComponentElement.new(node.name, node.members, node.children, template: ComponentElement::EXPR_STRING)
40
+ when ExpressionGroup
41
+ ExpressionGroup.new(node.members, outer_template: SUB_EXPR, inner_template: node.inner_template)
42
+ else
43
+ node
44
+ end
45
+ end.map_type_when_neighboring_type(ExpressionGroup, Raw) do |node|
46
+ ExpressionGroup.new(node.members, outer_template: SUB_EXPR_OUT, inner_template: node.inner_template)
47
+ end.insert_between_types(ExpressionGroup, Raw) do
48
+ Expression.new("+")
49
+ end.insert_between_types(ComponentElement, Raw) do
50
+ Expression.new("+")
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class HTMLAttr < AbstractAttr
4
+ def precompile
5
+ [
6
+ Raw.new(" #{name}=\""),
7
+ value.precompile,
8
+ Raw.new("\"")
9
+ ].flatten
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ module Rbexy
2
+ module Nodes
3
+ class HTMLElement < AbstractElement
4
+ KNOWN_VOID_ELEMENTS = ActionView::Helpers::TagHelper::TagBuilder::VOID_ELEMENTS.map(&:to_s).to_set
5
+
6
+ def precompile
7
+ nodes = []
8
+
9
+ if void? && children.length == 0
10
+ nodes.concat(precompile_open_tag)
11
+ else
12
+ nodes.concat(precompile_open_tag)
13
+ nodes.concat(children.map(&:precompile).flatten)
14
+ nodes << Raw.new("</#{name}>")
15
+ end
16
+
17
+ nodes
18
+ end
19
+
20
+ private
21
+
22
+ def void?
23
+ KNOWN_VOID_ELEMENTS.include?(name)
24
+ end
25
+
26
+ def precompile_open_tag
27
+ nodes = [Raw.new("<#{name}")]
28
+ nodes.concat(precompile_members)
29
+ nodes << Raw.new(">")
30
+ nodes
31
+ end
32
+
33
+ def precompile_members
34
+ members.map do |node|
35
+ if node.is_a? ExpressionGroup
36
+ ExpressionGroup.new(
37
+ node.members,
38
+ inner_template: "Rbexy::Runtime.splat_attrs(%s)",
39
+ outer_template: ExpressionGroup::OUTPUT_SAFE
40
+ )
41
+ else
42
+ node
43
+ end
44
+ end.map(&:precompile).flatten
45
+ end
46
+ end
47
+ end
48
+ end