rbexy 0.3.1 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|