moxml 0.5.171 → 0.5.173
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/Rakefile +23 -0
- data/conformance/moxml-conformance.json +413 -0
- data/docs/_pages/model-coverage.adoc +1 -0
- data/docs/_references/processing-model.adoc +7 -1
- data/lib/moxml/adapter/base.rb +9 -0
- data/lib/moxml/adapter/customized_leptris/declaration.rb +9 -0
- data/lib/moxml/adapter/customized_leptris/doctype.rb +8 -0
- data/lib/moxml/adapter/customized_leptris/entity_reference.rb +8 -0
- data/lib/moxml/adapter/customized_leptris/text_segment.rb +8 -0
- data/lib/moxml/adapter/customized_leptris.rb +5 -0
- data/lib/moxml/adapter/customized_libxml/cdata.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/comment.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/declaration.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/element.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/entity_reference.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/node.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +2 -0
- data/lib/moxml/adapter/customized_libxml/text.rb +2 -0
- data/lib/moxml/adapter/customized_libxml.rb +3 -0
- data/lib/moxml/adapter/customized_oga/entity_decoder.rb +8 -0
- data/lib/moxml/adapter/customized_oga/raw_value_override.rb +8 -0
- data/lib/moxml/adapter/customized_oga/xml_declaration.rb +8 -0
- data/lib/moxml/adapter/customized_oga/xml_generator.rb +1 -1
- data/lib/moxml/adapter/customized_oga.rb +4 -0
- data/lib/moxml/adapter/customized_ox/attribute.rb +5 -0
- data/lib/moxml/adapter/customized_ox/entity_reference.rb +5 -0
- data/lib/moxml/adapter/customized_ox/namespace.rb +5 -0
- data/lib/moxml/adapter/customized_ox/text.rb +6 -0
- data/lib/moxml/adapter/customized_ox.rb +3 -0
- data/lib/moxml/adapter/customized_rexml/entity_reference.rb +5 -0
- data/lib/moxml/adapter/customized_rexml/formatter.rb +6 -0
- data/lib/moxml/adapter/customized_rexml.rb +4 -0
- data/lib/moxml/adapter/leptris.rb +31 -0
- data/lib/moxml/adapter.rb +13 -0
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xsd/builtin_lexical.rb +100 -0
- data/spec/moxml/adapter/customized_lifecycle_audit_spec.rb +49 -0
- data/spec/moxml/adapter_capabilities_spec.rb +48 -0
- data/spec/moxml/adapter_registry_spec.rb +44 -0
- data/spec/moxml/customized_lifecycle_spec.rb +47 -0
- data/spec/moxml/xsd_conformance_cases_spec.rb +37 -0
- data/spec/support/model_coverage.rb +4 -0
- metadata +7 -1
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Stand-in XML declaration node.
|
|
4
|
+
#
|
|
5
|
+
# Engine gap (upstream oga): Oga::XML::XmlDeclaration is not writable —
|
|
6
|
+
# version/encoding/standalone cannot be set on an instance the way the
|
|
7
|
+
# facade contract requires, so this subclass owns the state and renders
|
|
8
|
+
# the declaration itself. Upstream tracker:
|
|
9
|
+
# https://github.com/yorickpeterse/oga
|
|
10
|
+
|
|
3
11
|
require "oga"
|
|
4
12
|
|
|
5
13
|
module Moxml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# rubocop:disable Style/FrozenStringLiteralComment
|
|
2
2
|
|
|
3
|
-
require "oga"
|
|
3
|
+
# Lifecycle record: engine gap (upstream oga); see the patched-class URL below.require "oga"
|
|
4
4
|
|
|
5
5
|
# monkey patch the Oga generator because it's not configurable
|
|
6
6
|
# https://github.com/yorickpeterse/oga/blob/main/lib/oga/xml/generator.rb
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Moxml
|
|
4
4
|
module Adapter
|
|
5
|
+
# Lifecycle record (#495): every override serves the :oga adapter,
|
|
6
|
+
# deprecated in moxml#491 and deleted with the Opal surface in
|
|
7
|
+
# moxml#489 phase 4. No separate upstream ask -- the adapter's
|
|
8
|
+
# fate governs this file.
|
|
5
9
|
module CustomizedOga
|
|
6
10
|
autoload :EntityDecoderOverride, "moxml/adapter/customized_oga/entity_decoder"
|
|
7
11
|
autoload :RawValueOverride, "moxml/adapter/customized_oga/raw_value_override"
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Engine gap (upstream ox): an ::Ox::Attribute carries no parent
|
|
4
|
+
# back-reference and no prefix slots, so the facade's attribute node
|
|
5
|
+
# contract needs this Node subclass. Upstream tracker:
|
|
6
|
+
# https://github.com/ohler55/ox
|
|
7
|
+
|
|
3
8
|
module Moxml
|
|
4
9
|
module Adapter
|
|
5
10
|
module CustomizedOx
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Parse-path alias: ox expands the built-in entities at parse time and
|
|
4
|
+
# has no reference nodes, so parsed references are the facade's
|
|
5
|
+
# Moxml::Entity::Reference values. Lifecycle: the :ox adapter is
|
|
6
|
+
# deprecated (#491) — this record dies with it.
|
|
7
|
+
|
|
3
8
|
module Moxml
|
|
4
9
|
module Adapter
|
|
5
10
|
module CustomizedOx
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Engine gap (upstream ox): ox has no Namespace node class — prefixes
|
|
4
|
+
# live as attribute spellings — so the facade's namespace node contract
|
|
5
|
+
# needs this value object. Upstream tracker:
|
|
6
|
+
# https://github.com/ohler55/ox
|
|
7
|
+
|
|
3
8
|
module Moxml
|
|
4
9
|
module Adapter
|
|
5
10
|
module CustomizedOx
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Engine gap (upstream ox): Ox uses Strings for text content, but a
|
|
4
|
+
# String cannot carry a @parent back-reference; this ::Ox::Node subclass
|
|
5
|
+
# gives text nodes node identity. NOTE: an ::Ox::Node subclass that is
|
|
6
|
+
# neither ::Ox::Element nor ::Ox::Document changes Ox's dump behavior.
|
|
7
|
+
# Upstream tracker: https://github.com/ohler55/ox
|
|
8
|
+
|
|
3
9
|
module Moxml
|
|
4
10
|
module Adapter
|
|
5
11
|
module CustomizedOx
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Moxml
|
|
4
4
|
module Adapter
|
|
5
|
+
# Lifecycle record (#495): engine-gap shims for the :ox adapter,
|
|
6
|
+
# deprecated in moxml#491 -- removed with it after the cycle.
|
|
7
|
+
# No separate upstream ask; the adapter's fate governs.
|
|
5
8
|
module CustomizedOx
|
|
6
9
|
autoload :Attribute, "moxml/adapter/customized_ox/attribute"
|
|
7
10
|
autoload :EntityReference, "moxml/adapter/customized_ox/entity_reference"
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Parse-path alias: rexml expands the built-in entities at parse time,
|
|
4
|
+
# so parsed references are the facade's Moxml::Entity::Reference values.
|
|
5
|
+
# Lifecycle: the :rexml adapter is Opal-only and dies with the Opal
|
|
6
|
+
# surface (#489 phase 4); third-party engine, no upstream ask.
|
|
7
|
+
|
|
3
8
|
module Moxml
|
|
4
9
|
module Adapter
|
|
5
10
|
module CustomizedRexml
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Custom REXML formatter that fixes indentation and wrapping issues.
|
|
4
|
+
# Engine gap (upstream rexml): REXML's Formatters::Pretty cannot be
|
|
5
|
+
# configured to the facade's whitespace contract. Third-party engine,
|
|
6
|
+
# no upstream ask; the :rexml adapter is Opal-only and dies with the
|
|
7
|
+
# Opal surface (#489 phase 4).
|
|
8
|
+
|
|
3
9
|
require "rexml/formatters/pretty"
|
|
4
10
|
|
|
5
11
|
module Moxml
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Moxml
|
|
4
4
|
module Adapter
|
|
5
|
+
# Lifecycle record (#495): engine-gap shims for the :rexml
|
|
6
|
+
# adapter (Opal fallback; deleted with the Opal surface in
|
|
7
|
+
# moxml#489 phase 4). No separate upstream ask; the adapter's
|
|
8
|
+
# fate governs this file.
|
|
5
9
|
module CustomizedRexml
|
|
6
10
|
autoload :EntityReference,
|
|
7
11
|
"moxml/adapter/customized_rexml/entity_reference"
|
|
@@ -320,6 +320,37 @@ module Moxml
|
|
|
320
320
|
BINDING_OF_CAP = 8_192
|
|
321
321
|
|
|
322
322
|
class << self
|
|
323
|
+
# The engine capability report (#493): one structured face
|
|
324
|
+
# answering what THIS installed binding+engine serves, queried
|
|
325
|
+
# once at attach — the replacement for the version-gate-
|
|
326
|
+
# constant class. The support faces (xsd, relaxng, xslt,
|
|
327
|
+
# digest) answer even when the floor makes them unconditional —
|
|
328
|
+
# consumers ask for them by name; the internal routing gates
|
|
329
|
+
# the floor made constant are absent by design. Frozen; the
|
|
330
|
+
# keys are the model's capability names.
|
|
331
|
+
def capabilities
|
|
332
|
+
@capabilities ||= {
|
|
333
|
+
engine_version: ::Leptris::VERSION,
|
|
334
|
+
native_read_layer: !NATIVE_READ_LAYER.nil?,
|
|
335
|
+
native_xpath_seams: !NATIVE_XPATH_SEAMS.nil?,
|
|
336
|
+
bulk_xpath_rows: BULK_XPATH_ROWS,
|
|
337
|
+
add_element_full: ADD_ELEMENT_FULL,
|
|
338
|
+
native_strings_utf8: !NATIVE_STRINGS_UTF8.nil?,
|
|
339
|
+
native_mutations_coherent: !NATIVE_MUTATIONS_COHERENT.nil?,
|
|
340
|
+
native_entity_refs: !NATIVE_ENTITY_REFS.nil?,
|
|
341
|
+
native_bulk_fixed: !NATIVE_BULK_FIXED.nil?,
|
|
342
|
+
native_bulk_sax_records: NATIVE_SAX_RECORDS,
|
|
343
|
+
native_document_parts: NATIVE_DOC_PARTS,
|
|
344
|
+
native_plan_rows: NATIVE_PLAN_ROWS,
|
|
345
|
+
native_plan_structs: NATIVE_PLAN_STRUCTS,
|
|
346
|
+
native_plan_typed: NATIVE_PLAN_TYPED,
|
|
347
|
+
digest: DIGEST_SUPPORTED,
|
|
348
|
+
xsd: XSD_SUPPORTED,
|
|
349
|
+
relaxng: RELAXNG_SUPPORTED,
|
|
350
|
+
xslt: XSLT_SUPPORTED,
|
|
351
|
+
}.freeze
|
|
352
|
+
end
|
|
353
|
+
|
|
323
354
|
# WeakMap has no #clear — 0.5.100's valve crashed every parse
|
|
324
355
|
# crossing the cap on 3.4+ (NoMethodError). Replace the
|
|
325
356
|
# registry wholesale, type-preserving: the WeakMap flavor
|
data/lib/moxml/adapter.rb
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Moxml
|
|
4
4
|
module Adapter
|
|
5
|
+
# Extension contract (#494): adding an adapter is exactly the trio
|
|
6
|
+
# below — nothing else, anywhere. The dispatch is open for
|
|
7
|
+
# extension and closed against edit: registration is data, the
|
|
8
|
+
# load path is generic, and spec/moxml/adapter_registry_spec.rb
|
|
9
|
+
# walks the registry mechanically so a skipped leg fails there.
|
|
10
|
+
#
|
|
11
|
+
# 1. one entry in AVAILABLE_ADAPTERS,
|
|
12
|
+
# 2. a requireable file at moxml/adapter/<name> (a
|
|
13
|
+
# `Customized<Name>` namespace module is optional),
|
|
14
|
+
# 3. a subclass of Adapter::Base in that file.
|
|
15
|
+
#
|
|
16
|
+
# Deprecated adapters live in DEPRECATED_ADAPTERS (still fully
|
|
17
|
+
# registered and loadable) until their removal milestone.
|
|
5
18
|
autoload :Base, "moxml/adapter/base"
|
|
6
19
|
autoload :CustomizedOga, "moxml/adapter/customized_oga"
|
|
7
20
|
autoload :CustomizedOx, "moxml/adapter/customized_ox"
|
data/lib/moxml/version.rb
CHANGED
|
@@ -255,6 +255,106 @@ module Moxml
|
|
|
255
255
|
"xs:NOTATION" => ->(lexical) { qname?(collapsed(lexical)) },
|
|
256
256
|
}.freeze
|
|
257
257
|
|
|
258
|
+
# The cross-language conformance dataset (#496): the model's
|
|
259
|
+
# builtin-lexical answers as data, pinned BY the Ruby suite
|
|
260
|
+
# (spec/moxml/xsd_conformance_cases_spec.rb) and exported to
|
|
261
|
+
# conformance/moxml-conformance.json by `rake conformance:export`
|
|
262
|
+
# — moxml-rs and moxml-ts run the same rows. Each row:
|
|
263
|
+
# [type, lexical, expected].
|
|
264
|
+
CONFORMANCE_CASES = [
|
|
265
|
+
# token family / collapse
|
|
266
|
+
["xs:token", "a b", true],
|
|
267
|
+
["xs:ID", " id ", true],
|
|
268
|
+
["xs:NMTOKEN", "\tx ", true],
|
|
269
|
+
["xs:ID", "1d", false],
|
|
270
|
+
# unbounded integers
|
|
271
|
+
["xs:integer", "1" * 29, true],
|
|
272
|
+
["xs:positiveInteger", "1" * 29, true],
|
|
273
|
+
["xs:nonNegativeInteger", "1" * 29, true],
|
|
274
|
+
["xs:negativeInteger", "-1#{'0' * 20}", true],
|
|
275
|
+
["xs:nonPositiveInteger", "0", true],
|
|
276
|
+
["xs:nonPositiveInteger", "-0", true],
|
|
277
|
+
# bounded integers
|
|
278
|
+
["xs:long", "9223372036854775807", true],
|
|
279
|
+
["xs:long", "9223372036854775808", false],
|
|
280
|
+
["xs:unsignedLong", "18446744073709551615", true],
|
|
281
|
+
["xs:unsignedLong", "18446744073709551616", false],
|
|
282
|
+
["xs:byte", "128", false],
|
|
283
|
+
["xs:unsignedByte", "256", false],
|
|
284
|
+
# float/decimal spellings
|
|
285
|
+
["xs:float", "+INF", true],
|
|
286
|
+
["xs:double", "-INF", true],
|
|
287
|
+
["xs:float", "NaN", true],
|
|
288
|
+
["xs:float", "1.5E-3", true],
|
|
289
|
+
["xs:decimal", "5.", true],
|
|
290
|
+
["xs:decimal", ".5", true],
|
|
291
|
+
["xs:decimal", "1e3", false],
|
|
292
|
+
# calendar
|
|
293
|
+
["xs:date", "2024-02-29", true],
|
|
294
|
+
["xs:date", "1999-02-29", false],
|
|
295
|
+
["xs:date", "2024-04-31", false],
|
|
296
|
+
["xs:date", "2024-13-01", false],
|
|
297
|
+
["xs:date", "not-a-date", false],
|
|
298
|
+
["xs:dateTime", "2024-02-29T23:59:59Z", true],
|
|
299
|
+
["xs:dateTime", "1999-02-29T00:00:00", false],
|
|
300
|
+
["xs:dateTime", "not-a-date", false],
|
|
301
|
+
["xs:dateTimeStamp", "2024-02-29T00:00:00Z", true],
|
|
302
|
+
["xs:dateTimeStamp", "2024-02-29T00:00:00", false],
|
|
303
|
+
["xs:time", "23:59:59.999+05:30", true],
|
|
304
|
+
["xs:time", "24:00:00", false],
|
|
305
|
+
["xs:time", "25:20:00", false],
|
|
306
|
+
["xs:time", "13:20:60", false],
|
|
307
|
+
["xs:gYearMonth", "2024-02Z", true],
|
|
308
|
+
["xs:gYearMonth", "2024-13", false],
|
|
309
|
+
["xs:gMonthDay", "--02-29", true],
|
|
310
|
+
["xs:gMonthDay", "--02-30", false],
|
|
311
|
+
["xs:gDay", "---31", true],
|
|
312
|
+
["xs:gDay", "---32", false],
|
|
313
|
+
# duration
|
|
314
|
+
["xs:duration", "P1Y2M3DT4H5M6.5S", true],
|
|
315
|
+
["xs:duration", "PT0S", true],
|
|
316
|
+
["xs:duration", "-P1D", true],
|
|
317
|
+
["xs:duration", "P", false],
|
|
318
|
+
["xs:duration", "PT", false],
|
|
319
|
+
["xs:duration", "P1Y2MT", false],
|
|
320
|
+
["xs:duration", "P200.5Y", false],
|
|
321
|
+
["xs:dayTimeDuration", "P1DT2H", true],
|
|
322
|
+
["xs:dayTimeDuration", "P1Y", false],
|
|
323
|
+
["xs:yearMonthDuration", "P1Y2M", true],
|
|
324
|
+
["xs:yearMonthDuration", "P1D", false],
|
|
325
|
+
["xs:yearMonthDuration", "P1YT1H", false],
|
|
326
|
+
# binary
|
|
327
|
+
["xs:base64Binary", "aGVsbG8=", true],
|
|
328
|
+
["xs:base64Binary", "abcd", true],
|
|
329
|
+
["xs:base64Binary", "abcde", false],
|
|
330
|
+
["xs:base64Binary", "a b", false],
|
|
331
|
+
["xs:hexBinary", "0A", true],
|
|
332
|
+
["xs:hexBinary", "0AB", false],
|
|
333
|
+
# QName family
|
|
334
|
+
["xs:QName", "foo", true],
|
|
335
|
+
["xs:QName", "ns:foo", true],
|
|
336
|
+
["xs:QName", "xmlns:xsi", false],
|
|
337
|
+
["xs:QName", ":foo", false],
|
|
338
|
+
["xs:QName", "a:b:c", false],
|
|
339
|
+
["xs:NOTATION", "foo", true],
|
|
340
|
+
# lists: items, not characters
|
|
341
|
+
["xs:IDREFS", "a b", true],
|
|
342
|
+
["xs:IDREFS", "a", true],
|
|
343
|
+
["xs:IDREFS", "", false],
|
|
344
|
+
["xs:NMTOKENS", "a.b-c:d e", true],
|
|
345
|
+
["xs:ENTITIES", "a 1", false],
|
|
346
|
+
# open lexical spaces
|
|
347
|
+
["xs:string", "anything <>&", true],
|
|
348
|
+
["xs:anyURI", "http://example.com/a b", true],
|
|
349
|
+
["xs:boolean", "true", true],
|
|
350
|
+
["xs:boolean", "0", true],
|
|
351
|
+
["xs:boolean", "TRUE", false],
|
|
352
|
+
["xs:language", "en-US", true],
|
|
353
|
+
["xs:language", "en_US", false],
|
|
354
|
+
["xs:Name", "a:b", true],
|
|
355
|
+
["xs:NCName", "a:b", false],
|
|
356
|
+
].map(&:freeze).freeze
|
|
357
|
+
|
|
258
358
|
private_constant :CHECKERS
|
|
259
359
|
end
|
|
260
360
|
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# #495: the Customized* adapter layer is either a removable-lifecycle
|
|
6
|
+
# record (an engine gap with a tracked upstream issue) or it dissolves
|
|
7
|
+
# into Base. This audit makes the lifecycle record checkable instead of
|
|
8
|
+
# folklore: every override file must cite its issue (an #NNN reference
|
|
9
|
+
# for our engines, or an upstream tracker URL for third-party engines
|
|
10
|
+
# we do not file against), and every Customized module must be wired
|
|
11
|
+
# into exactly its adapter (no dead records).
|
|
12
|
+
RSpec.describe "Customized adapter lifecycle audit" do
|
|
13
|
+
let(:override_files) do
|
|
14
|
+
Dir[File.expand_path("../../lib/moxml/adapter/customized_*/*.rb", __dir__)].sort
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "cites a tracked issue or upstream tracker in every override file" do
|
|
18
|
+
broken = override_files.reject do |file|
|
|
19
|
+
head = File.readlines(file).first(25).join
|
|
20
|
+
head.match?(/#\s*#\d{2,5}\b/) || head.include?("github.com/")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
expect(broken).to be_empty, <<~MSG
|
|
24
|
+
Customized* override files without a lifecycle citation:
|
|
25
|
+
#{broken.join("\n")}
|
|
26
|
+
Each file's header must cite the open upstream issue that explains
|
|
27
|
+
why the override exists (#NNN for leptris; the upstream tracker URL
|
|
28
|
+
for third-party engines), or the #491 deprecation that retires it.
|
|
29
|
+
MSG
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "wires every Customized module into exactly its adapter" do
|
|
33
|
+
shims = Dir[File.expand_path("../../lib/moxml/adapter/customized_*.rb", __dir__)]
|
|
34
|
+
|
|
35
|
+
shims.each do |shim|
|
|
36
|
+
module_name = File.read(shim)[/module (Customized\w+)/, 1]
|
|
37
|
+
adapter_file = File.expand_path(
|
|
38
|
+
"../../lib/moxml/adapter/#{module_name.delete_prefix('Customized').downcase}.rb",
|
|
39
|
+
__dir__,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
expect(File).to exist(adapter_file),
|
|
43
|
+
"#{module_name} has no #{adapter_file} to customize"
|
|
44
|
+
|
|
45
|
+
expect(File.read(adapter_file)).to include(module_name),
|
|
46
|
+
"#{module_name} is not wired into its adapter"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Processing model §Errors and loud degradation (normative): pinned here.
|
|
4
|
+
|
|
5
|
+
require "spec_helper"
|
|
6
|
+
|
|
7
|
+
# The engine capability report (#493): one structured face answering
|
|
8
|
+
# what the installed binding+engine serves — queried once at attach,
|
|
9
|
+
# the replacement for the version-gate-constant class. Only
|
|
10
|
+
# runtime-variable faces appear; anything the floor makes
|
|
11
|
+
# unconditional is absent by design.
|
|
12
|
+
RSpec.describe "engine capability report" do
|
|
13
|
+
it "answers for leptris with the engine version and known faces" do
|
|
14
|
+
caps = Moxml::Adapter::Leptris.capabilities
|
|
15
|
+
expect(caps).to be_frozen
|
|
16
|
+
expect(caps[:engine_version]).to match(/\A1\.\d+\.\d+/)
|
|
17
|
+
expect(caps.keys).to include(
|
|
18
|
+
:native_read_layer, :native_plan_structs, :native_bulk_sax_records,
|
|
19
|
+
:native_document_parts, :xsd, :relaxng, :xslt, :digest
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "reports only booleans beyond the version" do
|
|
24
|
+
caps = Moxml::Adapter::Leptris.capabilities
|
|
25
|
+
caps.except(:engine_version).each_value do |value|
|
|
26
|
+
expect(value).to eql(true).or eql(false)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "keeps the unwound internal gates out of the report" do
|
|
31
|
+
caps = Moxml::Adapter::Leptris.capabilities
|
|
32
|
+
expect(caps.keys).not_to include(
|
|
33
|
+
:prefixed_attr_predicates_native, :libxml2_layout_parity,
|
|
34
|
+
:indent_unit_supported, :element_unit_comments
|
|
35
|
+
)
|
|
36
|
+
expect(caps[:xsd]).to be(true)
|
|
37
|
+
expect(caps[:xslt]).to be(true)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "is memoized — repeated queries answer the same frozen object" do
|
|
41
|
+
expect(Moxml::Adapter::Leptris.capabilities)
|
|
42
|
+
.to equal(Moxml::Adapter::Leptris.capabilities)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "answers nil on adapters without a capability story" do
|
|
46
|
+
expect(Moxml::Adapter::Base.capabilities).to be_nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# The registry's extension contract (#494): adding an adapter is the
|
|
6
|
+
# documented trio — one AVAILABLE_ADAPTERS entry, one requireable
|
|
7
|
+
# adapter file, one Base subclass. The dispatch is open for extension:
|
|
8
|
+
# this spec walks the registry mechanically so a new adapter that
|
|
9
|
+
# skips any leg fails here, not in a consumer.
|
|
10
|
+
RSpec.describe "Adapter registry extension contract" do
|
|
11
|
+
it "loads every registered adapter through the public face" do
|
|
12
|
+
Moxml::Adapter::AVAILABLE_ADAPTERS.each do |name|
|
|
13
|
+
adapter = Moxml::Adapter.load(name)
|
|
14
|
+
expect(adapter).not_to be_nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "resolves every registered adapter to an Adapter::Base subclass" do
|
|
19
|
+
Moxml::Adapter::AVAILABLE_ADAPTERS.each do |name|
|
|
20
|
+
adapter = Moxml::Adapter.load(name)
|
|
21
|
+
expect(adapter).to be <= Moxml::Adapter::Base
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "answers available? truthfully for every registered adapter" do
|
|
26
|
+
Moxml::Adapter::AVAILABLE_ADAPTERS.each do |name|
|
|
27
|
+
expect(Moxml::Adapter.available?(name)).to be(true)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "rejects unregistered names before any require runs" do
|
|
32
|
+
expect do
|
|
33
|
+
Moxml::Adapter.load(:definitely_not_an_adapter)
|
|
34
|
+
end.to raise_error(Moxml::AdapterError, /not available on this platform/)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "keeps the deprecated adapters inside the registry with guidance" do
|
|
38
|
+
described = Moxml::Adapter::DEPRECATED_ADAPTERS
|
|
39
|
+
expect(described.keys).to all(satisfy { |name| Moxml::Adapter::AVAILABLE_ADAPTERS.include?(name) })
|
|
40
|
+
described.each_value do |guidance|
|
|
41
|
+
expect(guidance).to match(/:nokogiri|:leptris/)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# The customized_* layer's doctrine (#495): each namespace module is
|
|
6
|
+
# either a tracked shim (an engine gap with a stated resolution) or an
|
|
7
|
+
# adapter-fate case (dies with its deprecated adapter). A Customized*
|
|
8
|
+
# file exists only when its header says which — the record is
|
|
9
|
+
# checkable, not folklore.
|
|
10
|
+
RSpec.describe "customized adapter layer lifecycle" do
|
|
11
|
+
def customized_files
|
|
12
|
+
Dir["lib/moxml/adapter/customized_*.rb"]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "has customized namespaces to govern" do
|
|
16
|
+
expect(customized_files).not_to be_empty
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "cites its lifecycle in every module header" do
|
|
20
|
+
customized_files.each do |path|
|
|
21
|
+
header = File.readlines(path).first(30).join
|
|
22
|
+
expect(header).to match(/#\d{3}/),
|
|
23
|
+
"#{path} carries no lifecycle citation (#495)"
|
|
24
|
+
expect(header).to match(/Lifecycle record|no native representation/),
|
|
25
|
+
"#{path} header does not state its lifecycle"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "marks adapter-fate cases as deprecated or Opal-bound" do
|
|
30
|
+
adapter_fate = customized_files.reject { |p| p.include?("leptris") }
|
|
31
|
+
expect(adapter_fate).not_to be_empty
|
|
32
|
+
adapter_fate.each do |path|
|
|
33
|
+
header = File.readlines(path).first(30).join
|
|
34
|
+
expect(header).to match(/moxml#491|moxml#489/),
|
|
35
|
+
"#{path} is an adapter-fate case but cites neither " \
|
|
36
|
+
"its deprecation (#491) nor the Opal removal (#489)"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "keeps the tracked shim pointed at its resolution" do
|
|
41
|
+
header = File.readlines("lib/moxml/adapter/customized_leptris.rb")
|
|
42
|
+
.first(30).join
|
|
43
|
+
expect(header).to include("tracked shim"), "the leptris shim must say so"
|
|
44
|
+
expect(header).to include("dissolve into Base"),
|
|
45
|
+
"the leptris shim must state its end state"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Processing model §Validation (normative): pinned here.
|
|
4
|
+
|
|
5
|
+
require "spec_helper"
|
|
6
|
+
|
|
7
|
+
# The conformance dataset is the model's builtin-lexical answers AS
|
|
8
|
+
# DATA (#496): the Ruby suite pins every row here, and the exported
|
|
9
|
+
# JSON (rake conformance:export) is what moxml-rs and moxml-ts run.
|
|
10
|
+
# A row that fails here breaks the cross-language contract, not just
|
|
11
|
+
# this implementation.
|
|
12
|
+
RSpec.describe "builtin lexical conformance dataset" do
|
|
13
|
+
def valid_lexical?(type, lexical)
|
|
14
|
+
Moxml::XSD.builtin_valid?(Moxml.new(:leptris), type, lexical)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "carries the dataset" do
|
|
18
|
+
expect(Moxml::XSD::BuiltinLexical::CONFORMANCE_CASES.size).to be >= 80
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "answers every row exactly as the dataset expects" do
|
|
22
|
+
Moxml::XSD::BuiltinLexical::CONFORMANCE_CASES.each do |type, lexical, expected|
|
|
23
|
+
answer = valid_lexical?(type, lexical)
|
|
24
|
+
expect(answer).to eql(expected),
|
|
25
|
+
"#{type} #{lexical.inspect}: got #{answer.inspect}, " \
|
|
26
|
+
"dataset expects #{expected.inspect}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "keeps every dataset type in the table" do
|
|
31
|
+
Moxml::XSD::BuiltinLexical::CONFORMANCE_CASES.each do |type, _lexical, _expected|
|
|
32
|
+
expect do
|
|
33
|
+
valid_lexical?(type, "")
|
|
34
|
+
end.not_to raise_error
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -113,6 +113,10 @@ module ModelCoverage
|
|
|
113
113
|
section: "Errors and loud degradation",
|
|
114
114
|
pin: "spec/consistency/loud_degradation_spec.rb",
|
|
115
115
|
},
|
|
116
|
+
"engine capability report" => {
|
|
117
|
+
section: "Errors and loud degradation",
|
|
118
|
+
pin: "spec/moxml/adapter_capabilities_spec.rb",
|
|
119
|
+
},
|
|
116
120
|
}.freeze
|
|
117
121
|
|
|
118
122
|
# Normative sections that are not face families (meta/apparatus).
|
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.
|
|
4
|
+
version: 0.5.173
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -53,6 +53,7 @@ files:
|
|
|
53
53
|
- bin/console
|
|
54
54
|
- bin/generate-model-coverage
|
|
55
55
|
- bin/setup
|
|
56
|
+
- conformance/moxml-conformance.json
|
|
56
57
|
- data/w3c_entities.json
|
|
57
58
|
- docs/ENTITY_SUPPORT_FOR_LUTAML_MODEL.md
|
|
58
59
|
- docs/Gemfile
|
|
@@ -479,6 +480,7 @@ files:
|
|
|
479
480
|
- spec/moxml/adapter/README.md
|
|
480
481
|
- spec/moxml/adapter/base_spec.rb
|
|
481
482
|
- spec/moxml/adapter/columnar_invalidation_spec.rb
|
|
483
|
+
- spec/moxml/adapter/customized_lifecycle_audit_spec.rb
|
|
482
484
|
- spec/moxml/adapter/entity_restoration_spec.rb
|
|
483
485
|
- spec/moxml/adapter/headed_ox_spec.rb
|
|
484
486
|
- spec/moxml/adapter/leptris_adoption_spec.rb
|
|
@@ -512,7 +514,9 @@ files:
|
|
|
512
514
|
- spec/moxml/adapter/rexml_spec.rb
|
|
513
515
|
- spec/moxml/adapter/shared_examples/.gitkeep
|
|
514
516
|
- spec/moxml/adapter/shared_examples/adapter_contract.rb
|
|
517
|
+
- spec/moxml/adapter_capabilities_spec.rb
|
|
515
518
|
- spec/moxml/adapter_deprecation_spec.rb
|
|
519
|
+
- spec/moxml/adapter_registry_spec.rb
|
|
516
520
|
- spec/moxml/adapter_spec.rb
|
|
517
521
|
- spec/moxml/allocation_benchmark_spec.rb
|
|
518
522
|
- spec/moxml/allocation_guard_spec.rb
|
|
@@ -538,6 +542,7 @@ files:
|
|
|
538
542
|
- spec/moxml/config_spec.rb
|
|
539
543
|
- spec/moxml/context_spec.rb
|
|
540
544
|
- spec/moxml/css_spec.rb
|
|
545
|
+
- spec/moxml/customized_lifecycle_spec.rb
|
|
541
546
|
- spec/moxml/cycle_rejection_spec.rb
|
|
542
547
|
- spec/moxml/declaration_preservation_spec.rb
|
|
543
548
|
- spec/moxml/declaration_spec.rb
|
|
@@ -634,6 +639,7 @@ files:
|
|
|
634
639
|
- spec/moxml/xpath_capabilities_spec.rb
|
|
635
640
|
- spec/moxml/xpath_spec.rb
|
|
636
641
|
- spec/moxml/xsd_builtin_lexical_spec.rb
|
|
642
|
+
- spec/moxml/xsd_conformance_cases_spec.rb
|
|
637
643
|
- spec/moxml/xsd_engine_meta_spec.rb
|
|
638
644
|
- spec/moxml/xsd_error_contract_spec.rb
|
|
639
645
|
- spec/moxml/xsd_handle_mismatch_spec.rb
|