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.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -5
- data/README.md +20 -0
- data/lib/rbexy.rb +27 -10
- data/lib/rbexy/ast_transformer.rb +21 -0
- data/lib/rbexy/component.rb +12 -18
- data/lib/rbexy/component/backtrace_cleaner.rb +59 -0
- data/lib/rbexy/component_context.rb +18 -0
- data/lib/rbexy/component_resolver.rb +60 -0
- data/lib/rbexy/configuration.rb +19 -1
- data/lib/rbexy/lexer.rb +20 -14
- data/lib/rbexy/nodes.rb +15 -141
- data/lib/rbexy/nodes/abstract_attr.rb +12 -0
- data/lib/rbexy/nodes/abstract_element.rb +13 -0
- data/lib/rbexy/nodes/abstract_node.rb +58 -0
- data/lib/rbexy/nodes/component_element.rb +69 -0
- data/lib/rbexy/nodes/component_prop.rb +29 -0
- data/lib/rbexy/nodes/declaration.rb +15 -0
- data/lib/rbexy/nodes/expression.rb +15 -0
- data/lib/rbexy/nodes/expression_group.rb +55 -0
- data/lib/rbexy/nodes/html_attr.rb +13 -0
- data/lib/rbexy/nodes/html_element.rb +48 -0
- data/lib/rbexy/nodes/newline.rb +9 -0
- data/lib/rbexy/nodes/raw.rb +23 -0
- data/lib/rbexy/nodes/root.rb +19 -0
- data/lib/rbexy/nodes/text.rb +15 -0
- data/lib/rbexy/nodes/util.rb +9 -0
- data/lib/rbexy/parser.rb +22 -16
- data/lib/rbexy/rails/component_template_resolver.rb +3 -3
- data/lib/rbexy/rails/controller_helper.rb +5 -4
- data/lib/rbexy/rails/engine.rb +1 -11
- data/lib/rbexy/refinements.rb +5 -0
- data/lib/rbexy/refinements/array.rb +9 -0
- data/lib/rbexy/refinements/array/find_map.rb +13 -0
- data/lib/rbexy/refinements/array/insert_between_types.rb +26 -0
- data/lib/rbexy/refinements/array/map_type_when_neighboring_type.rb +26 -0
- data/lib/rbexy/runtime.rb +17 -23
- data/lib/rbexy/template.rb +12 -0
- data/lib/rbexy/version.rb +1 -1
- data/rbexy.gemspec +4 -4
- metadata +49 -38
- data/example.rb +0 -113
- data/lib/rbexy/component_providers/namespaced_rbexy_provider.rb +0 -20
- data/lib/rbexy/component_providers/rbexy_provider.rb +0 -21
- data/lib/rbexy/component_providers/view_component_provider.rb +0 -21
- data/lib/rbexy/component_tag_builder.rb +0 -19
- data/lib/rbexy/hash_mash.rb +0 -15
- data/lib/rbexy/output_buffer.rb +0 -10
- data/lib/rbexy/view_context_helper.rb +0 -11
data/lib/rbexy/nodes.rb
CHANGED
@@ -1,145 +1,19 @@
|
|
1
1
|
module Rbexy
|
2
2
|
module Nodes
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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,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,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
|