moxml 0.5.67 → 0.5.69

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: 945e557e4dbc4028aa2c97eff20d12d62e34e866a1b27b788908ead119f9fbac
4
- data.tar.gz: 7e327b86a60671f9824fec042b61da3a41753d8e13103062346a5941c3d14980
3
+ metadata.gz: d107d95a6e6c40031e9ea519397fe43ecbb08bf991ea5308bb72cc1510df0525
4
+ data.tar.gz: 574d6d7b1b5b211a87992b772358c0bfd96cdf0133c5cd2a2ac6547115139f02
5
5
  SHA512:
6
- metadata.gz: fd59e3f68acd8471903331eff3696af0fae5e64b06a49bd7d7526a5b4ee52078bc52d763e4bc2554f8294f90a4540836f1c2c2e0a8d6f9c3505706f4383a119e
7
- data.tar.gz: e5ac7c12f77a6f89e2e3e55252cf7d67acce9340d61702e344fa818f8168749e59bc91c831c41e446509134e17e9f7fc526ba8105040ef34a66ef33a3a57f984
6
+ metadata.gz: fc99001a56408820af4db232e682b4a5723eb1ef36545909b38144973c3b1583cca7966f89c08ee9b6d6c450bd034fc90bf53300f35e041b8f394154c18e80d7
7
+ data.tar.gz: 15cae743eca3abed5bcf07d4ea264974602b247b9b7edfee018ccf73b0dc4732bb2420779ee8cb90b7a6d7055fe274a51ec5d2509fab9536c056df1d9339a1cf
@@ -3,10 +3,10 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedLeptris
6
- # Wrapper for an XML declaration. libleptris stores declaration
7
- # data on the document struct (read-only, serialized via options)
8
- # and has no first-class declaration node, so Moxml exposes this
9
- # mutable value object instead.
6
+ # Wrapper for an XML declaration. libleptris gained declaration
7
+ # setters (#1094) but has no first-class declaration node and no
8
+ # way to clear the state, so Moxml exposes this mutable,
9
+ # removable value object instead.
10
10
  class Declaration
11
11
  attr_accessor :version, :encoding, :standalone, :parent_doc
12
12
 
@@ -3,9 +3,11 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedLeptris
6
- # Wrapper for a programmatic DOCTYPE. libleptris only parses
7
- # DOCTYPEs from source; it has no API to create one, so Moxml
8
- # stores this value object in the document's attachments.
6
+ # Wrapper for a programmatic DOCTYPE. libleptris can create
7
+ # one (Document#set_doctype, 1.9.176 / #212) but cannot unset
8
+ # it, and the facade contract makes DOCTYPEs removable nodes —
9
+ # so Moxml keeps this value object as the lifecycle record in
10
+ # the document's attachments.
9
11
  class Doctype
10
12
  attr_accessor :name, :external_id, :system_id, :parent_doc
11
13
 
@@ -9,7 +9,8 @@ module Moxml
9
9
  # the root), reachable through Document#processing_instructions
10
10
  # as [target, data] pairs. This pseudo-native gives the pairs a
11
11
  # node identity so the moxml contract can list them as document
12
- # children.
12
+ # children (and answer mutations: creation routes native via
13
+ # add_pi; removal has no engine entry).
13
14
  class DocumentPI
14
15
  attr_accessor :target, :data, :parent_doc
15
16
  alias content data
@@ -3,9 +3,11 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedLeptris
6
- # libleptris expands the five built-in entities at parse time
7
- # and has no custom ones; the adapter carries entity references
8
- # as Moxml::Entity::Reference values over marker-bearing text.
6
+ # Parse-path face: libleptris expands the five built-in entities
7
+ # at parse time and has no custom ones, so parsed references are
8
+ # carried as Moxml::Entity::Reference values over marker-bearing
9
+ # text. Programmatic creation is native (NATIVE_ENTITY_REFS,
10
+ # binding >= 1.9.177).
9
11
  EntityReference = ::Moxml::Entity::Reference
10
12
  end
11
13
  end
@@ -23,11 +23,13 @@ module Moxml
23
23
  def assemble_document_children(doc)
24
24
  children = []
25
25
 
26
- native_doctype = doc.doctype
27
- children << native_doctype if native_doctype
28
-
29
- doctype_wrapper = attachments.get(doc, :doctype)
30
- children << doctype_wrapper if doctype_wrapper
26
+ # Attached DOCTYPEs (NATIVE_DOC_PARTS) list the STORED
27
+ # native the same object the attaching wrapper was
28
+ # refreshed onto — so wrapper identity holds; doc.doctype
29
+ # mints a fresh DocType per call and would fork wrappers.
30
+ doctype_native = attachments.get(doc, :doctype)
31
+ doctype_native = doc.doctype unless doctype_native.is_a?(::Leptris::XML::DocType)
32
+ children << doctype_native if doctype_native
31
33
 
32
34
  # The libxml2-model document node lists prolog PIs/comments,
33
35
  # the root, and epilog PIs/comments in document order — the
@@ -55,10 +57,25 @@ module Moxml
55
57
  when CustomizedLeptris::Declaration
56
58
  child.parent_doc = doc
57
59
  attachments.set(doc, :declaration, child)
60
+ mirror_declaration_native(doc, child) if NATIVE_DOC_PARTS
58
61
  when CustomizedLeptris::Doctype
62
+ if NATIVE_DOC_PARTS
63
+ dt = doc.set_doctype(child.name,
64
+ public_id: child.external_id,
65
+ system_id: child.system_id)
66
+ attachments.set(doc, :doctype, dt)
67
+ return dt
68
+ end
59
69
  child.parent_doc = doc
60
70
  attachments.set(doc, :doctype, child)
61
71
  when ::Leptris::XML::DocType
72
+ if NATIVE_DOC_PARTS
73
+ dt = doc.set_doctype(child.root_name,
74
+ public_id: child.public_id,
75
+ system_id: child.system_id)
76
+ attachments.set(doc, :doctype, dt)
77
+ return dt
78
+ end
62
79
  raise Moxml::DocumentStructureError.new(
63
80
  "libleptris does not support attaching a native DocType to a document",
64
81
  )
@@ -112,7 +129,7 @@ module Moxml
112
129
  end
113
130
 
114
131
  doctype = attachments.get(doc, :doctype)
115
- parts << doctype.to_xml << "\n" if doctype
132
+ parts << doctype.to_xml << "\n" if doctype.is_a?(CustomizedLeptris::Doctype)
116
133
 
117
134
  native = native_doctype_xml(doc)
118
135
  parts << native << "\n" if native
@@ -304,6 +321,40 @@ module Moxml
304
321
  attachments.get(native, :had_source_declaration) ? true : false
305
322
  end
306
323
 
324
+ # Write a created declaration through to the engine's
325
+ # document state (setters, libleptris 1.9.176 / #1094) so
326
+ # native reads and serialization see the same truth the
327
+ # facade does. Removal clears it (clear_declaration).
328
+ def mirror_declaration_native(doc, child)
329
+ # The engine setters reject empty values; the facade's
330
+ # minimal declarations may carry them (serializer formats
331
+ # what it gets). Mirror only non-empty parts — the wrapper
332
+ # remains the record for what the facade shows.
333
+ unless child.version.to_s.empty?
334
+ ::Leptris::XML::FFI.check_status(
335
+ ::Leptris::XML::FFI.leptris_document_set_version(
336
+ doc.c_ptr, child.version.to_s
337
+ ),
338
+ )
339
+ end
340
+ unless child.encoding.to_s.empty?
341
+ ::Leptris::XML::FFI.check_status(
342
+ ::Leptris::XML::FFI.leptris_document_set_encoding(
343
+ doc.c_ptr, child.encoding.to_s
344
+ ),
345
+ )
346
+ end
347
+ case child.standalone.to_s
348
+ when "yes" then sa = 1
349
+ when "no" then sa = 0
350
+ end
351
+ ::Leptris::XML::FFI.check_status(
352
+ ::Leptris::XML::FFI.leptris_document_set_standalone(
353
+ doc.c_ptr, sa || -1
354
+ ),
355
+ )
356
+ end
357
+
307
358
  def marker_text_for(parent, name)
308
359
  return nil unless parent.is_a?(::Leptris::XML::Element)
309
360
 
@@ -12,9 +12,12 @@ module Moxml
12
12
  # Adapter over the leptris FFI binding (libleptris C library).
13
13
  #
14
14
  # libleptris provides DOM parsing, a native XPath 1.0 engine, SAX,
15
- # and serialization. It has no first-class XML declaration or
16
- # programmatic DOCTYPE, so those live in CustomizedLeptris value
17
- # objects stored through NativeAttachment.
15
+ # and serialization. Its document-level creation surfaces exist
16
+ # (set_doctype 1.9.176/#212, declaration setters #1094) but are
17
+ # SET-ONLY no unset for declaration, DOCTYPE, or document PIs —
18
+ # while the moxml facade contract makes those parts removable
19
+ # nodes. CustomizedLeptris value objects therefore remain the
20
+ # lifecycle record, attached through NativeAttachment.
18
21
  class Leptris < Base
19
22
  # The binding floor (issue #149): 1.9.32 carried the traverse
20
23
  # fix (leptris-ruby#89) and made built documents reflect their
@@ -551,6 +554,16 @@ module Moxml
551
554
  (!defined?(::Leptris::XML::Native) ||
552
555
  ::Leptris::XML::Native.respond_to?(:plan_structs))
553
556
 
557
+ # leptris-ruby#275 (binding 1.9.204, the remove half of the
558
+ # document-level surfaces): remove_pi, clear_declaration,
559
+ # remove_doctype complete the set-only creation entries.
560
+ # Attached DOCTYPEs materialize as native nodes, document-PI
561
+ # removal works, and declaration state mirrors through.
562
+ NATIVE_DOC_PARTS =
563
+ Gem::Version.new(::Leptris::VERSION) >= Gem::Version.new("1.9.204.0") &&
564
+ ::Leptris::XML::Document.method_defined?(:remove_doctype) &&
565
+ ::Leptris::XML::Document.method_defined?(:clear_declaration)
566
+
554
567
  def self.plan_structs(native, spec)
555
568
  return nil unless NATIVE_PLAN_STRUCTS
556
569
 
@@ -954,6 +967,9 @@ module Moxml
954
967
  def remove_declaration(native_doc)
955
968
  attachments.delete(native_doc, :declaration)
956
969
  attachments.delete(native_doc, :had_source_declaration)
970
+ if NATIVE_DOC_PARTS && native_doc.is_a?(::Leptris::XML::Document)
971
+ native_doc.clear_declaration
972
+ end
957
973
  end
958
974
 
959
975
  def create_native_namespace(element, prefix, uri)
@@ -1496,6 +1512,15 @@ module Moxml
1496
1512
  attr
1497
1513
  end
1498
1514
 
1515
+ def actual_native(child_native, parent_native)
1516
+ if NATIVE_DOC_PARTS && child_native.is_a?(CustomizedLeptris::Doctype) &&
1517
+ parent_native.is_a?(::Leptris::XML::Document)
1518
+ attached = attachments.get(parent_native, :doctype)
1519
+ return attached if attached.is_a?(::Leptris::XML::DocType)
1520
+ end
1521
+ child_native
1522
+ end
1523
+
1499
1524
  def add_child(parent, child)
1500
1525
  if NATIVE_READ_LAYER && !(NATIVE_MUTATIONS_COHERENT &&
1501
1526
  parent.is_a?(::Leptris::XML::NativeNode) &&
@@ -1588,14 +1613,33 @@ module Moxml
1588
1613
  remove_declaration(node.parent_doc) if node.parent_doc
1589
1614
  when CustomizedLeptris::Doctype
1590
1615
  attachments.delete(node.parent_doc, :doctype) if node.parent_doc
1616
+ when ::Leptris::XML::DocType
1617
+ if NATIVE_DOC_PARTS
1618
+ doc = node.document || doc_for(node)
1619
+ if doc
1620
+ doc.remove_doctype
1621
+ attachments.delete(doc, :doctype)
1622
+ end
1623
+ end
1591
1624
  when CustomizedLeptris::EntityReference
1592
1625
  marker_text_for(node.parent, node.name)&.unlink
1593
1626
  when CustomizedLeptris::DocumentPI
1594
- raise Moxml::NotImplementedError.new(
1595
- "libleptris has no document-level PI removal",
1596
- adapter: :leptris,
1597
- feature: :remove,
1598
- )
1627
+ if NATIVE_DOC_PARTS && node.parent_doc
1628
+ pis = node.parent_doc.processing_instructions
1629
+ index = pis.index do |target, data|
1630
+ target == node.target && data == node.data
1631
+ end
1632
+ if index
1633
+ node.parent_doc.remove_pi(index)
1634
+ node.parent_doc = nil
1635
+ end
1636
+ else
1637
+ raise Moxml::NotImplementedError.new(
1638
+ "libleptris has no document-level PI removal",
1639
+ adapter: :leptris,
1640
+ feature: :remove,
1641
+ )
1642
+ end
1599
1643
  else
1600
1644
  node.unlink
1601
1645
  end
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.67"
4
+ VERSION = "0.5.69"
5
5
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "leptris"
5
+ rescue LoadError
6
+ return
7
+ end
8
+
9
+ require "moxml/adapter/leptris"
10
+
11
+ # leptris-ruby#275 (binding 1.9.204, the remove half): attached
12
+ # DOCTYPEs materialize as native nodes with wrapper identity, and
13
+ # document-PI removal / declaration clear work natively. Below the
14
+ # gate the legacy CustomizedLeptris paths keep the contract.
15
+ RSpec.describe Moxml::Adapter::Leptris do
16
+ around do |example|
17
+ Moxml.with_config(:leptris, true, "UTF-8") do
18
+ example.run
19
+ end
20
+ end
21
+
22
+ let(:ctx) { Moxml.new(:leptris) }
23
+ let(:gate) do
24
+ Moxml::Adapter::Leptris::NATIVE_DOC_PARTS
25
+ end
26
+
27
+ describe "created DOCTYPE as a native node" do
28
+ it "attaches, lists once with wrapper identity, serializes, and removes" do
29
+ skip "requires binding 1.9.204+ (leptris-ruby#275)" unless gate
30
+
31
+ doc = ctx.parse("<root/>")
32
+ doctype = doc.create_doctype("root", "-//X//DTD Y//EN", "y.dtd")
33
+ doc.add_child(doctype)
34
+
35
+ listed = doc.children.grep(Moxml::Doctype)
36
+ expect(listed.size).to eq(1)
37
+ expect(listed.first).to equal(doctype)
38
+ expect(doc.to_xml)
39
+ .to include(%(<!DOCTYPE root PUBLIC "-//X//DTD Y//EN" "y.dtd">))
40
+
41
+ doctype.remove
42
+ expect(doc.children).to all(be_a(Moxml::Element))
43
+ expect(doc.to_xml).not_to include("DOCTYPE")
44
+ end
45
+ end
46
+
47
+ describe "document-level PI removal" do
48
+ it "removes the PI from children and serialization" do
49
+ skip "requires binding 1.9.204+ (leptris-ruby#275)" unless gate
50
+
51
+ doc = ctx.parse("<root/>")
52
+ doc.add_child(doc.create_processing_instruction("before", "data"))
53
+ expect(doc.children.count { |c| c.is_a?(Moxml::ProcessingInstruction) })
54
+ .to eq(1)
55
+
56
+ doc.children
57
+ .find { |c| c.is_a?(Moxml::ProcessingInstruction) }
58
+ .remove
59
+ expect(doc.children.count { |c| c.is_a?(Moxml::ProcessingInstruction) })
60
+ .to eq(0)
61
+ expect(doc.to_xml).not_to include("<?before")
62
+ end
63
+ end
64
+
65
+ describe "declaration mirroring" do
66
+ it "writes created declarations through to engine state and clears on remove" do
67
+ skip "requires binding 1.9.204+ (leptris-ruby#275)" unless gate
68
+
69
+ doc = ctx.parse("<root/>")
70
+ declaration = doc.create_declaration("1.1", "UTF-8", "yes")
71
+ doc.add_child(declaration)
72
+
73
+ ffi = Leptris::XML::FFI
74
+ native = doc.native
75
+ expect(ffi.leptris_document_version(native.c_ptr)).to eq("1.1")
76
+ expect(ffi.leptris_document_standalone(native.c_ptr)).to eq(1)
77
+ expect(doc.to_xml).to include(%(version="1.1"))
78
+ expect(doc.to_xml).to include(%(standalone="yes"))
79
+
80
+ declaration.remove
81
+ expect(doc.to_xml).not_to include("version=")
82
+ end
83
+ end
84
+ 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.67
4
+ version: 0.5.69
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -433,6 +433,7 @@ files:
433
433
  - spec/moxml/adapter/base_spec.rb
434
434
  - spec/moxml/adapter/entity_restoration_spec.rb
435
435
  - spec/moxml/adapter/headed_ox_spec.rb
436
+ - spec/moxml/adapter/leptris_doc_parts_spec.rb
436
437
  - spec/moxml/adapter/leptris_spec.rb
437
438
  - spec/moxml/adapter/libxml_internals_spec.rb
438
439
  - spec/moxml/adapter/libxml_spec.rb