moxml 0.5.105 → 0.5.106

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: 0c57aa62d4c524daa9096eb565711a4ebbed7525ba851cb6e327c98de842c4e4
4
- data.tar.gz: 604a922868c9ba3fb656c41e84e7b2f848bdd20defcd5259d697da32e2fd7e0e
3
+ metadata.gz: 28a815d79bd0bc2f356a01f0a4f5337e111ab6bce63f7e8c2f7247efac096b4c
4
+ data.tar.gz: b0a75eb438464fe9327fdb0420f14be0e8b19fea4252fe8abc995e295a6c6449
5
5
  SHA512:
6
- metadata.gz: 80f4dc813942807549d58b93492e731dceeb3528e7cfcfd3f3a3d4c5fbd1a2c4d5b234cbc1cad9b8945efc1c280e4408b373ac8d0bf2e489051277b98716fc82
7
- data.tar.gz: c91474a18a6877d6c0a012765f27c37c2ccd42260c810b130d62c3d69a6f55f2e08019a6472bb6f1b5d1f8649f99c3747f0139c72a80a606322850e56a98f134
6
+ metadata.gz: 33363ebc463f8e46fbd955ad3adb8f43b01775c27cc72ddaf356e62761e9a7b1917c1c15de36716806a1c306c111368fa0705ec1e37a11fd386f6183c274f291
7
+ data.tar.gz: aef109c340cdcb4f30a76f87ef05e2568091e01c3dcf815fa2c945ff1cc49a961a0c36e1541f32873cca0226af2bd43a019c7cdac0c5f89b195558c2090a621a
@@ -175,6 +175,14 @@ module Moxml
175
175
  node
176
176
  end
177
177
 
178
+ # Cross-document root adoption: adapters whose engine deep-copies
179
+ # a foreign root into the target document natively answer the
180
+ # installed native here (leptris >= 1.9.292, engine #1495);
181
+ # nil keeps the Ruby splice.
182
+ def adopt_root(_doc, _element)
183
+ nil
184
+ end
185
+
178
186
  # Element-only children: adapters whose engine carries the
179
187
  # face override (leptris C filter, nokogiri native); the
180
188
  # default type-filters the native child list so non-element
@@ -1437,6 +1437,23 @@ module Moxml
1437
1437
  end
1438
1438
  end
1439
1439
 
1440
+ NATIVE_ROOT_ADOPT =
1441
+ NATIVE_READ_LAYER &&
1442
+ Gem::Version.new(::Leptris::VERSION) >= Gem::Version.new("1.9.292.0")
1443
+
1444
+ # The engine deep-copies the foreign subtree into the target
1445
+ # document's pool (leptris#1495) and the binding memoizes the
1446
+ # INSTALLED handle — a fresh pointer distinct from the consumed
1447
+ # source. Answer the installed binding element; callers re-point
1448
+ # wrappers at it.
1449
+ def adopt_root(doc, element)
1450
+ return nil unless NATIVE_ROOT_ADOPT
1451
+
1452
+ binding_doc = to_binding(doc)
1453
+ binding_doc.root = to_binding(element)
1454
+ binding_doc.root
1455
+ end
1456
+
1440
1457
  # Element-only children through the engine-level filter: the
1441
1458
  # C face mints element-kind natives directly (klass-children),
1442
1459
  # so interleaved text/comment nodes cost nothing. Entity
@@ -29,6 +29,21 @@ module Moxml
29
29
  (owner.is_a?(Document) && owner.root.equal?(element))
30
30
  if owner.is_a?(Document) && attached &&
31
31
  !owner.equal?(self) && element.context.equal?(context)
32
+ installed = adapter.adopt_root(@native, element.native)
33
+ if installed
34
+ # The engine deep-copies the foreign subtree into this
35
+ # document's pool (leptris >= 1.9.292, engine #1495) and the
36
+ # binding memoizes the INSTALLED handle — a fresh pointer.
37
+ # Re-point the source wrapper so later writes reach the live
38
+ # tree, and recompute its scope-derived memos.
39
+ unless installed.equal?(element.native)
40
+ element.refresh_native!(Moxml::Node.wrap(installed, context).native)
41
+ element.invalidate_namespace_cache!
42
+ end
43
+ context.bump_children_generation
44
+ invalidate_children_cache!
45
+ return
46
+ end
32
47
  # libleptris refuses a root owned by another document (the
33
48
  # engine's set_root ownership check), while Nokogiri adopts.
34
49
  # Cross-document CHILD attaches are supported, so build the
data/lib/moxml/element.rb CHANGED
@@ -360,9 +360,18 @@ module Moxml
360
360
 
361
361
  alias content= text=
362
362
 
363
+ # Generation-gated memo (the #321 shape): the native read
364
+ # allocates a fresh String per call and hydration walks re-read
365
+ # the same wrappers — 122k births over 10 passes of 2,000
366
+ # elements before this memo, 5 after. All inner-text writers are
367
+ # children mutations, which bump the children generation.
363
368
  def inner_text
364
- text = raw_inner_text
365
- entity_bearing? ? adapter.restore_entities(text) : text
369
+ @inner_text = nil if @inner_text_gen != context.children_generation
370
+ @inner_text_gen = context.children_generation
371
+ @inner_text ||= begin
372
+ text = raw_inner_text
373
+ entity_bearing? ? adapter.restore_entities(text) : text
374
+ end
366
375
  end
367
376
 
368
377
  # Returns inner text without entity marker restoration.
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.105"
4
+ VERSION = "0.5.106"
5
5
  end
@@ -312,6 +312,22 @@ RSpec.describe "Nokogiri-compatible node sugar" do
312
312
  end
313
313
  end
314
314
 
315
+ describe "Document#root= native adoption re-points the source wrapper" do
316
+ it "writes through the original wrapper reach the installed tree" do
317
+ ctx = Moxml.new(:leptris)
318
+ other = ctx.parse('<r xmlns="urn:x" a="1"><p>hi<b>t</b></p></r>')
319
+ doc = ctx.create_document
320
+ src_root = other.root
321
+ doc.root = src_root
322
+ # the engine deep-copies; the wrapper now addresses the installed
323
+ # handle — a later write must serialize into the new document
324
+ src_root["a"] = "2"
325
+ expect(doc.to_xml(indent: 0)).to include('a="2"')
326
+ expect(doc.root["a"]).to eq("2")
327
+ expect(doc.root.namespace_uri.to_s).to eq("urn:x")
328
+ end
329
+ end
330
+
315
331
  describe "Document#root= with a foreign root" do
316
332
  it "adopts the subtree from another document" do
317
333
  doc = Moxml.parse("<old><x/></old>")
@@ -409,6 +425,17 @@ RSpec.describe "Nokogiri-compatible node sugar" do
409
425
  expect(a.text).to eq("w")
410
426
  end
411
427
 
428
+ it "Element#inner_text memoizes and invalidates on child mutations" do
429
+ doc = Moxml.parse("<r><a>x<b>y</b>z</a></r>")
430
+ a = doc.at("//a")
431
+ first = a.inner_text
432
+ expect(a.inner_text).to equal(first)
433
+ a.add_child(doc.create_element("c"))
434
+ expect(a.inner_text).not_to equal(first)
435
+ a.text = "plain"
436
+ expect(a.inner_text).to eq("plain")
437
+ end
438
+
412
439
  it "Attribute#value memoizes and invalidates on value=" do
413
440
  doc = Moxml.parse(%(<r a="1"/>))
414
441
  attr = doc.root.attributes.first
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moxml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.105
4
+ version: 0.5.106
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-03 00:00:00.000000000 Z
11
+ date: 2026-10-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Moxml is a unified XML manipulation library that provides a common API