leptris 1.9.311.0-arm-linux → 1.9.311.1-arm-linux

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: 8061846b17aec1e2893941c716bedc88f5cf18744c14027e8a0d402cf69a23ff
4
- data.tar.gz: f0e89fb77b36cbb8c31fe0c07a504e0fcd0c6c2894a345580286754618c9ea74
3
+ metadata.gz: df4785eab905b23b3ababb440d2c0f47051bf0f7acde2c6631216828d4fa10d1
4
+ data.tar.gz: 4f8488030ff6e479afc2ebdc59075cd3c92e5f7c17d986731195df6aad13621a
5
5
  SHA512:
6
- metadata.gz: 60b7ebc0d8d0794729cf943c3bf6f1d07caf0dde15a15cd0b3bc8a1842fb8b7b763f2ae6f859ce3fa0083953daba6f71dcddee35c3a85d0519c897957dfefa82
7
- data.tar.gz: ab1f295ed8b2cbc3400f6e33935c65ca4c55a7f566e37f29f432758dc9fe6d4e5c554abe52f7dd4f15bbf3a7591c3beb667e039b11df1c796ea471016e77984c
6
+ metadata.gz: 7fe50d8bc07f07ce47a09539df0def21e0e75716ee96afb471b2f82c5d6687f0e73544bd5afc185ae8767e7576b8e664f27b2e50cb2df7763e616668f28ba51f
7
+ data.tar.gz: 3646cd773bcace3e4f0023b8f5fc80680969062228b458ff2ff296b44bf88f206261caebedb185871eca81a97a583df5579040d6cceb960f67a2d21e3ed3adf3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## [1.9.311.1] - 2026-10-06
2
+
3
+ ### Fixed
4
+
5
+ - **Docless children now route through the adoption contract
6
+ (#376)**: moxml's created nodes arrive as Node wrappers whose
7
+ #document is nil but whose C node is live in a foreign pool —
8
+ the splice sites' foreign check required a document, so those
9
+ children bypassed the namespace lift and, worse, the returned
10
+ wrapper addressed the ABANDONED source instead of the installed
11
+ in-tree copy (moxml's flows then mutated a node the tree never
12
+ saw). `foreign_child?` now treats document-nil as foreign at
13
+ add_child, prepend_child, add_next_sibling,
14
+ add_previous_sibling, and append_children, so every splice
15
+ returns the installed wrapper. Document#root= routes docless
16
+ roots through the copying ex-face too — the plain set_root of a
17
+ foreign-pool node linked the pointer WITHOUT adopting it into
18
+ the destination pool, so destination-side writes landed in the
19
+ source arena and reads through the root memo missed them.
20
+ Node-level mutations on docless
21
+ wrappers no longer crash the version gate (they memoize
22
+ nothing, so there is no version to advance).
23
+
1
24
  ## [1.9.311.0] - 2026-10-06
2
25
 
3
26
  ### Added
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.311.0"
4
+ VERSION = "1.9.311.1"
5
5
  end
@@ -388,7 +388,12 @@ class Leptris::XML::Document
388
388
  # the foreign subtree into this document's pool and reports the
389
389
  # installed element — a fresh handle distinct from the source
390
390
  # pointer. Same-document installs keep the native fast path.
391
- cross = element.document && !element.document.equal?(self)
391
+ # Docless roots count as foreign (#376): a plain set_root of a
392
+ # foreign-pool node links the pointer WITHOUT adopting it into
393
+ # this pool — writes through this document land in the source
394
+ # arena and reads through the root memo miss them. The ex-face
395
+ # copies properly.
396
+ cross = Leptris::XML::Element.foreign_to?(element, self)
392
397
  installed_ptr = nil
393
398
  if cross
394
399
  out = ::FFI::MemoryPointer.new(:pointer)
@@ -389,6 +389,15 @@ class Leptris::XML::Element < Leptris::XML::Node
389
389
  !Leptris::XML::Native.ns_lift_needed?(node.c_ptr.address)
390
390
  end
391
391
 
392
+ # A node is foreign to +document+ when it belongs to another one
393
+ # — or to NONE (#376): moxml's created nodes are live C nodes
394
+ # wrapped without a document, and they splice by copy exactly
395
+ # like attached-foreign ones. One definition of "foreign" for
396
+ # the element splices and Document#root=.
397
+ def self.foreign_to?(node, document)
398
+ node.document.nil? || !node.document.equal?(document)
399
+ end
400
+
392
401
  def self.lift_namespaces_for_adoption(node, target_scope)
393
402
  return unless node.is_a?(Leptris::XML::Element)
394
403
  # Declarations the node already carries (its own definitions —
@@ -419,11 +428,11 @@ class Leptris::XML::Element < Leptris::XML::Node
419
428
  # C-bound insert (TODO.perf/14): gates + predicate + version
420
429
  # bump + engine insert in one dispatch; Qnil = the child needs
421
430
  # the namespace lift — the full path below handles it.
422
- # Cross-document nodes skip the fast path entirely (1.9.304,
423
- # #1528): the engine deep-copies them at the splice, so the
424
- # full path's lift must run FIRST and the source original is
425
- # removed after (move semantics).
426
- if node.document && !node.document.equal?(@document)
431
+ # Cross-document and docless nodes skip the fast path entirely
432
+ # (1.9.304, #1528; #376): the engine deep-copies them at the
433
+ # splice, so the full path's lift must run FIRST and the source
434
+ # original is removed after (move semantics).
435
+ if Leptris::XML::Element.foreign_to?(node, @document)
427
436
  ensure_writable!
428
437
  unless Leptris::XML::Element.skip_adoption_lift?(node)
429
438
  Leptris::XML::Element.lift_namespaces_for_adoption(node, namespaces)
@@ -455,10 +464,10 @@ class Leptris::XML::Element < Leptris::XML::Node
455
464
  # C-bound insert (TODO.perf/14): gates + predicate + version
456
465
  # bump + engine insert in one dispatch; Qnil = the child needs
457
466
  # the namespace lift — the full path below handles it.
458
- # Cross-document: full path first (lift + engine copy), then
459
- # the source original is removed; returns the installed copy
460
- # (self's new next sibling).
461
- if node.document && !node.document.equal?(@document)
467
+ # Cross-document and docless (#376): full path first (lift +
468
+ # engine copy), then the source original is removed; returns
469
+ # the installed copy (self's new next sibling).
470
+ if Leptris::XML::Element.foreign_to?(node, @document)
462
471
  ensure_writable!
463
472
  unless Leptris::XML::Element.skip_adoption_lift?(node)
464
473
  Leptris::XML::Element.lift_namespaces_for_adoption(node, namespaces)
@@ -490,10 +499,10 @@ class Leptris::XML::Element < Leptris::XML::Node
490
499
  # C-bound insert (TODO.perf/14): gates + predicate + version
491
500
  # bump + engine insert in one dispatch; Qnil = the child needs
492
501
  # the namespace lift — the full path below handles it.
493
- # Cross-document: full path first (lift + engine copy), then
494
- # the source original is removed; returns the installed copy
495
- # (self's new previous sibling).
496
- if node.document && !node.document.equal?(@document)
502
+ # Cross-document and docless (#376): full path first (lift +
503
+ # engine copy), then the source original is removed; returns
504
+ # the installed copy (self's new previous sibling).
505
+ if Leptris::XML::Element.foreign_to?(node, @document)
497
506
  ensure_writable!
498
507
  unless Leptris::XML::Element.skip_adoption_lift?(node)
499
508
  Leptris::XML::Element.lift_namespaces_for_adoption(node, namespaces)
@@ -551,9 +560,7 @@ class Leptris::XML::Element < Leptris::XML::Node
551
560
  nodes.each { |n| add_child(n) }
552
561
  return
553
562
  end
554
- cross = nodes.any? do |n|
555
- n.document && !n.document.equal?(@document)
556
- end
563
+ cross = nodes.any? { |n| Leptris::XML::Element.foreign_to?(n, @document) }
557
564
  if native_fast_children?
558
565
  addrs = nodes.map { |n| n.c_ptr.address }
559
566
  done = Leptris::XML::Native.append_binding_children(
@@ -668,13 +675,13 @@ class Leptris::XML::Element < Leptris::XML::Node
668
675
  ensure_writable!
669
676
  case node_or_markup
670
677
  when Leptris::XML::Node
671
- # Cross-document adoption (1.9.304, #1528): the engine
678
+ # Foreign-child adoption (1.9.304, #1528): the engine
672
679
  # deep-copies foreign nodes at the splice — the returned
673
680
  # wrapper must be the INSTALLED copy, not the detached
674
- # source. Route those through the re-resolving path.
675
- cross = node_or_markup.document &&
676
- !node_or_markup.document.equal?(@document)
677
- return append_installed(node_or_markup) if cross
681
+ # source. Docless wrappers count as foreign (#376): moxml's
682
+ # created nodes carry live C pointers with no owning
683
+ # document, and their callers expect the in-tree handle.
684
+ return append_installed(node_or_markup) if Leptris::XML::Element.foreign_to?(node_or_markup, @document)
678
685
  # C-bound append (TODO.perf/08-09): one dispatch runs the
679
686
  # readonly/liveness gates, the provable no-op lift
680
687
  # predicate, the version bump, and the engine append. Qnil
@@ -281,14 +281,15 @@ class Leptris::XML::Node
281
281
  # passes through this gate, so it is where the document's mutation
282
282
  # version advances — the invalidation behind writable-document
283
283
  # memoization. Bumping before the C call is conservative: a failed
284
- # mutation merely discards memos.
284
+ # mutation merely discards memos. Docless wrappers (#376) mutate
285
+ # fine — they memoize nothing, so there is no version to advance.
285
286
  def ensure_writable!
286
287
  ensure_alive!
287
288
  if readonly_document?
288
289
  raise Leptris::XML::ReadOnlyError,
289
290
  "document is readonly — mutation attempted on #{inspect}"
290
291
  end
291
- @document.advance_version
292
+ @document&.advance_version
292
293
  nil
293
294
  end
294
295
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.311.0
4
+ version: 1.9.311.1
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.