rbexy 0.3.1 → 2.0.0.beta1

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 +6 -5
  3. data/README.md +20 -0
  4. data/lib/rbexy.rb +27 -10
  5. data/lib/rbexy/ast_transformer.rb +21 -0
  6. data/lib/rbexy/component.rb +12 -18
  7. data/lib/rbexy/component/backtrace_cleaner.rb +59 -0
  8. data/lib/rbexy/component_context.rb +18 -0
  9. data/lib/rbexy/component_resolver.rb +60 -0
  10. data/lib/rbexy/configuration.rb +19 -1
  11. data/lib/rbexy/lexer.rb +20 -14
  12. data/lib/rbexy/nodes.rb +15 -141
  13. data/lib/rbexy/nodes/abstract_attr.rb +12 -0
  14. data/lib/rbexy/nodes/abstract_element.rb +13 -0
  15. data/lib/rbexy/nodes/abstract_node.rb +58 -0
  16. data/lib/rbexy/nodes/component_element.rb +69 -0
  17. data/lib/rbexy/nodes/component_prop.rb +29 -0
  18. data/lib/rbexy/nodes/declaration.rb +15 -0
  19. data/lib/rbexy/nodes/expression.rb +15 -0
  20. data/lib/rbexy/nodes/expression_group.rb +55 -0
  21. data/lib/rbexy/nodes/html_attr.rb +13 -0
  22. data/lib/rbexy/nodes/html_element.rb +48 -0
  23. data/lib/rbexy/nodes/newline.rb +9 -0
  24. data/lib/rbexy/nodes/raw.rb +23 -0
  25. data/lib/rbexy/nodes/root.rb +19 -0
  26. data/lib/rbexy/nodes/text.rb +15 -0
  27. data/lib/rbexy/nodes/util.rb +9 -0
  28. data/lib/rbexy/parser.rb +22 -16
  29. data/lib/rbexy/rails/component_template_resolver.rb +3 -3
  30. data/lib/rbexy/rails/controller_helper.rb +5 -4
  31. data/lib/rbexy/rails/engine.rb +1 -11
  32. data/lib/rbexy/refinements.rb +5 -0
  33. data/lib/rbexy/refinements/array.rb +9 -0
  34. data/lib/rbexy/refinements/array/find_map.rb +13 -0
  35. data/lib/rbexy/refinements/array/insert_between_types.rb +26 -0
  36. data/lib/rbexy/refinements/array/map_type_when_neighboring_type.rb +26 -0
  37. data/lib/rbexy/runtime.rb +17 -23
  38. data/lib/rbexy/template.rb +12 -0
  39. data/lib/rbexy/version.rb +1 -1
  40. data/rbexy.gemspec +4 -4
  41. metadata +49 -38
  42. data/example.rb +0 -113
  43. data/lib/rbexy/component_providers/namespaced_rbexy_provider.rb +0 -20
  44. data/lib/rbexy/component_providers/rbexy_provider.rb +0 -21
  45. data/lib/rbexy/component_providers/view_component_provider.rb +0 -21
  46. data/lib/rbexy/component_tag_builder.rb +0 -19
  47. data/lib/rbexy/hash_mash.rb +0 -15
  48. data/lib/rbexy/output_buffer.rb +0 -10
  49. data/lib/rbexy/view_context_helper.rb +0 -11
@@ -1,145 +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
- [
22
- "Rbexy::OutputBuffer.new.tap { |output|",
23
- children.map(&:compile).map { |c| "output << (#{c})"}.join(";"),
24
- "}.html_safe"
25
- ].join(" ")
26
- end
27
- end
28
-
29
- class Text
30
- attr_reader :content
31
-
32
- def initialize(content)
33
- @content = content
34
- end
35
-
36
- def compile
37
- "\"#{Util.safe_string(content)}\""
38
- end
39
- end
40
-
41
- class ExpressionGroup
42
- attr_reader :statements
43
-
44
- def initialize(statements)
45
- @statements = statements
46
- end
47
-
48
- def compile
49
- statements.map(&:compile).join
50
- end
51
- end
52
-
53
- class Expression
54
- attr_reader :content
55
-
56
- def initialize(content)
57
- @content = content
58
- end
59
-
60
- def compile
61
- content
62
- end
63
- end
64
-
65
- class XmlNode
66
- attr_reader :name, :members, :children
67
-
68
- def initialize(name, members, children)
69
- @name = name
70
- @members = members || []
71
- @children = children
72
- end
73
-
74
- def compile
75
- base_tag = "rbexy_tag.#{Util.safe_tag_name(name)}(#{compile_members})"
76
- tag = if children.length > 0
77
- [
78
- "#{base_tag} {",
79
- "Rbexy::OutputBuffer.new.tap { |output|",
80
- children.map(&:compile).map { |c| "output << (#{c})"}.join(";"),
81
- "}.html_safe",
82
- "}"
83
- ].join(" ")
84
- else
85
- base_tag
86
- end
87
-
88
- context_open = Rbexy.configuration.enable_context ? "rbexy_context.push({});" : nil
89
- context_close = Rbexy.configuration.enable_context ? "rbexy_context.pop;" : nil
90
-
91
- [
92
- "Rbexy::OutputBuffer.new.tap { |output|",
93
- context_open,
94
- "output << (#{tag}).html_safe;",
95
- context_close,
96
- "}.html_safe"
97
- ].join(" ")
98
- end
99
-
100
- def compile_members
101
- members.each_with_object("") do |member, result|
102
- case member
103
- when ExpressionGroup
104
- result << "**#{member.compile},"
105
- when SilentNewline
106
- result << member.compile
107
- else
108
- result << "#{member.compile},"
109
- end
110
- end
111
- end
112
- end
113
-
114
- class XmlAttr
115
- attr_reader :name, :value
116
-
117
- def initialize(name, value)
118
- @name = name
119
- @value = value
120
- end
121
-
122
- def compile
123
- "\"#{name}\": #{value.compile}"
124
- end
125
- end
126
-
127
- class SilentNewline
128
- def compile
129
- "\n"
130
- end
131
- end
132
-
133
- class Declaration
134
- attr_reader :content
135
-
136
- def initialize(content)
137
- @content = content
138
- end
139
-
140
- def compile
141
- "\"#{Util.safe_string(content)}\".html_safe"
142
- end
143
- 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"
144
18
  end
145
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},"
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