heartml 1.0.0.beta3 → 1.0.0.beta5

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 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