heartml 1.0.0.beta3 → 1.0.0.beta5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af1df02bbfde39341b4b9a7df922718be4461b749195d341dece40c6f96a82f5
4
- data.tar.gz: c379e7456d7c04d187465a36b8b526a5b1c9668576c1f7e9970f43c6a7f3729a
3
+ metadata.gz: 053e789d42574715a2f4269205a6dfe549a3d4af6970a6f6446b51735a9be340
4
+ data.tar.gz: cfe795359ca2e951218853f336057d4751bac7e04564bc857808573c3f2e045a
5
5
  SHA512:
6
- metadata.gz: 9e7e19aabcec51daeaa138e9601ce5298d41c36326654b3f2362aa6976c74e26bf6376b9e8d0a3cb27db98ea611db07cb3ae80690a2a4f246c97f45d28869113
7
- data.tar.gz: af65f1e24ba4eac17f6bf91e521edc141e2d2b856a1702d44203071dd6f06dbf857591481da95d9ca7f11e9b1154ede933a5275a7a1658efe0c71554ba8b5c53
6
+ metadata.gz: 36c6248a2b135f2d11b20b054d2a6bf8334460d56fe184a6c4d646e92561c2210e1e3a707975930613ed86091812708888b14d1fbd46f5efefe3befe3aeb3558
7
+ data.tar.gz: a4241d8e092361148f6ce228c0023007c7e97e650ab4c4336ea12b1f61287f1c1b034eff06f97f6718ae1c400fb82f252197de9205bdd7057058ad382cb56ce6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.0.beta5] - 2023-09-04
4
+
5
+ - Fix issue with ViewComponent in Rails apps
6
+ - Add fragment error handling
7
+
8
+ ## [1.0.0.beta4] - 2023-08-27
9
+
10
+ - Refactor and improve Bridgetown plugin and simplify context handling for template rendering
11
+
3
12
  ## [1.0.0.beta3] - 2023-08-12
4
13
 
5
14
  - Ensure attributes are processed on component node before it's rendered as component
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- heartml (1.0.0.beta3)
4
+ heartml (1.0.0.beta5)
5
5
  concurrent-ruby (~> 1.2)
6
6
  nokolexbor (>= 0.4.2)
7
7
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Heartml
4
+ class BridgetownRenderer < Bridgetown::Builder
5
+ def build
6
+ render_heart_modules
7
+ end
8
+
9
+ def render_heart_modules
10
+ inspect_html do |doc, resource|
11
+ view_context = Bridgetown::ERBView.new(resource)
12
+
13
+ rdr = Heartml::TemplateRenderer.new(body: doc.at_css("body"), context: view_context)
14
+ # rdr.define_singleton_method(:view_context) { view_context }
15
+ rdr.call
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Bridgetown.initializer :heartml do |config|
22
+ Bridgetown::Component.extend ActiveSupport::DescendantsTracker
23
+
24
+ Heartml.module_eval do
25
+ def render_in(view_context, rendering_mode: :string, &block)
26
+ self.rendering_mode = rendering_mode
27
+ super(view_context, &block)
28
+ end
29
+ end
30
+
31
+ # Eager load all components
32
+ config.hook :site, :after_reset do |site|
33
+ unless site.config.eager_load_paths.find { _1.end_with?(site.config.components_dir) }
34
+ site.config.eager_load_paths << site.config.autoload_paths.find { _1.end_with?(site.config.components_dir) }
35
+ end
36
+ end
37
+
38
+ config.html_inspector_parser "nokolexbor"
39
+ config.builder Heartml::BridgetownRenderer
40
+ end
@@ -38,21 +38,25 @@ module Heartml
38
38
 
39
39
  params.each do |param|
40
40
  new_key, v2 = param.split(":").map(&:strip)
41
+ v2 ||= new_key
42
+
41
43
  new_attrs[new_key] = @component.evaluate_attribute_expression(attr, v2)
42
44
  end
43
45
  attrs.delete(k)
44
46
  end
45
47
  attrs.merge!(new_attrs)
46
48
  attrs.reject! { |k| k.start_with?("server-") || k.start_with?("iso-") || k.start_with?("host-") }
47
- attrs.transform_keys!(&:to_sym)
49
+ attrs.transform_keys! { _1.tr("-", "_").to_sym }
48
50
 
49
51
  obj = component.new(**attrs)
50
52
  render_output = if obj.respond_to?(:render_in)
51
- obj.render_in(@component.view_context, rendering_mode: :node) do
53
+ obj.render_in(@component.context, rendering_mode: :node) do
52
54
  process(fragamatize(node.children))
53
55
  end
54
56
  else
55
- obj.render_element(content: process(fragamatize(node.children)))
57
+ obj.render_element(
58
+ content: process(fragamatize(node.children)), context: @component.context
59
+ )
56
60
  end
57
61
 
58
62
  node.replace(render_output)
@@ -78,7 +82,7 @@ module Heartml
78
82
  break unless attribute_binding.method.(attribute: attr_node, node: node)
79
83
  end
80
84
  rescue Exception => e # rubocop:disable Lint/RescueException
81
- line_segments = [@component.class.heart_module, @component.class.line_number_of_node(attr_node)]
85
+ line_segments = [@component.class.heart_module, @component._line_number_of_node(attr_node)]
82
86
  raise e.class, e.message.lines.first, [line_segments.join(":"), *e.backtrace]
83
87
  end
84
88
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Heartml
4
4
  # @return [String]
5
- VERSION = "1.0.0.beta3"
5
+ VERSION = "1.0.0.beta5"
6
6
  end
data/lib/heartml.rb CHANGED
@@ -54,9 +54,13 @@ module Heartml
54
54
  klass.attribute_binding "server-unsafe-eval", :_server_replace_binding
55
55
 
56
56
  # Don't stomp on a superclass's `content` method
57
- return if klass.instance_methods.include?(:content)
57
+ has_content_method = begin
58
+ klass.instance_method(:content)
59
+ rescue NameError
60
+ false
61
+ end
58
62
 
59
- klass.include ContentMethod
63
+ klass.include ContentMethod unless has_content_method
60
64
  end
61
65
 
62
66
  # Extends the component class
@@ -124,10 +128,8 @@ module Heartml
124
128
  end
125
129
  end
126
130
 
127
- def line_number_of_node(node)
128
- loc = node.source_location
129
- instance_variable_get(:@doc_html)[0..loc].count("\n") + 1
130
- end
131
+ # @return [String]
132
+ def doc_html = @doc_html
131
133
 
132
134
  def attribute_bindings = @attribute_bindings ||= []
133
135
 
@@ -149,6 +151,14 @@ module Heartml
149
151
  @_replaced_content = new_content
150
152
  end
151
153
 
154
+ def context
155
+ return @context if @context
156
+
157
+ return unless respond_to?(:view_context)
158
+
159
+ view_context # compatibility with other Ruby component systems
160
+ end
161
+
152
162
  # Override in component
153
163
  #
154
164
  # @return [Hash]
@@ -165,9 +175,11 @@ module Heartml
165
175
 
166
176
  # @param attributes [Hash]
167
177
  # @param content [String, Nokolexbor::Element]
168
- def render_element(attributes: self.attributes, content: self.content) # rubocop:disable Metrics
178
+ def render_element(attributes: self.attributes, content: self.content, context: self.context) # rubocop:disable Metrics
169
179
  doc = self.class.doc.clone
180
+ @doc_html ||= self.class.doc_html # keep a spare copy for determining error line number
170
181
  @_content = content
182
+ @context = context
171
183
 
172
184
  tmpl_el = doc.css("> template").find do |node|
173
185
  node.attributes.empty? ||
@@ -184,33 +196,6 @@ module Heartml
184
196
  # Process all the template bits
185
197
  process_fragment(tmpl_el)
186
198
 
187
- # Heartml.registered_elements.each do |component|
188
- # tmpl_el.children[0].css(component.tag_name).reverse.each do |node|
189
- # if node["server-ignore"]
190
- # node.remove_attribute("server-ignore")
191
- # next
192
- # end
193
-
194
- # attrs = node.attributes.transform_values(&:value)
195
- # attrs.reject! { |k| k.start_with?("server-") }
196
- # new_attrs = {}
197
- # attrs.each do |k, v|
198
- # next unless k.start_with?("arg:")
199
-
200
- # new_key = k.delete_prefix("arg:")
201
- # attrs.delete(k)
202
- # new_attrs[new_key] = instance_eval(v, self.class.heart_module, self.class.line_number_of_node(node))
203
- # end
204
- # attrs.merge!(new_attrs)
205
- # attrs.transform_keys!(&:to_sym)
206
-
207
- # new_node = node.replace(
208
- # component.new(**attrs).render_element(content: node.children)
209
- # )
210
- # new_node.remove_attribute("server-ignore")
211
- # end
212
- # end
213
-
214
199
  # Set attributes on the custom element
215
200
  attributes.each { |k, v| doc[k.to_s.tr("_", "-")] = value_to_attribute(v) if v }
216
201
 
@@ -323,7 +308,7 @@ module Heartml
323
308
  _context_locals.keys.reverse_each do |name|
324
309
  eval_code = "#{name} = _context_locals[\"#{name}\"];" + eval_code
325
310
  end
326
- instance_eval(eval_code, self.class.heart_module, self.class.line_number_of_node(attribute))
311
+ instance_eval(eval_code, self.class.heart_module, _line_number_of_node(attribute))
327
312
  end
328
313
 
329
314
  def class_list_for(obj)
@@ -338,6 +323,11 @@ module Heartml
338
323
  end.join(" ")
339
324
  end
340
325
 
326
+ def _line_number_of_node(node)
327
+ loc = node.source_location
328
+ instance_variable_get(:@doc_html)[0..loc].count("\n") + 1
329
+ end
330
+
341
331
  def _context_nodes = @_context_nodes ||= []
342
332
 
343
333
  def _context_locals = @_context_locals ||= {}
@@ -381,26 +371,6 @@ module Heartml
381
371
  end
382
372
  end
383
373
 
384
- # def _server_replace_binding(attribute:, node:)
385
- # if node.name == "template"
386
- # node.children[0].inner_html = node_or_string(evaluate_attribute_expression(attribute))
387
- # node.replace(node.children[0].children)
388
- # else
389
- # node.inner_html = node_or_string(evaluate_attribute_expression(attribute))
390
- # node.replace(node.children)
391
- # end
392
- # end
393
-
394
- # def _server_expr_binding(attribute:, node:)
395
- # if attribute.name.end_with?(":text")
396
- # node.content = node_or_string(evaluate_attribute_expression(attribute))
397
- # attribute.parent.delete(attribute.name)
398
- # elsif attribute.name.end_with?(":html")
399
- # node.inner_html = node_or_string(evaluate_attribute_expression(attribute))
400
- # attribute.parent.delete(attribute.name)
401
- # end
402
- # end
403
-
404
374
  class ServerComponent
405
375
  def self.inherited(klass)
406
376
  super
@@ -409,19 +379,15 @@ module Heartml
409
379
  end
410
380
  end
411
381
 
412
- class FragmentRenderComponent < ServerComponent
382
+ class TemplateRenderer < ServerComponent
413
383
  def self.heart_module
414
384
  "eval"
415
385
  end
416
386
 
417
- def self.line_number_of_node(_node)
418
- # FIXME: this should actually work!
419
- 0
420
- end
421
-
422
- def initialize(body:, scope:) # rubocop:disable Lint/MissingSuper
387
+ def initialize(body:, context:) # rubocop:disable Lint/MissingSuper
388
+ @doc_html = body.is_a?(String) ? body : body.to_html
423
389
  @body = body.is_a?(String) ? Nokolexbor::DocumentFragment.parse(body) : body
424
- @scope = scope
390
+ @context = context
425
391
  end
426
392
 
427
393
  def call
@@ -430,36 +396,14 @@ module Heartml
430
396
  end
431
397
 
432
398
  def respond_to_missing?(key)
433
- @scope.respond_to?(key)
399
+ context.respond_to?(key)
434
400
  end
435
401
 
436
402
  # TODO: delegate instead?
437
403
  def method_missing(key, *args, **kwargs)
438
- @scope.send(key, *args, **kwargs)
404
+ context.send(key, *args, **kwargs)
439
405
  end
440
406
  end
441
407
  end
442
408
 
443
- if defined?(Bridgetown)
444
- Bridgetown.initializer :heartml do |config|
445
- Bridgetown::Component.extend ActiveSupport::DescendantsTracker
446
-
447
- Heartml.module_eval do
448
- def render_in(view_context, rendering_mode = :string, &block)
449
- self.rendering_mode = rendering_mode
450
- super(view_context, &block)
451
- end
452
- end
453
-
454
- # Eager load all components
455
- config.hook :site, :after_reset do |site|
456
- unless site.config.eager_load_paths.find { _1.end_with?(site.config.components_dir) }
457
- site.config.eager_load_paths << site.config.autoload_paths.find { _1.end_with?(site.config.components_dir) }
458
- end
459
- end
460
-
461
- config.html_inspector_parser "nokolexbor"
462
- require_relative "heartml/component_renderer"
463
- config.builder Heartml::ComponentRenderer
464
- end
465
- end
409
+ require_relative "heartml/bridgetown_renderer" if defined?(Bridgetown)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heartml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta3
4
+ version: 1.0.0.beta5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared White
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-13 00:00:00.000000000 Z
11
+ date: 2023-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -70,7 +70,7 @@ files:
70
70
  - benchmark.rb
71
71
  - heartml.gemspec
72
72
  - lib/heartml.rb
73
- - lib/heartml/component_renderer.rb
73
+ - lib/heartml/bridgetown_renderer.rb
74
74
  - lib/heartml/fragment.rb
75
75
  - lib/heartml/petite.rb
76
76
  - lib/heartml/query_selection.rb
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Heartml
4
- class ComponentRenderer < Bridgetown::Builder
5
- def build
6
- render_heart_modules
7
- end
8
-
9
- # TODO: rework this using new server effects and component context!
10
- def render_heart_modules
11
- inspect_html do |doc, resource|
12
- view_context = Bridgetown::ERBView.new(resource)
13
-
14
- rdr = FragmentRenderComponent.new(body: doc.at_css("body"), scope: view_context)
15
- rdr.define_singleton_method(:view_context) { view_context }
16
- rdr.call
17
-
18
- # Heartml.registered_elements.each do |component|
19
- # tag_name = component.tag_name
20
- # doc.xpath("//#{tag_name}").reverse.each do |node|
21
- # if node["server-ignore"]
22
- # node.remove_attribute("server-ignore")
23
- # next
24
- # end
25
-
26
- # attrs = node.attributes.transform_values(&:value)
27
- # attrs.reject! { |k| k.start_with?("server-") }
28
-
29
- # new_attrs = {}
30
- # attrs.each do |k, v|
31
- # next unless k.start_with?("arg:")
32
-
33
- # new_key = k.delete_prefix("arg:")
34
- # attrs.delete(k)
35
- # new_attrs[new_key] = resource.instance_eval(v)
36
- # end
37
- # attrs.merge!(new_attrs)
38
- # attrs.transform_keys!(&:to_sym)
39
-
40
- # new_node = node.replace(
41
- # component.new(**attrs).render_in(view_context, rendering_mode: :node) { node.children }
42
- # )
43
- # new_node.remove_attribute("server-ignore")
44
- # end
45
- # rescue StandardError => e
46
- # Bridgetown.logger.error "Unable to render <#{tag_name}> (#{component}) in #{resource.path}"
47
- # raise e
48
- # end
49
- end
50
- end
51
- end
52
- end