moxml 0.5.161 → 0.5.162

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: 39e75ce66c66f3b1d5c72e8ba103dd2a4e6a2eb14d3e7fc9b016672e35a8759b
4
- data.tar.gz: d502f9d3c5c739d6d86c68d79d2486d40b1a85747d3ef5b8503d1f1e9fc0d17c
3
+ metadata.gz: e3ff9c9a02aad66036e51b20f9dd72fb17adb09b51dbe3950bb5a5174a2f2158
4
+ data.tar.gz: b4924b020e3b4738e08197d918594df3269d5206fda86ab0f582b27e801a1dbf
5
5
  SHA512:
6
- metadata.gz: 9ae62f4b5b1cef0b4f84c0a12b640292d762d110004dc0fd2bbadf4af5a374ace336d30e9aef7cd9e8e151590de5b67f07d9cf1e31afc7e82b8de1b2f01ebda2
7
- data.tar.gz: 819a5bade9e79d666087a4a302484e0f88653f3a77db26585c2d370c70cd388e774b685bf5499ee1dbff2cb7307f5476aee3153acbf098db61e6e0c3bb010fcb
6
+ metadata.gz: dcb4225b3f662a656232b4e4bccdaefeb261a186d9c01d5369ee54ec28829678202e69349372842e470dcd21bed702f6f28c0e58dc9e45b6c262fffab1ed937a
7
+ data.tar.gz: 22fa41a31b5a8541e2c3f5fa2c8eb088975f173902ff8c046e325ec55c28246e3c459df5e49d004fb2e89ea1d1d8f9adb841d71cae8e4fe8bfaea14cd25c5d7c
data/benchmark/README.md CHANGED
@@ -92,16 +92,16 @@ rewrites this block and `docs/_pages/performance.adoc`):
92
92
  <!-- SCOREBOARD:BEGIN -->
93
93
  | Row | Ratio | Kind | Status |
94
94
  | --- | ----- | ---- | ------ |
95
- | `parse` | 3.59x | parity | met |
96
- | `serialize` | 1.83x | parity | met |
97
- | `xpath //field (count)` | 4.79x | parity | met |
98
- | `xpath //field (each)` | 0.44x | structural | tracked (below parity) |
99
- | `attr pairs listing` | 7.46x | parity | met |
100
- | `build add_element` | 0.57x | structural | tracked (below parity) |
101
- | `walk+read (warm)` | 0.64x | structural | tracked (below parity) |
102
- | `walk+read (cold)` | 0.17x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression) |
103
- | `children recursion (cold)` | 0.13x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression) |
104
- | `plan records (typed)` | 1.14x | data | informational |
95
+ | `parse` | 4.61x | parity | met |
96
+ | `serialize` | 1.65x | parity | met |
97
+ | `xpath //field (count)` | 3.39x | parity | met |
98
+ | `xpath //field (each)` | 0.34x | structural | tracked (below parity) |
99
+ | `attr pairs listing` | 8.48x | parity | met |
100
+ | `build add_element` | 0.74x | structural | tracked (below parity) |
101
+ | `walk+read (warm)` | 0.54x | structural | tracked (below parity) |
102
+ | `walk+read (cold)` | 0.37x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression) |
103
+ | `children recursion (cold)` | 0.45x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression) |
104
+ | `plan records (typed)` | 1.13x | data | informational |
105
105
  <!-- SCOREBOARD:END -->
106
106
 
107
107
  The open rows are the known structural gap: every node the facade
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "protocol": {
3
- "measured": "2026-10-23T15:54:45Z",
3
+ "measured": "2026-10-24T05:26:53Z",
4
4
  "ruby": "3.3.13",
5
5
  "adapter": "leptris",
6
6
  "adapter_version": "1.9.381.0",
@@ -8,16 +8,16 @@
8
8
  "reps": 9,
9
9
  "warmup": 2,
10
10
  "clock": "CLOCK_PROCESS_CPUTIME_ID",
11
- "load": 1.87
11
+ "load": 1.74
12
12
  },
13
13
  "rows": [
14
14
  {
15
15
  "row": "parse",
16
16
  "kind": "parity",
17
17
  "parity": true,
18
- "baseline_us": 1027.8,
19
- "candidate_us": 286.6,
20
- "ratio": 3.586,
18
+ "baseline_us": 1075.7,
19
+ "candidate_us": 233.6,
20
+ "ratio": 4.606,
21
21
  "baseline_allocs": 7,
22
22
  "candidate_allocs": 18
23
23
  },
@@ -25,9 +25,9 @@
25
25
  "row": "serialize",
26
26
  "kind": "parity",
27
27
  "parity": true,
28
- "baseline_us": 517.0,
29
- "candidate_us": 281.9,
30
- "ratio": 1.834,
28
+ "baseline_us": 457.0,
29
+ "candidate_us": 277.6,
30
+ "ratio": 1.646,
31
31
  "baseline_allocs": 30,
32
32
  "candidate_allocs": 14
33
33
  },
@@ -35,9 +35,9 @@
35
35
  "row": "xpath //field (count)",
36
36
  "kind": "parity",
37
37
  "parity": true,
38
- "baseline_us": 121.9,
39
- "candidate_us": 25.4,
40
- "ratio": 4.791,
38
+ "baseline_us": 64.4,
39
+ "candidate_us": 19.0,
40
+ "ratio": 3.387,
41
41
  "baseline_allocs": 13,
42
42
  "candidate_allocs": 8
43
43
  },
@@ -45,9 +45,9 @@
45
45
  "row": "xpath //field (each)",
46
46
  "kind": "structural",
47
47
  "parity": false,
48
- "baseline_us": 361.9,
49
- "candidate_us": 822.7,
50
- "ratio": 0.44,
48
+ "baseline_us": 256.4,
49
+ "candidate_us": 744.4,
50
+ "ratio": 0.344,
51
51
  "baseline_allocs": 1213,
52
52
  "candidate_allocs": 10
53
53
  },
@@ -55,9 +55,9 @@
55
55
  "row": "attr pairs listing",
56
56
  "kind": "parity",
57
57
  "parity": true,
58
- "baseline_us": 502.0,
59
- "candidate_us": 67.3,
60
- "ratio": 7.458,
58
+ "baseline_us": 503.6,
59
+ "candidate_us": 59.4,
60
+ "ratio": 8.484,
61
61
  "baseline_allocs": 3300,
62
62
  "candidate_allocs": 0
63
63
  },
@@ -65,19 +65,19 @@
65
65
  "row": "build add_element",
66
66
  "kind": "structural",
67
67
  "parity": false,
68
- "baseline_us": 5532.8,
69
- "candidate_us": 9658.2,
70
- "ratio": 0.573,
68
+ "baseline_us": 5607.1,
69
+ "candidate_us": 7620.4,
70
+ "ratio": 0.736,
71
71
  "baseline_allocs": 20358,
72
- "candidate_allocs": 11363
72
+ "candidate_allocs": 10163
73
73
  },
74
74
  {
75
75
  "row": "walk+read (warm)",
76
76
  "kind": "structural",
77
77
  "parity": false,
78
- "baseline_us": 1805.4,
79
- "candidate_us": 2797.9,
80
- "ratio": 0.645,
78
+ "baseline_us": 1631.1,
79
+ "candidate_us": 3005.5,
80
+ "ratio": 0.543,
81
81
  "baseline_allocs": 4503,
82
82
  "candidate_allocs": 2
83
83
  },
@@ -85,9 +85,9 @@
85
85
  "row": "walk+read (cold)",
86
86
  "kind": "structural",
87
87
  "parity": false,
88
- "baseline_us": 2938.6,
89
- "candidate_us": 17354.2,
90
- "ratio": 0.169,
88
+ "baseline_us": 3094.4,
89
+ "candidate_us": 8308.1,
90
+ "ratio": 0.372,
91
91
  "baseline_allocs": 6011,
92
92
  "candidate_allocs": 10232
93
93
  },
@@ -95,9 +95,9 @@
95
95
  "row": "children recursion (cold)",
96
96
  "kind": "structural",
97
97
  "parity": false,
98
- "baseline_us": 3346.5,
99
- "candidate_us": 25949.4,
100
- "ratio": 0.129,
98
+ "baseline_us": 3414.5,
99
+ "candidate_us": 7574.2,
100
+ "ratio": 0.451,
101
101
  "baseline_allocs": 5711,
102
102
  "candidate_allocs": 8732
103
103
  },
@@ -105,9 +105,9 @@
105
105
  "row": "plan records (typed)",
106
106
  "kind": "data",
107
107
  "parity": false,
108
- "baseline_us": 2901.1,
109
- "candidate_us": 2554.9,
110
- "ratio": 1.136,
108
+ "baseline_us": 3056.3,
109
+ "candidate_us": 2700.7,
110
+ "ratio": 1.132,
111
111
  "baseline_allocs": 8112,
112
112
  "candidate_allocs": 13232
113
113
  }
@@ -41,6 +41,7 @@ Generated by `bundle exec rake docs:coverage` from the coverage matrix and the d
41
41
  | materialization | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent
42
42
  | validation | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent
43
43
  | validation under-detections | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent
44
+ | validation version reporting | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent
44
45
  | loud capability contracts | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent | equivalent
45
46
  |===
46
47
 
@@ -14,21 +14,21 @@ the marked block below from a live measurement; see
14
14
  // SCOREBOARD:BEGIN
15
15
  Generated by `SCORE_PUBLISH=1 bundle exec ruby benchmark/scoreboard.rb`. Protocol: CPU-time medians of an interleaved A/B run (raw nokogiri vs moxml on leptris); the ratio is baseline / candidate, so > 1.0 means the facade is faster. Warmups discarded, GC between samples.
16
16
 
17
- Measurement: Ruby 3.3.13, leptris 1.9.381.0, nokogiri 1.19.4, 2026-10-23T15:54:45Z, 1-minute load 1.87, 9 repetitions.
17
+ Measurement: Ruby 3.3.13, leptris 1.9.381.0, nokogiri 1.19.4, 2026-10-24T05:26:53Z, 1-minute load 1.74, 9 repetitions.
18
18
 
19
19
  [cols="2,1,1,1",options="header"]
20
20
  |===
21
21
  | Row | Ratio | Kind | Status
22
- | `parse` | 3.59x | parity | met
23
- | `serialize` | 1.83x | parity | met
24
- | `xpath //field (count)` | 4.79x | parity | met
25
- | `xpath //field (each)` | 0.44x | structural | tracked (below parity)
26
- | `attr pairs listing` | 7.46x | parity | met
27
- | `build add_element` | 0.57x | structural | tracked (below parity)
28
- | `walk+read (warm)` | 0.64x | structural | tracked (below parity)
29
- | `walk+read (cold)` | 0.17x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression)
30
- | `children recursion (cold)` | 0.13x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression)
31
- | `plan records (typed)` | 1.14x | data | informational
22
+ | `parse` | 4.61x | parity | met
23
+ | `serialize` | 1.65x | parity | met
24
+ | `xpath //field (count)` | 3.39x | parity | met
25
+ | `xpath //field (each)` | 0.34x | structural | tracked (below parity)
26
+ | `attr pairs listing` | 8.48x | parity | met
27
+ | `build add_element` | 0.74x | structural | tracked (below parity)
28
+ | `walk+read (warm)` | 0.54x | structural | tracked (below parity)
29
+ | `walk+read (cold)` | 0.37x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression)
30
+ | `children recursion (cold)` | 0.45x | structural | tracked (below parity), paused: leptris-ruby#527 (1.9.380 crossing regression)
31
+ | `plan records (typed)` | 1.13x | data | informational
32
32
  |===
33
33
 
34
34
  *Parity rows* must stay at or above the 0.95 measurement floor. *Structural rows* are measured and trend-locked (10% regression tolerance) while their gaps remain open: per-node wrapper minting costs (#312 endgame) and engine construction. *Data API* rows are informational.
@@ -255,7 +255,7 @@ semantics.
255
255
 
256
256
  === Validation
257
257
 
258
- Pins:: `spec/moxml/xsd_spec.rb`, `spec/moxml/xsd_underdetection_spec.rb`
258
+ Pins:: `spec/moxml/xsd_spec.rb`, `spec/moxml/xsd_underdetection_spec.rb`, `spec/moxml/xsd_version_spec.rb`
259
259
 
260
260
  XSD validation through engines that ship a validator (libxml2;
261
261
  leptris tier-1: recognized roots, one-level content descent, lexical
@@ -265,7 +265,11 @@ where it does not; `[]` means valid. Documents outside the engine's
265
265
  scope validate laxly, except that strict `xs:any` /
266
266
  `xs:anyAttribute` wildcard matches and `xsi:nil` are re-checked from
267
267
  the schema source on every adapter — the re-check can only
268
- under-report, never false-report. Unsupported adapters raise
268
+ under-report, never false-report. A compiled schema reports the
269
+ version its source declares: root `vc:minVersion="1.1"` scopes the
270
+ document to 1.1, anything else is 1.0 (consumers scope 1.0-only
271
+ checks with it; applying 1.1 semantics is the engine-side program).
272
+ Unsupported adapters raise
269
273
  `Moxml::NotImplementedError` at compile; `Moxml::XSD.supported?`
270
274
  answers without raising. RELAX NG rides engines with an RNG face
271
275
  (the same shapes).
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.161"
4
+ VERSION = "0.5.162"
5
5
  end
@@ -67,7 +67,11 @@ module Moxml
67
67
  :declared_attributes, :any_attribute)
68
68
  SchemaIndex = Struct.new(:target_namespace, :element_default,
69
69
  :attribute_default, :elements,
70
- :attributes, :contents)
70
+ :attributes, :contents, :version)
71
+
72
+ # The XSD 1.1 version-tagging namespace (Structures §C.3):
73
+ # vc:minVersion / vc:maxVersion gate 1.1 constructs.
74
+ VC_NS = "http://www.w3.org/2001/XMLSchema-versioning"
71
75
 
72
76
  class << self
73
77
  # Index one schema document. Returns nil when the source
@@ -81,7 +85,7 @@ module Moxml
81
85
  root["targetNamespace"].to_s,
82
86
  root["elementFormDefault"] == "qualified",
83
87
  root["attributeFormDefault"] == "qualified",
84
- {}, {}, {}
88
+ {}, {}, {}, schema_version(root)
85
89
  )
86
90
  child_elements(root).each do |decl|
87
91
  case decl.name
@@ -94,6 +98,20 @@ module Moxml
94
98
  nil
95
99
  end
96
100
 
101
+ # The effective schema version declared at the root
102
+ # (#460 item 2): vc:minVersion="1.1" on <xs:schema> scopes
103
+ # the document to 1.1 semantics; anything else reports
104
+ # 1.0. Conditional (subtree-level) vc: evaluation is the
105
+ # engine's conditional-assignment work — the facade reports
106
+ # the root declaration only.
107
+ def schema_version(root)
108
+ declared = root.attributes.find do |attribute|
109
+ attribute.namespace&.uri == VC_NS &&
110
+ attribute.name == "minVersion"
111
+ end&.value
112
+ declared.to_s.start_with?("1.1") ? "1.1" : "1.0"
113
+ end
114
+
97
115
  # Post-validation findings for one instance document.
98
116
  def findings(doc, index)
99
117
  return [] unless index
data/lib/moxml/xsd.rb CHANGED
@@ -175,6 +175,15 @@ module Moxml
175
175
  @context.config.adapter.xsd_declarations(@handle)
176
176
  end
177
177
 
178
+ # The effective schema version the source declares (#460 item
179
+ # 2): "1.1" when the root carries vc:minVersion="1.1", else
180
+ # "1.0". Consumers (lutaml-xsd) scope 1.0-only checks with
181
+ # it; the engine's application of 1.1 semantics is the
182
+ # engine-side program.
183
+ def version
184
+ @rules_index ? @rules_index.version : "1.0"
185
+ end
186
+
178
187
  # Deterministic drop (#362.3): true when the adapter freed
179
188
  # the engine-side schema NOW; false when the adapter can only
180
189
  # wait for GC (documented per adapter). After a true release
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # Processing model §Validation (normative): pinned here.
6
+
7
+ # #460 item 2: a compiled schema reports the effective version its
8
+ # source declares — vc:minVersion="1.1" on the root scopes the
9
+ # document to 1.1 semantics; anything else reports 1.0. The
10
+ # detection is namespace-based (vc: is a convention, not a
11
+ # requirement) and reads the ROOT declaration; conditional
12
+ # (subtree-level) vc: evaluation is the engine's program.
13
+ RSpec.describe "Moxml::XSD::Schema#version (#460 item 2)" do
14
+ %i[nokogiri leptris].each do |adapter_name|
15
+ describe "on #{adapter_name}" do
16
+ let(:ctx) { Moxml.new(adapter_name) }
17
+
18
+ before do
19
+ skip "#{adapter_name} requires an XSD-capable engine" unless
20
+ Moxml::XSD.supported?(ctx)
21
+ end
22
+
23
+ it "reports 1.1 when the root declares vc:minVersion=1.1" do
24
+ schema = ctx.xsd(<<~XSD)
25
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
26
+ xmlns:vc="http://www.w3.org/2001/XMLSchema-versioning"
27
+ vc:minVersion="1.1">
28
+ <xs:element name="note" type="xs:string"/>
29
+ </xs:schema>
30
+ XSD
31
+ expect(schema.version).to eq("1.1")
32
+ end
33
+
34
+ it "detects the versioning namespace, not the prefix" do
35
+ schema = ctx.xsd(<<~XSD)
36
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
37
+ xmlns:vcx="http://www.w3.org/2001/XMLSchema-versioning"
38
+ vcx:minVersion="1.1">
39
+ <xs:element name="note" type="xs:string"/>
40
+ </xs:schema>
41
+ XSD
42
+ expect(schema.version).to eq("1.1")
43
+ end
44
+
45
+ it "reports 1.0 without a root version declaration" do
46
+ schema = ctx.xsd(<<~XSD)
47
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
48
+ <xs:element name="note" type="xs:string"/>
49
+ </xs:schema>
50
+ XSD
51
+ expect(schema.version).to eq("1.0")
52
+ end
53
+
54
+ it "reports 1.0 for an explicit root vc:minVersion=1.0" do
55
+ schema = ctx.xsd(<<~XSD)
56
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
57
+ xmlns:vc="http://www.w3.org/2001/XMLSchema-versioning"
58
+ vc:minVersion="1.0">
59
+ <xs:element name="note" type="xs:string"/>
60
+ </xs:schema>
61
+ XSD
62
+ expect(schema.version).to eq("1.0")
63
+ end
64
+
65
+ it "reports 1.0 when only a construct carries vc:minVersion" do
66
+ schema = ctx.xsd(<<~XSD)
67
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
68
+ xmlns:vc="http://www.w3.org/2001/XMLSchema-versioning">
69
+ <xs:element name="note">
70
+ <xs:complexType>
71
+ <xs:sequence vc:minVersion="1.1">
72
+ <xs:element name="a"/>
73
+ </xs:sequence>
74
+ </xs:complexType>
75
+ </xs:element>
76
+ </xs:schema>
77
+ XSD
78
+ expect(schema.version).to eq("1.0")
79
+ end
80
+ end
81
+ end
82
+ end
@@ -85,6 +85,10 @@ module ModelCoverage
85
85
  section: "Validation",
86
86
  pin: "spec/moxml/xsd_underdetection_spec.rb",
87
87
  },
88
+ "validation version reporting" => {
89
+ section: "Validation",
90
+ pin: "spec/moxml/xsd_version_spec.rb",
91
+ },
88
92
  "loud capability contracts" => {
89
93
  section: "Errors and loud degradation",
90
94
  pin: "spec/consistency/loud_degradation_spec.rb",
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.161
4
+ version: 0.5.162
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -634,6 +634,7 @@ files:
634
634
  - spec/moxml/xsd_release_spec.rb
635
635
  - spec/moxml/xsd_spec.rb
636
636
  - spec/moxml/xsd_underdetection_spec.rb
637
+ - spec/moxml/xsd_version_spec.rb
637
638
  - spec/moxml/xslt/stylesheet_spec.rb
638
639
  - spec/performance/README.md
639
640
  - spec/performance/benchmark_spec.rb