moxml 0.5.98 → 0.5.99

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: 8c17ad7b7e8250a5f143af509bfe551cb5c29deb1a2ae7f5cc64f275d8d460df
4
- data.tar.gz: 9c6302666df0ca9a3761b2c072dc098ff3bc49a419b9cba404161e7d352bc70b
3
+ metadata.gz: e0799669e81215c8738217d5d9f75a5cc8842a9a35c92553d07f3f60ee6a8196
4
+ data.tar.gz: 86aeb7370ef541cc898fa1f3c9a63ba3da154a7ffb09a68d0236f82a1241fc10
5
5
  SHA512:
6
- metadata.gz: f47afe09d0f5cbe9016846c3ca7d8b43bd7f8f79b63b7dfdc51013578a71b82ef4b28701a7dea4be55edbb96e9a2f5cc011c7cc51a7029dcdcad557e542c8c37
7
- data.tar.gz: 1d7d971a95328b9397b71c49ff0c01df4af8ffc1e38c461a4801dd294993d58faa6eae05018000dd5c02e719a9162d25fcdf912b334409b2d3731f6fb67b36c5
6
+ metadata.gz: '0932b236b7f6e452705f49c6328848edd315774b35ae47d732a90fa65e5ed98612265765fab4c5bde3ca7eaad79b583457da72e051dbbac3d1df027986105435'
7
+ data.tar.gz: 1afbad96dc4a770d0b7c74a23fa55d6d80b2c80a3276bec9ae4b83d10cbda9cb59ae22649634ebfc4c6b49ab7715364396bf387236234372fc93212e4a3d0777
@@ -1774,6 +1774,31 @@ module Moxml
1774
1774
  child_native
1775
1775
  end
1776
1776
 
1777
+ # moxml#304: a cross-document attach makes the target's tree
1778
+ # point into the child's owning document; when that document is
1779
+ # collected its arena dies and the subtree vanishes (empty
1780
+ # output, nameless element pairs — silent, GC-dependent). Pin
1781
+ # the owning document on the target's document so the arena
1782
+ # outlives every attached subtree.
1783
+ def pin_foreign_owner_document(parent, child)
1784
+ return unless child.is_a?(NN) || child.is_a?(::Leptris::XML::Node)
1785
+
1786
+ # Two document fetches + identity compare on the same-document
1787
+ # hot path (every builder add_child); the WeakMap bridge and
1788
+ # the pin only pay when the child actually comes from another
1789
+ # document.
1790
+ child_doc = child.is_a?(NN) ? NN_DOCUMENT.bind_call(child) : child.document
1791
+ return if child_doc.nil?
1792
+
1793
+ parent_doc = parent.is_a?(NN) ? NN_DOCUMENT.bind_call(parent) : parent.document
1794
+ return if parent_doc.nil? || child_doc.equal?(parent_doc)
1795
+
1796
+ owner = child_doc.is_a?(NN) ? to_binding(child_doc) : child_doc
1797
+ docs = attachments.get(parent_doc, :adopted_docs) || []
1798
+ docs << owner
1799
+ attachments.set(parent_doc, :adopted_docs, docs)
1800
+ end
1801
+
1777
1802
  def add_child(parent, child)
1778
1803
  if NATIVE_READ_LAYER && !(NATIVE_MUTATIONS_COHERENT &&
1779
1804
  parent.is_a?(::Leptris::XML::NativeNode) &&
@@ -1781,6 +1806,7 @@ module Moxml
1781
1806
  parent = to_binding(parent)
1782
1807
  child = to_binding(child)
1783
1808
  end
1809
+ pin_foreign_owner_document(parent, child)
1784
1810
  case parent
1785
1811
  when ::Leptris::XML::Document then add_document_child(parent, child)
1786
1812
  else
data/lib/moxml/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Moxml
4
- VERSION = "0.5.98"
4
+ VERSION = "0.5.99"
5
5
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # moxml#304: cross-document append_xml / add_child silently lost
6
+ # appended subtrees under GC pressure on MRI < 3.4 — the wrapper
7
+ # registry's WeakMap loses/mangles entries during incremental GC
8
+ # marking (moxml#303's root cause) while the appended fragment's
9
+ # natives are only weakly held; the references then read freed
10
+ # natives ("<sections></sections>", nameless element pairs).
11
+ # The strong-registry fallback (WEAK_WRAPPERS=false on MRI < 3.4)
12
+ # resolves it; this pins the shape.
13
+ RSpec.describe "leptris cross-document append under GC pressure" do
14
+ let(:ctx) { Moxml.new(:leptris) }
15
+ let(:frags) do
16
+ [
17
+ '<clause id="a"><p>one</p></clause>',
18
+ '<annex id="b"><p>two &amp; more</p><fn ref="1"/><!-- c --></annex>',
19
+ '<p standalone="x" y="1"/>',
20
+ ]
21
+ end
22
+
23
+ it "keeps appended subtrees across collections" do
24
+ 8.times do
25
+ root = ctx.parse("<sections/>").root
26
+ frags.each do |frag|
27
+ root.append_xml(frag)
28
+ GC.start(full_mark: true, immediate_sweep: true)
29
+ end
30
+ out = root.to_xml(indent: 0)
31
+ expect(out).to include("<clause")
32
+ expect(out).to include("<annex")
33
+ expect(out).to include("standalone")
34
+ expect(out).not_to include("<></>")
35
+ end
36
+ end
37
+
38
+ it "keeps parse_fragment nodes across collections" do
39
+ built = ctx.parse("<sections/>")
40
+ 4.times do
41
+ frags.each do |frag|
42
+ ctx.parse_fragment(frag).each do |node|
43
+ built.root.add_child(node)
44
+ GC.start(full_mark: true, immediate_sweep: true)
45
+ end
46
+ end
47
+ out = built.root.to_xml(indent: 0)
48
+ expect(out).to include("<clause")
49
+ expect(out).to include("<annex")
50
+ end
51
+ end
52
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moxml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.98
4
+ version: 0.5.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -440,6 +440,7 @@ files:
440
440
  - spec/moxml/adapter/base_spec.rb
441
441
  - spec/moxml/adapter/entity_restoration_spec.rb
442
442
  - spec/moxml/adapter/headed_ox_spec.rb
443
+ - spec/moxml/adapter/leptris_append_gc_spec.rb
443
444
  - spec/moxml/adapter/leptris_doc_parts_spec.rb
444
445
  - spec/moxml/adapter/leptris_parse_skips_spec.rb
445
446
  - spec/moxml/adapter/leptris_record_driver_spec.rb