rbexy 1.0.2 → 2.0.0.beta4

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -1
  3. data/README.md +18 -0
  4. data/lib/rbexy.rb +27 -9
  5. data/lib/rbexy/ast_transformer.rb +21 -0
  6. data/lib/rbexy/component.rb +10 -18
  7. data/lib/rbexy/component_context.rb +18 -0
  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/component_template_resolver.rb +3 -3
  29. data/lib/rbexy/rails/controller_helper.rb +5 -4
  30. data/lib/rbexy/rails/engine.rb +1 -11
  31. data/lib/rbexy/refinements.rb +5 -0
  32. data/lib/rbexy/refinements/array.rb +9 -0
  33. data/lib/rbexy/refinements/array/find_map.rb +13 -0
  34. data/lib/rbexy/refinements/array/insert_between_types.rb +26 -0
  35. data/lib/rbexy/refinements/array/map_type_when_neighboring_type.rb +26 -0
  36. data/lib/rbexy/runtime.rb +16 -23
  37. data/lib/rbexy/template.rb +12 -0
  38. data/lib/rbexy/version.rb +1 -1
  39. data/rbexy.gemspec +1 -0
  40. metadata +42 -11
  41. data/example.rb +0 -113
  42. data/lib/rbexy/component_providers/namespaced_rbexy_provider.rb +0 -20
  43. data/lib/rbexy/component_providers/rbexy_provider.rb +0 -21
  44. data/lib/rbexy/component_providers/view_component_provider.rb +0 -21
  45. data/lib/rbexy/component_tag_builder.rb +0 -19
  46. data/lib/rbexy/hash_mash.rb +0 -15
  47. data/lib/rbexy/view_context_helper.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8c0ebb095f668e7b85fbd14fe770be07fc9f42565b7f71a02e4001a5a0c88c6
4
- data.tar.gz: 4670b8929fba14f2cdb197eca4c9d72f37ecdef6d1e84d33d43f18bdb09b0a07
3
+ metadata.gz: d9cb20a821099f8fd51a0abb4b80ad3b2d8d936afcfe240a4b99ea29f4dea92a
4
+ data.tar.gz: aab32903c9632f245857c917b0b99743e5e58ddb8356fce1274c5dd2e4791b37
5
5
  SHA512:
6
- metadata.gz: 8e9920411ff9198828488d984cfd9e69c67e1ced6600a48d701c01153c4bc06419aaac58d2395ab61676798e9bb0a45137f40788d293fade0c0344c596e60c06
7
- data.tar.gz: 3da407f7258c3d2f2ef33a157747f6bf0f9ac945ebf801ec064430d80237f802ae7deac36de07a905b055dc9bd7f1958e80774a57f73d036a931a1c4cdac8b81
6
+ metadata.gz: a849303b1f41e2e6295558b09f1a608a3b24bca8317bde650c579c6a0da2206c67f1ea9bb49e4b7bf15e66497960fff70703845544a57271c4947e4abe16d5ef
7
+ data.tar.gz: 5f08d1838d39cf38d3f3d727e5c1ea098255e81e4a2ab4affd2b67a77a10d7f55dccdff52114f5ce9d544238d81d09a66f548ed74961298026f7887ad30339fd
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbexy (1.0.2)
4
+ rbexy (2.0.0.beta4)
5
5
  actionview (>= 6.0, < 7.0)
6
6
  activesupport (>= 6.0, < 7.0)
7
7
 
@@ -101,6 +101,7 @@ GEM
101
101
  mini_mime (>= 0.1.1)
102
102
  marcel (0.3.3)
103
103
  mimemagic (~> 0.3.2)
104
+ memory_profiler (0.9.14)
104
105
  method_source (1.0.0)
105
106
  mimemagic (0.3.5)
106
107
  mini_mime (1.0.2)
@@ -199,6 +200,7 @@ PLATFORMS
199
200
 
200
201
  DEPENDENCIES
201
202
  guard-rspec (~> 4.7, >= 4.7.3)
203
+ memory_profiler (~> 0.9.14)
202
204
  pry-byebug
203
205
  rails (>= 6.0, < 7.0)
204
206
  rake
data/README.md CHANGED
@@ -173,6 +173,14 @@ Loops:
173
173
  </ul>
174
174
  ```
175
175
 
176
+ Blocks:
177
+
178
+ ```jsx
179
+ {link_to "/" do
180
+ <span>Click me</span>
181
+ end}
182
+ ```
183
+
176
184
  As an attribute:
177
185
 
178
186
  ```jsx
@@ -189,6 +197,16 @@ Pass a lambda to a prop, that when called returns a tag:
189
197
  </Hero>
190
198
  ```
191
199
 
200
+ _Note that when using tags inside blocks, the block must evaluate to a single root element. Rbexy behaves similar to JSX in this way. E.g.:_
201
+
202
+ ```
203
+ # Do
204
+ -> { <span><i>Hello</i> World</span> }
205
+
206
+ # Don't
207
+ -> { <i>Hello</i> World }
208
+ ```
209
+
192
210
  ### Tags
193
211
 
194
212
  You can put standard HTML tags anywhere.
@@ -1,14 +1,22 @@
1
1
  require "rbexy/version"
2
+ require "active_support/inflector"
3
+ require "active_support/concern"
4
+ require "action_view/helpers/output_safety_helper"
5
+ require "action_view/helpers/capture_helper"
6
+ require "action_view/helpers/tag_helper"
7
+ require "action_view/context"
2
8
 
3
9
  module Rbexy
4
10
  autoload :Lexer, "rbexy/lexer"
5
11
  autoload :Parser, "rbexy/parser"
6
12
  autoload :Nodes, "rbexy/nodes"
7
13
  autoload :Runtime, "rbexy/runtime"
8
- autoload :HashMash, "rbexy/hash_mash"
9
- autoload :ComponentTagBuilder, "rbexy/component_tag_builder"
10
- autoload :ViewContextHelper, "rbexy/view_context_helper"
14
+ autoload :ComponentContext, "rbexy/component_context"
11
15
  autoload :Configuration, "rbexy/configuration"
16
+ autoload :ComponentResolver, "rbexy/component_resolver"
17
+ autoload :Template, "rbexy/template"
18
+ autoload :Refinements, "rbexy/refinements"
19
+ autoload :ASTTransformer, "rbexy/ast_transformer"
12
20
 
13
21
  ContextNotFound = Class.new(StandardError)
14
22
 
@@ -21,14 +29,24 @@ module Rbexy
21
29
  @configuration ||= Configuration.new
22
30
  end
23
31
 
24
- def compile(template_string)
25
- tokens = Rbexy::Lexer.new(template_string).tokenize
26
- template = Rbexy::Parser.new(tokens).parse
27
- template.compile
32
+ def compile(template, context = build_default_compile_context(template))
33
+ tokens = Lexer.new(template, context.element_resolver).tokenize
34
+ root = Parser.new(tokens).parse
35
+ root.inject_compile_context(context)
36
+ root.transform!
37
+ root.precompile.compile
28
38
  end
29
39
 
30
- def evaluate(template_string, runtime)
31
- runtime.evaluate compile(template_string)
40
+ def evaluate(template_string, runtime = Rbexy::Runtime.new)
41
+ runtime.evaluate compile(Template.new(template_string))
42
+ end
43
+
44
+ def build_default_compile_context(template)
45
+ OpenStruct.new(
46
+ template: template,
47
+ element_resolver: configuration.element_resolver,
48
+ ast_transformer: configuration.transforms
49
+ )
32
50
  end
33
51
  end
34
52
  end
@@ -0,0 +1,21 @@
1
+ module Rbexy
2
+ class ASTTransformer
3
+ attr_reader :registry
4
+
5
+ def initialize
6
+ clear!
7
+ end
8
+
9
+ def register(*node_classes, &block)
10
+ node_classes.each { |k| (registry[k] ||= []) << block }
11
+ end
12
+
13
+ def transform(node, context)
14
+ registry[node.class]&.each { |t| t.call(node, context) }
15
+ end
16
+
17
+ def clear!
18
+ @registry = {}
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,4 @@
1
1
  require "action_view"
2
- require "active_support/core_ext/class/attribute"
3
2
 
4
3
  module Rbexy
5
4
  class Component < ActionView::Base
@@ -28,7 +27,7 @@ module Rbexy
28
27
 
29
28
  @view_context = view_context
30
29
 
31
- setup(**props)
30
+ after_initialize(**props)
32
31
  end
33
32
 
34
33
  # Override in your subclass to handle props, setup your component, etc.
@@ -54,17 +53,6 @@ module Rbexy
54
53
  content_block ? content_block.call : ""
55
54
  end
56
55
 
57
- def create_context(name, value)
58
- rbexy_context.last[name] = value
59
- end
60
-
61
- def use_context(name)
62
- index = rbexy_context.rindex { |c| c.has_key?(name) }
63
- index ?
64
- rbexy_context[index][name] :
65
- raise(ContextNotFound, "no parent context `#{name}`")
66
- end
67
-
68
56
  def compiled_method_container
69
57
  Rbexy::Component
70
58
  end
@@ -74,16 +62,20 @@ module Rbexy
74
62
  attr_reader :view_context, :content_block
75
63
 
76
64
  def method_missing(meth, *args, &block)
77
- if view_context.respond_to?(meth)
78
- view_context.send(meth, *args, &block)
79
- else
80
- super
81
- end
65
+ view_context.send(meth, *args, &block)
66
+ end
67
+
68
+ def respond_to_missing?(method_name, include_all)
69
+ view_context.respond_to?(method_name, include_all)
82
70
  end
83
71
 
84
72
  def clean_template_backtrace(backtrace)
85
73
  return backtrace if Rbexy.configuration.debug
86
74
  BacktraceCleaner.new(backtrace).call
87
75
  end
76
+
77
+ def after_initialize(**props)
78
+ setup(**props)
79
+ end
88
80
  end
89
81
  end
@@ -0,0 +1,18 @@
1
+ module Rbexy
2
+ module ComponentContext
3
+ def rbexy_context
4
+ @rbexy_context ||= [{}]
5
+ end
6
+
7
+ def create_context(name, value)
8
+ rbexy_context.last[name] = value
9
+ end
10
+
11
+ def use_context(name)
12
+ index = rbexy_context.rindex { |c| c.has_key?(name) }
13
+ index ?
14
+ rbexy_context[index][name] :
15
+ raise(ContextNotFound, "no parent context `#{name}`")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ module Rbexy
2
+ class ComponentResolver
3
+ using Rbexy::Refinements::Array::FindMap
4
+
5
+ KNOWN_HTML_ELEMENTS = %w(
6
+ a abbr acronym address animate animateMotion animateTransform applet area article aside audio b base basefont
7
+ bdi bdo bgsound big blink blockquote body br button canvas caption center circle cite clipPath code col colgroup
8
+ color-profile command content data datalist dd defs del desc details dfn dialog dir discard div dl dt element
9
+ ellipse em embed feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting
10
+ feDisplacementMap feDistantLight feDropShadow feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage
11
+ feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence
12
+ fieldset figcaption figure filter font footer foreignObject form frame frameset g h1 h2 h3 h4 h5 h6 hatch
13
+ hatchpath head header hgroup hr html i iframe image img input ins isindex kbd keygen label legend li line
14
+ linearGradient link listing main map mark marker marquee mask menu menuitem mesh meshgradient meshpatch meshrow
15
+ meta metadata meter mpath multicol nav nextid nobr noembed noframes noscript object ol optgroup option output p
16
+ param path pattern picture plaintext polygon polyline pre progress q radialGradient rb rect rp rt rtc ruby s
17
+ samp script section select set shadow slot small solidcolor source spacer span stop strike strong style sub
18
+ summary sup svg switch symbol table tbody td template text textarea textPath tfoot th thead time title tr track
19
+ tspan tt u ul unknown use var video view wbr xmp
20
+ ).to_set
21
+
22
+ attr_reader :component_namespaces
23
+
24
+ def initialize
25
+ self.component_namespaces = {}
26
+ end
27
+
28
+ def component_namespaces=(hash)
29
+ @component_namespaces = hash.transform_keys(&:to_s)
30
+ end
31
+
32
+ def component?(name, template)
33
+ return false if KNOWN_HTML_ELEMENTS.include?(name)
34
+ return true if component_class(name, template)
35
+ false
36
+ end
37
+
38
+ def component_class(name, template)
39
+ possible_names = matching_namespaces(template).map { |ns| "#{ns}.#{name}" } << name
40
+ possible_names.find_map(&method(:find))
41
+ end
42
+
43
+ private
44
+
45
+ def find(name)
46
+ find!(name)
47
+ rescue NameError => e
48
+ raise e unless e.message =~ /wrong constant name/ || e.message =~ /uninitialized constant/
49
+ nil
50
+ end
51
+
52
+ def matching_namespaces(template)
53
+ component_namespaces.select { |path, ns| template.identifier.start_with?(path) }.values.flatten.uniq
54
+ end
55
+
56
+ def find!(name)
57
+ ActiveSupport::Inflector.constantize("#{name.gsub(".", "::")}Component")
58
+ end
59
+ end
60
+ end
@@ -1,12 +1,29 @@
1
1
  module Rbexy
2
2
  class Configuration
3
- attr_accessor :component_provider
3
+ attr_accessor :element_resolver
4
4
  attr_accessor :template_paths
5
5
  attr_accessor :enable_context
6
6
  attr_accessor :debug
7
+ attr_accessor :component_rendering_templates
8
+ attr_accessor :transforms
7
9
 
8
10
  def template_paths
9
11
  @template_paths ||= []
10
12
  end
13
+
14
+ def element_resolver
15
+ @element_resolver ||= ComponentResolver.new
16
+ end
17
+
18
+ def transforms
19
+ @transforms ||= ASTTransformer.new
20
+ end
21
+
22
+ def component_rendering_templates
23
+ @component_rendering_templates ||= {
24
+ children: "{capture{%{children}}}",
25
+ component: "::%{component_class}.new(%{view_context},%{kwargs}).render%{children_block}"
26
+ }
27
+ end
11
28
  end
12
29
  end
@@ -10,7 +10,7 @@ module Rbexy
10
10
  end
11
11
  end
12
12
 
13
- Patterns = HashMash.new(
13
+ Patterns = OpenStruct.new(
14
14
  open_expression: /{/,
15
15
  close_expression: /}/,
16
16
  expression_content: /[^}{"'<]+/,
@@ -29,23 +29,23 @@ module Rbexy
29
29
  single_quote: /'/,
30
30
  double_quoted_text_content: /[^"]+/,
31
31
  single_quoted_text_content: /[^']+/,
32
- expression_internal_tag_prefixes: /(\s+(&&|\?|:|do|do\s*\|[^\|]+\||{|{\s*\|[^\|]+\|)\s+\z|\A\s*\z)/,
32
+ expression_internal_tag_prefixes: /(\s+(&&|\|\||\?|:|do|do\s*\|[^\|]+\||{|{\s*\|[^\|]+\|)\s+\z|\A\s*\z)/,
33
33
  declaration: /<![^>]*>/
34
34
  )
35
35
 
36
- attr_reader :stack, :tokens, :scanner, :curr_expr_quote_levels
37
- attr_accessor :curr_expr_bracket_levels, :curr_expr, :curr_default_text,
36
+ attr_reader :stack, :tokens, :scanner, :element_resolver, :template
37
+ attr_accessor :curr_expr, :curr_default_text,
38
38
  :curr_quoted_text
39
39
 
40
- def initialize(code)
40
+ def initialize(template, element_resolver)
41
+ @template = template
42
+ @scanner = StringScanner.new(template.source)
43
+ @element_resolver = element_resolver
41
44
  @stack = [:default]
42
- @curr_expr_bracket_levels = 0
43
- @curr_expr_quote_levels = { single: 0, double: 0 }
44
45
  @curr_expr = ""
45
46
  @curr_default_text = ""
46
47
  @curr_quoted_text = ""
47
48
  @tokens = []
48
- @scanner = StringScanner.new(code)
49
49
  end
50
50
 
51
51
  def tokenize
@@ -59,7 +59,7 @@ module Rbexy
59
59
  elsif scanner.scan(Patterns.open_expression)
60
60
  open_expression
61
61
  elsif scanner.scan(Patterns.comment)
62
- tokens << [:SILENT_NEWLINE]
62
+ tokens << [:NEWLINE]
63
63
  elsif scanner.check(Patterns.text_content)
64
64
  stack.push(:default_text)
65
65
  else
@@ -74,7 +74,7 @@ module Rbexy
74
74
  elsif scanner.scan(Patterns.open_expression)
75
75
  open_expression
76
76
  elsif scanner.scan(Patterns.comment)
77
- tokens << [:SILENT_NEWLINE]
77
+ tokens << [:NEWLINE]
78
78
  elsif scanner.check(Patterns.text_content)
79
79
  stack.push(:default_text)
80
80
  else
@@ -163,9 +163,9 @@ module Rbexy
163
163
  tokens << [:CLOSE_TAG_DEF]
164
164
  stack.pop
165
165
  elsif scanner.scan(Patterns.tag_name)
166
- tokens << [:TAG_NAME, scanner.matched]
166
+ tokens << [:TAG_DETAILS, tag_details(scanner.matched)]
167
167
  elsif scanner.scan(Patterns.whitespace)
168
- scanner.matched.count("\n").times { tokens << [:SILENT_NEWLINE] }
168
+ scanner.matched.count("\n").times { tokens << [:NEWLINE] }
169
169
  tokens << [:OPEN_ATTRS]
170
170
  stack.push(:tag_attrs)
171
171
  else
@@ -182,7 +182,7 @@ module Rbexy
182
182
  end
183
183
  when :tag_attrs
184
184
  if scanner.scan(Patterns.whitespace)
185
- scanner.matched.count("\n").times { tokens << [:SILENT_NEWLINE] }
185
+ scanner.matched.count("\n").times { tokens << [:NEWLINE] }
186
186
  elsif scanner.check(Patterns.close_tag)
187
187
  tokens << [:CLOSE_ATTRS]
188
188
  stack.pop
@@ -205,7 +205,7 @@ module Rbexy
205
205
  open_expression
206
206
  elsif scanner.scan(Patterns.whitespace) || scanner.check(Patterns.close_tag)
207
207
  tokens << [:CLOSE_ATTR_VALUE]
208
- scanner.matched.count("\n").times { tokens << [:SILENT_NEWLINE] }
208
+ scanner.matched.count("\n").times { tokens << [:NEWLINE] }
209
209
  stack.pop
210
210
  else
211
211
  raise SyntaxError, self
@@ -286,5 +286,12 @@ module Rbexy
286
286
  # etc).
287
287
  scanner.scan(Patterns.expression_content) || scanner.scan(Patterns.open_tag_end)
288
288
  end
289
+
290
+ def tag_details(name)
291
+ type = element_resolver.component?(name, template) ? :component : :html
292
+ details = { name: scanner.matched, type: type }
293
+ details[:component_class] = element_resolver.component_class(name, template) if type == :component
294
+ details
295
+ end
289
296
  end
290
297
  end
@@ -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