moxml 0.5.15 → 0.5.16
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 +4 -4
- data/Gemfile +1 -1
- data/docs/_pages/adapter-protocol.adoc +3 -3
- data/docs/_pages/adapters/leptris.adoc +8 -5
- data/lib/moxml/adapter/leptris/document_parts.rb +11 -75
- data/lib/moxml/adapter/leptris/materialize.rb +0 -2
- data/lib/moxml/adapter/leptris.rb +12 -33
- data/lib/moxml/config.rb +9 -7
- data/lib/moxml/version.rb +1 -1
- data/spec/moxml/adapter/leptris_spec.rb +0 -4
- data/spec/moxml/adapter/platform_spec.rb +10 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39cfbe08ea2a0e92f2ba89e83beacf564401765e964807dc4d73ca23d867af38
|
|
4
|
+
data.tar.gz: cdd5d499fd4b3233a6c4d2774b188aef2339f341f7c7a7112a82ac392ec4e53b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 894d6bacdd4f26dbb2a59b0684b29e8ca68b39b66f841a5cd11005351eff38404e745b47d58bb860c898d3da92e1e2a769210938f26cac2f88cac34cc887de76
|
|
7
|
+
data.tar.gz: c5b7b7c9de4f2362e910b740ce4cf6185a72773f39f31a3dfc17fbd7436f65f542e66ff099900bf9073e87bd5975568cb3833ac658115ea5ee21a4218719ce90
|
data/Gemfile
CHANGED
|
@@ -86,9 +86,9 @@ eight record fields per node, returning nil falls back to the
|
|
|
86
86
|
generic wrapper walk. Leptris walks raw C pointers with the batch
|
|
87
87
|
`leptris_node_children` call — no wrappers, no per-node callback.
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
`
|
|
91
|
-
per engine capability, computed at load.
|
|
89
|
+
Version gates like `PREFIXED_ATTR_PREDICATES_NATIVE` and the
|
|
90
|
+
`MINIMUM_BINDING_VERSION` floor (Leptris) follow the same idea: one
|
|
91
|
+
probe per engine capability, computed at load.
|
|
92
92
|
|
|
93
93
|
== Return shapes
|
|
94
94
|
|
|
@@ -13,11 +13,14 @@ with a native XPath 1.0 engine, SAX, and canonicalization.
|
|
|
13
13
|
|
|
14
14
|
== Default resolution
|
|
15
15
|
|
|
16
|
-
Leptris becomes the default when the installed binding
|
|
17
|
-
|
|
18
|
-
leptris >= 1.
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
Leptris becomes the default when the installed binding meets the
|
|
17
|
+
adapter's floor — `Moxml::Adapter::Leptris::MINIMUM_BINDING_VERSION`
|
|
18
|
+
(leptris >= 1.9.32; issue #149): bounded traverse, built documents
|
|
19
|
+
that reflect their parts immediately, and every capability surface
|
|
20
|
+
the adapter assumes. Below the floor the default falls back to
|
|
21
|
+
Nokogiri rather than driving a binding the adapter no longer
|
|
22
|
+
accommodates. Under Opal the default is rexml (stock oga requires
|
|
23
|
+
its C extension and libleptris does not build for Opal).
|
|
21
24
|
|
|
22
25
|
[source,ruby]
|
|
23
26
|
----
|
|
@@ -10,7 +10,7 @@ module Moxml
|
|
|
10
10
|
# swept too (the context wrapper identity map self-cleans via
|
|
11
11
|
# its size valve).
|
|
12
12
|
DOCUMENT_ATTACHMENT_KEYS = %i[
|
|
13
|
-
entity_markers
|
|
13
|
+
entity_markers declaration doctype
|
|
14
14
|
had_source_declaration document_text
|
|
15
15
|
].freeze
|
|
16
16
|
|
|
@@ -29,64 +29,18 @@ module Moxml
|
|
|
29
29
|
doctype_wrapper = attachments.get(doc, :doctype)
|
|
30
30
|
children << doctype_wrapper if doctype_wrapper
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# root does not appear); document_node_children answers
|
|
39
|
-
# nil there for the legacy parts path.
|
|
40
|
-
doc_children = document_node_children(doc)
|
|
41
|
-
if doc_children
|
|
42
|
-
children.concat(doc_children)
|
|
43
|
-
else
|
|
44
|
-
children.concat(document_pi_nodes(doc))
|
|
45
|
-
children << doc.root if doc.root
|
|
46
|
-
end
|
|
47
|
-
else
|
|
48
|
-
# Legacy path: document-level PIs live outside the element
|
|
49
|
-
# tree in a flat pre-root list (libleptris < 1.9.7 C
|
|
50
|
-
# model); epilog anchoring is not representable there.
|
|
51
|
-
children.concat(document_pi_nodes(doc))
|
|
52
|
-
|
|
53
|
-
children << doc.root if doc.root
|
|
54
|
-
end
|
|
32
|
+
# The libxml2-model document node lists prolog PIs/comments,
|
|
33
|
+
# the root, and epilog PIs/comments in document order — the
|
|
34
|
+
# Nokogiri-shaped contract, epilog anchoring included (issue
|
|
35
|
+
# #130). Built documents reflect their parts immediately
|
|
36
|
+
# since leptris-ruby 1.9.32 (leptris-ruby#91).
|
|
37
|
+
children.concat(doc.children.to_a)
|
|
55
38
|
|
|
56
39
|
texts = attachments.get(doc, :document_text)
|
|
57
40
|
children.concat(texts) if texts
|
|
58
41
|
children
|
|
59
42
|
end
|
|
60
43
|
|
|
61
|
-
# Document-level PI pseudo-nodes, materialized once from the C
|
|
62
|
-
# list and cached per document: children and serialization read
|
|
63
|
-
# the same objects, so wrapper mutations round-trip. Build the
|
|
64
|
-
# cache BEFORE appending a PI with add_pi, or the C-side
|
|
65
|
-
# addition would be double-counted.
|
|
66
|
-
# The document node's children, or nil when the node does not
|
|
67
|
-
# reflect reality: parsed documents always list the root
|
|
68
|
-
# element among their children, but programmatically built
|
|
69
|
-
# ones do not (binding gap) — those keep the legacy parts
|
|
70
|
-
# path.
|
|
71
|
-
def document_node_children(doc)
|
|
72
|
-
doc_children = doc.children.to_a
|
|
73
|
-
has_root = doc_children.any?(::Leptris::XML::Element)
|
|
74
|
-
return doc_children if has_root
|
|
75
|
-
return doc_children if doc.root.nil?
|
|
76
|
-
|
|
77
|
-
nil
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def document_pi_nodes(doc)
|
|
81
|
-
attachments.get(doc, :doc_pi_nodes) || begin
|
|
82
|
-
nodes = doc.processing_instructions.map do |(target, data)|
|
|
83
|
-
CustomizedLeptris::DocumentPI.new(target, data, doc)
|
|
84
|
-
end
|
|
85
|
-
attachments.set(doc, :doc_pi_nodes, nodes)
|
|
86
|
-
nodes
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
44
|
def add_document_child(doc, child)
|
|
91
45
|
case child
|
|
92
46
|
when CustomizedLeptris::Declaration
|
|
@@ -102,15 +56,9 @@ module Moxml
|
|
|
102
56
|
when ::Leptris::XML::Element
|
|
103
57
|
doc.root = child
|
|
104
58
|
when ::Leptris::XML::ProcessingInstruction
|
|
105
|
-
document_pi_nodes(doc)
|
|
106
59
|
doc.add_pi(child.target, child.content.to_s)
|
|
107
|
-
document_pi_nodes(doc) << CustomizedLeptris::DocumentPI.new(
|
|
108
|
-
child.target, child.content.to_s, doc
|
|
109
|
-
)
|
|
110
60
|
when CustomizedLeptris::DocumentPI
|
|
111
|
-
document_pi_nodes(doc)
|
|
112
61
|
doc.add_pi(child.target, child.data)
|
|
113
|
-
document_pi_nodes(doc) << child
|
|
114
62
|
when ::Leptris::XML::Text
|
|
115
63
|
texts = attachments.get(doc, :document_text) || []
|
|
116
64
|
texts << child
|
|
@@ -149,22 +97,10 @@ module Moxml
|
|
|
149
97
|
native = native_doctype_xml(doc)
|
|
150
98
|
parts << native << "\n" if native
|
|
151
99
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
doc_children = document_node_children(doc)
|
|
157
|
-
if doc_children
|
|
158
|
-
doc_children.each { |child| parts << raw_serialize(child, options) << "\n" }
|
|
159
|
-
else
|
|
160
|
-
document_pi_nodes(doc).each { |pi| parts << pi.to_xml << "\n" }
|
|
161
|
-
parts << raw_serialize(doc.root, options) << "\n" if doc.root
|
|
162
|
-
end
|
|
163
|
-
else
|
|
164
|
-
document_pi_nodes(doc).each { |pi| parts << pi.to_xml << "\n" }
|
|
165
|
-
|
|
166
|
-
parts << raw_serialize(doc.root, options) << "\n" if doc.root
|
|
167
|
-
end
|
|
100
|
+
# The libxml2-model document node: prolog PIs/comments, the
|
|
101
|
+
# root, epilog PIs/comments — in document order, so epilog
|
|
102
|
+
# parts serialize after the root (issue #130).
|
|
103
|
+
doc.children.each { |child| parts << raw_serialize(child, options) << "\n" }
|
|
168
104
|
|
|
169
105
|
texts = attachments.get(doc, :document_text)
|
|
170
106
|
texts&.each { |text| parts << XmlEmitter.escape_text(text.content.to_s) }
|
|
@@ -39,8 +39,6 @@ module Moxml
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def materialize_fields(native, buffers, &block)
|
|
42
|
-
return nil unless Leptris::BULK_FIELD_READS
|
|
43
|
-
|
|
44
42
|
doc = native.is_a?(::Leptris::XML::Document) ? native : native.document
|
|
45
43
|
# Marker-bearing text needs the split pipeline (children-level
|
|
46
44
|
# ER expansion); the bulk path has no marker handling.
|
|
@@ -4,11 +4,6 @@ return if RUBY_ENGINE == "opal"
|
|
|
4
4
|
|
|
5
5
|
require "stringio"
|
|
6
6
|
require "leptris"
|
|
7
|
-
# leptris-ruby 1.9.0 regression (leptris-ruby#53): the eager ffi load
|
|
8
|
-
# shadows the Leptris::XML autoload manifest, leaving Document/Element
|
|
9
|
-
# unreachable. Loading the manifest explicitly is a no-op when the gem
|
|
10
|
-
# is fixed.
|
|
11
|
-
require "leptris/xml"
|
|
12
7
|
|
|
13
8
|
module Moxml
|
|
14
9
|
module Adapter
|
|
@@ -19,29 +14,14 @@ module Moxml
|
|
|
19
14
|
# programmatic DOCTYPE, so those live in CustomizedLeptris value
|
|
20
15
|
# objects stored through NativeAttachment.
|
|
21
16
|
class Leptris < Base
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# The raw field-read surface for the bulk materializer (issue
|
|
32
|
-
# #143). Bindings without the full set fall back to the generic
|
|
33
|
-
# wrapper walk.
|
|
34
|
-
BULK_FIELD_READS = %i[
|
|
35
|
-
leptris_node_children leptris_node_get_type
|
|
36
|
-
leptris_element_name leptris_element_prefix leptris_element_namespace
|
|
37
|
-
leptris_element_namespace_count leptris_element_namespace_decl_prefix
|
|
38
|
-
leptris_element_namespace_decl_uri leptris_element_first_attribute
|
|
39
|
-
leptris_attribute_get_name leptris_attribute_get_value
|
|
40
|
-
leptris_attribute_next leptris_attribute_namespace_uri
|
|
41
|
-
leptris_text_node_get_content leptris_cdata_node_get_content
|
|
42
|
-
leptris_comment_node_get_content leptris_pi_node_get_target
|
|
43
|
-
leptris_pi_node_get_data
|
|
44
|
-
].all? { |fn| ::Leptris::XML::FFI.respond_to?(fn) }
|
|
17
|
+
# The binding floor (issue #149): 1.9.32 carried the traverse
|
|
18
|
+
# fix (leptris-ruby#89) and made built documents reflect their
|
|
19
|
+
# parts immediately (leptris-ruby#91); the document node
|
|
20
|
+
# (1.9.26), DTDATTR (1.9.8), and the batch child-pointer read
|
|
21
|
+
# (1.7.0) surfaces predate it. Older bindings are not eligible
|
|
22
|
+
# for the default (see Config.leptris_preferred_available?) and
|
|
23
|
+
# the adapter no longer carries accommodation paths for them.
|
|
24
|
+
MINIMUM_BINDING_VERSION = "1.9.32"
|
|
45
25
|
|
|
46
26
|
# leptris-ruby#103: prefixed attribute tests inside predicates
|
|
47
27
|
# stopped resolving through the document's in-scope declarations
|
|
@@ -115,12 +95,11 @@ module Moxml
|
|
|
115
95
|
doc
|
|
116
96
|
end
|
|
117
97
|
|
|
118
|
-
# nil
|
|
119
|
-
#
|
|
98
|
+
# nil unless DTDATTR is requested — the binding treats a nil
|
|
99
|
+
# options hash as plain defaults (defaults exclude ATTLIST
|
|
100
|
+
# defaults, matching libxml2/Nokogiri semantics).
|
|
120
101
|
def dtdattr_parse_options(options)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
::Leptris::XML::ParseOptions.dtdattr
|
|
102
|
+
options[:dtdattr] == true ? ::Leptris::XML::ParseOptions.dtdattr : nil
|
|
124
103
|
end
|
|
125
104
|
|
|
126
105
|
def parse_errors(native_doc)
|
data/lib/moxml/config.rb
CHANGED
|
@@ -58,18 +58,20 @@ module Moxml
|
|
|
58
58
|
OPAL_FALLBACK_ADAPTER
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
# True when the leptris gem is installed AND
|
|
62
|
-
#
|
|
63
|
-
#
|
|
61
|
+
# True when the leptris gem is installed AND meets the adapter's
|
|
62
|
+
# binding floor (issue #149; 1.9.32 — traverse bounding #89,
|
|
63
|
+
# built-docs parts #91, and every capability surface the adapter
|
|
64
|
+
# now assumes). Memoized: the probe runs once. Below the floor
|
|
65
|
+
# the default falls back to Nokogiri rather than driving a
|
|
66
|
+
# binding the adapter no longer accommodates.
|
|
64
67
|
def leptris_preferred_available?
|
|
65
68
|
return @leptris_preferred_available if defined?(@leptris_preferred_available)
|
|
66
69
|
|
|
67
70
|
@leptris_preferred_available = begin
|
|
68
71
|
require "leptris"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
::Leptris::XML::Document.respond_to?(:create)
|
|
72
|
+
Moxml::Adapter.load(:leptris)
|
|
73
|
+
Gem::Version.new(::Leptris::VERSION) >=
|
|
74
|
+
Gem::Version.new(Moxml::Adapter::Leptris::MINIMUM_BINDING_VERSION)
|
|
73
75
|
rescue LoadError, NameError
|
|
74
76
|
false
|
|
75
77
|
end
|
data/lib/moxml/version.rb
CHANGED
|
@@ -186,16 +186,12 @@ RSpec.describe Moxml::Adapter::Leptris do
|
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
it "excludes ATTLIST defaults on plain parse" do
|
|
189
|
-
skip "requires leptris with no-DTDATTR semantics" unless Moxml::Adapter::Leptris::DTDATTR_SUPPORTED
|
|
190
|
-
|
|
191
189
|
doc = ctx.parse(dtd_xml)
|
|
192
190
|
expect(doc.at_xpath("//e9")["attr"]).to be_nil
|
|
193
191
|
expect(doc.to_xml).not_to include("attr=")
|
|
194
192
|
end
|
|
195
193
|
|
|
196
194
|
it "materializes ATTLIST defaults with dtdattr: true" do
|
|
197
|
-
skip "requires leptris with ParseOptions::DTDATTR" unless Moxml::Adapter::Leptris::DTDATTR_SUPPORTED
|
|
198
|
-
|
|
199
195
|
doc = ctx.parse(dtd_xml, dtdattr: true)
|
|
200
196
|
expect(doc.at_xpath("//e9")["attr"]).to eq("default")
|
|
201
197
|
expect(doc.to_xml).to include(%(attr="default"))
|
|
@@ -85,7 +85,7 @@ RSpec.describe Moxml::Adapter do
|
|
|
85
85
|
.to include(Moxml::Config.default_adapter)
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
it "prefers leptris only when the installed
|
|
88
|
+
it "prefers leptris only when the installed binding meets the floor" do
|
|
89
89
|
if Moxml::Config.leptris_preferred_available?
|
|
90
90
|
expect(Moxml::Config.runtime_default_adapter).to eq(:leptris)
|
|
91
91
|
else
|
|
@@ -93,6 +93,15 @@ RSpec.describe Moxml::Adapter do
|
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
+
it "pins the leptris binding floor at 1.9.32 (issue #149)" do
|
|
97
|
+
skip "leptris not installed" unless described_class.available?(:leptris)
|
|
98
|
+
|
|
99
|
+
adapter = described_class.load(:leptris)
|
|
100
|
+
expect(adapter::MINIMUM_BINDING_VERSION).to eq("1.9.32")
|
|
101
|
+
expect(Gem::Version.new(Leptris::VERSION))
|
|
102
|
+
.to be >= Gem::Version.new(adapter::MINIMUM_BINDING_VERSION)
|
|
103
|
+
end
|
|
104
|
+
|
|
96
105
|
it "OPAL_DEFAULT_ADAPTER is a member of OPAL_AVAILABLE_ADAPTERS" do
|
|
97
106
|
expect(Moxml::Adapter::OPAL_AVAILABLE_ADAPTERS)
|
|
98
107
|
.to include(Moxml::Config::OPAL_DEFAULT_ADAPTER)
|