lutaml-model 0.8.119 → 0.8.121
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/.github/workflows/dependent-repos-tools.json +9 -0
- data/.github/workflows/dependent-repos.json +1 -6
- data/.github/workflows/dependent-tests.yml +19 -0
- data/lib/lutaml/json/adapter/yeptris_adapter.rb +6 -4
- data/lib/lutaml/model/union.rb +10 -7
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/schema/xsd/keyref.rb +1 -0
- data/lib/lutaml/yaml/adapter/yeptris_adapter.rb +6 -4
- data/spec/lutaml/model/union_attribute_spec.rb +51 -0
- data/spec/lutaml/model/yeptris_error_parity_spec.rb +11 -1
- data/spec/lutaml/model/yeptris_native_detection_spec.rb +6 -2
- data/spec/lutaml/xml/schema/xsd/keyref_refer_spec.rb +21 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b4c137e1f669303a163bde341097dae39b9171b3f9c65b2a8dba97fff0ac6e5
|
|
4
|
+
data.tar.gz: a9c13e332f7228b0d45c1a2b24ce9cbe032c7d3b9a06b8585b54c30bd78fcfdc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 51cad246d238f97af6becc7e9f90409d21152e60ff136658832e3440656a13f02b18693f8683605e0831738a2fb707490d137a2a47769121a2139aa845c927f6
|
|
7
|
+
data.tar.gz: a7be0c13e87ac6d37a61044bdea091f7d49a21ad2bb75cd206424456c9d1a77a13ba895b9f2d5d7b6ae6c45fe64b71ae493cd4dab444486641ebbc7cc6294a08
|
|
@@ -14,22 +14,17 @@
|
|
|
14
14
|
"lutaml/unibuf",
|
|
15
15
|
"lutaml/xmi",
|
|
16
16
|
"metanorma/atmospheric",
|
|
17
|
-
"metanorma/docbook",
|
|
18
|
-
"metanorma/metanorma-cli",
|
|
19
17
|
"metanorma/modspec-ruby",
|
|
20
18
|
"metanorma/niso-jats",
|
|
21
19
|
"metanorma/prosereflect",
|
|
22
20
|
"metanorma/revix",
|
|
23
|
-
"metanorma/rfcxml",
|
|
24
21
|
"metanorma/sts-ruby",
|
|
25
|
-
"metanorma/uniword",
|
|
26
22
|
"plurimath/mml",
|
|
27
23
|
"plurimath/plurimath",
|
|
28
24
|
"relaton/ieee-idams",
|
|
29
25
|
"relaton/loc_mods",
|
|
30
26
|
"relaton/w3c_api",
|
|
31
|
-
"ukiryu/ukiryu",
|
|
32
27
|
"unitsml/unitsdb-ruby",
|
|
33
28
|
"unitsml/unitsml-ruby"
|
|
34
29
|
]
|
|
35
|
-
}
|
|
30
|
+
}
|
|
@@ -18,10 +18,29 @@ on:
|
|
|
18
18
|
types: [ release-passed ]
|
|
19
19
|
|
|
20
20
|
jobs:
|
|
21
|
+
# Most dependents are pure data/format gems: their suites invoke no
|
|
22
|
+
# external tools, so skipping the tool install removes the Windows
|
|
23
|
+
# Chocolatey flake surface (choco CDN 504s killed cells pre-rspec,
|
|
24
|
+
# e.g. the ukiryu Windows leg) for the majority of the matrix.
|
|
21
25
|
rake:
|
|
22
26
|
uses: metanorma/ci/.github/workflows/dependent-rake.yml@main
|
|
23
27
|
with:
|
|
24
28
|
command: bundle exec rspec
|
|
29
|
+
repos-json-file: .github/workflows/dependent-repos.json
|
|
30
|
+
after-setup-ruby: |
|
|
31
|
+
if [ -f frontend/package.json ]; then cd frontend && npm install && npm run build; fi
|
|
32
|
+
secrets:
|
|
33
|
+
pat_token: ${{ secrets.LUTAML_CI_PAT_TOKEN }}
|
|
34
|
+
|
|
35
|
+
# Dependents whose suites invoke the tools: ukiryu wraps
|
|
36
|
+
# inkscape/imagemagick/ghostscript and raises if absent, and its
|
|
37
|
+
# smoke suite exercises exiftool, yq and ffmpeg too; the metanorma
|
|
38
|
+
# renderers run full document renders.
|
|
39
|
+
rake-with-tools:
|
|
40
|
+
uses: metanorma/ci/.github/workflows/dependent-rake.yml@main
|
|
41
|
+
with:
|
|
42
|
+
command: bundle exec rspec
|
|
43
|
+
repos-json-file: .github/workflows/dependent-repos-tools.json
|
|
25
44
|
setup-tools: 'inkscape,ghostscript,exiftool,ffmpeg,imagemagick,yq'
|
|
26
45
|
after-setup-ruby: |
|
|
27
46
|
if [ -f frontend/package.json ]; then cd frontend && npm install && npm run build; fi
|
|
@@ -32,9 +32,11 @@ module Lutaml
|
|
|
32
32
|
# constant (the poison-process state the gem documents)
|
|
33
33
|
# passes const_defined? and require while every parse fails,
|
|
34
34
|
# and the native parse error then surfaces on valid input.
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
35
|
+
# Any failure — missing native, engine error, or a binding and
|
|
36
|
+
# native binary out of sync (NameError on a missing FFI surface,
|
|
37
|
+
# yeptris 0.6.34.2 x64-mingw-ucrt) — reports false instead of
|
|
38
|
+
# raising, so optional-engine callers (detection) gate on it and
|
|
39
|
+
# fall back to the standard lane.
|
|
38
40
|
def self.available?
|
|
39
41
|
require_engine
|
|
40
42
|
native_ready?
|
|
@@ -48,7 +50,7 @@ module Lutaml
|
|
|
48
50
|
@native_ready = begin
|
|
49
51
|
::Yeptris::JSON.load('{"native_probe": 1}')
|
|
50
52
|
true
|
|
51
|
-
rescue
|
|
53
|
+
rescue StandardError
|
|
52
54
|
false
|
|
53
55
|
end
|
|
54
56
|
end
|
data/lib/lutaml/model/union.rb
CHANGED
|
@@ -154,12 +154,15 @@ module Lutaml
|
|
|
154
154
|
member.is_a?(::Class) && member.include?(Serialize)
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
-
# Structural
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
157
|
+
# Structural selection: at least one input key maps to one of the
|
|
158
|
+
# member's mapped fields. Keys no rule claims are ignored exactly
|
|
159
|
+
# as they are when the same hash reaches the model outside a
|
|
160
|
+
# union — extension keys (x-** vendor keywords, forward-compatible
|
|
161
|
+
# vocabularies) must not defeat dispatch (#987). Once selected,
|
|
162
|
+
# field values cast leniently via the member's normal path. An
|
|
163
|
+
# existing member instance conforms as-is, keeping conformance
|
|
164
|
+
# idempotent — values can re-enter casting (e.g. a value
|
|
165
|
+
# transformer builds the member before the cast runs).
|
|
163
166
|
def conform_model(member, value, format, register)
|
|
164
167
|
return value if value.is_a?(member)
|
|
165
168
|
|
|
@@ -167,7 +170,7 @@ module Lutaml
|
|
|
167
170
|
return :no_match if keys.nil? || keys.empty?
|
|
168
171
|
|
|
169
172
|
field_names = member_field_names(member, format, register)
|
|
170
|
-
return :no_match unless keys.
|
|
173
|
+
return :no_match unless keys.any? do |key|
|
|
171
174
|
field_names.include?(key)
|
|
172
175
|
end
|
|
173
176
|
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -46,9 +46,11 @@ module Lutaml
|
|
|
46
46
|
# constant (the poison-process state the gem documents)
|
|
47
47
|
# passes const_defined? and require while every parse fails,
|
|
48
48
|
# and the native parse error then surfaces on valid input.
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
49
|
+
# Any failure — missing native, engine error, or a binding and
|
|
50
|
+
# native binary out of sync (NameError on a missing FFI surface,
|
|
51
|
+
# yeptris 0.6.34.2 x64-mingw-ucrt) — reports false instead of
|
|
52
|
+
# raising, so optional-engine callers (detection) gate on it and
|
|
53
|
+
# fall back to the standard lane.
|
|
52
54
|
def self.available?
|
|
53
55
|
require_engine
|
|
54
56
|
native_ready?
|
|
@@ -63,7 +65,7 @@ module Lutaml
|
|
|
63
65
|
# rubocop:disable-next Naming/VariableNumber -- upstream schema literal
|
|
64
66
|
::Yeptris::YAML.load("native_probe: 1", schema: :compat_11)
|
|
65
67
|
true
|
|
66
|
-
rescue
|
|
68
|
+
rescue StandardError
|
|
67
69
|
false
|
|
68
70
|
end
|
|
69
71
|
end
|
|
@@ -214,6 +214,25 @@ module UnionAttributeSpec
|
|
|
214
214
|
end
|
|
215
215
|
end
|
|
216
216
|
|
|
217
|
+
# Union members for the #987 dispatch contract: an extension-carrying
|
|
218
|
+
# model (keys no rule maps must not defeat dispatch) and a holder
|
|
219
|
+
# mixing it with a scalar member.
|
|
220
|
+
class ExtendedShape < Lutaml::Model::Serializable
|
|
221
|
+
attribute :type, :string
|
|
222
|
+
|
|
223
|
+
key_value do
|
|
224
|
+
map "type", to: :type
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
class ExtendedHolder < Lutaml::Model::Serializable
|
|
229
|
+
attribute :value, [ExtendedShape, :boolean]
|
|
230
|
+
|
|
231
|
+
key_value do
|
|
232
|
+
map "value", to: :value
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
217
236
|
RSpec.describe "Union-typed attributes (issue #190)" do
|
|
218
237
|
describe "deserialization — member resolution by shape" do
|
|
219
238
|
it "resolves a scalar string to the :string member" do
|
|
@@ -646,6 +665,38 @@ RSpec.describe "Union-typed attributes (issue #190)" do
|
|
|
646
665
|
end
|
|
647
666
|
end
|
|
648
667
|
|
|
668
|
+
describe "unmapped keys do not defeat model dispatch (#987)" do
|
|
669
|
+
# ExtendedShape / ExtendedHolder: extension-carrying objects (JSON
|
|
670
|
+
# Schema vocabularies, OpenAPI x-** keywords) carry keys no rule
|
|
671
|
+
# maps; the same hash reaches the model member fine outside a
|
|
672
|
+
# union, so it must inside one too.
|
|
673
|
+
|
|
674
|
+
it "selects the model member when mapped and unmapped keys mix" do
|
|
675
|
+
parsed = ExtendedHolder.from_json(
|
|
676
|
+
'{"value":{"type":"string","x-ext":1}}',
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
expect(parsed.value).to be_a(ExtendedShape)
|
|
680
|
+
expect(parsed.value.type).to eq("string")
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
it "still falls through when no key maps to any model member" do
|
|
684
|
+
parsed = ExtendedHolder.from_json('{"value":true}')
|
|
685
|
+
|
|
686
|
+
expect(parsed.value).to be(true)
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
it "returns nil only when no member conforms at all" do
|
|
690
|
+
holder = Class.new(Lutaml::Model::Serializable) do
|
|
691
|
+
attribute :value, [ExtendedShape, :boolean]
|
|
692
|
+
key_value { map "value", to: :value }
|
|
693
|
+
end
|
|
694
|
+
stub_const("ExtendedHolderNinetyEight", holder)
|
|
695
|
+
|
|
696
|
+
expect(holder.from_json('{"value":{"unrelated":1}}').value).to be_nil
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
|
|
649
700
|
describe "value transformers (cast idempotence)" do
|
|
650
701
|
it "keeps a model member built by transform: before the cast runs" do
|
|
651
702
|
reading = UnionAttributeSpec::TransformedReading.from_yaml(<<~YAML)
|
|
@@ -70,7 +70,17 @@ RSpec.describe "yeptris adapter error parity" do
|
|
|
70
70
|
RUBY
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
# Installed is not enough: a binding/native desync (yeptris
|
|
74
|
+
# 0.6.34.2 x64-mingw-ucrt) leaves the gem resolvable while every
|
|
75
|
+
# parse raises. The parity contract only holds when the engines
|
|
76
|
+
# actually answer a probe — detection then selects them.
|
|
77
|
+
def yeptris_usable?
|
|
78
|
+
yeptris_installed? &&
|
|
79
|
+
Lutaml::Json::Adapter::YeptrisAdapter.available? &&
|
|
80
|
+
Lutaml::Yaml::Adapter::YeptrisAdapter.available?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
before { skip "yeptris is not usable on this platform" unless yeptris_usable? }
|
|
74
84
|
|
|
75
85
|
it "prefers the yeptris adapters when the engine is installed" do
|
|
76
86
|
expect(outcomes).to include("yaml-adapter: Lutaml::Yaml::Adapter::YeptrisAdapter")
|
|
@@ -27,12 +27,16 @@ RSpec.describe Lutaml::Model::AdapterResolver, ".adapter_for yeptris native dete
|
|
|
27
27
|
RUBY
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# The gem resolving is not enough: a binding/native desync leaves
|
|
31
|
+
# yeptris loadable while every parse raises. The healthy-lane spec
|
|
32
|
+
# is only meaningful where the native answers a probe.
|
|
30
33
|
def subprocess_yeptris_capable?
|
|
31
34
|
probe = <<~RUBY
|
|
32
35
|
begin
|
|
33
36
|
require "yeptris"
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
require "lutaml/json/adapter/yeptris_adapter"
|
|
38
|
+
exit(Lutaml::Json::Adapter::YeptrisAdapter.available? ? 0 : 1)
|
|
39
|
+
rescue LoadError, StandardError
|
|
36
40
|
exit(1)
|
|
37
41
|
end
|
|
38
42
|
RUBY
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Lutaml::Xml::Schema::Xsd::Keyref do
|
|
6
|
+
it "maps the refer attribute from the parsed XSD" do
|
|
7
|
+
xsd = <<~XSD
|
|
8
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
9
|
+
<xs:element name="catalog">
|
|
10
|
+
<xs:keyref name="refKey" refer="itemKey"/>
|
|
11
|
+
</xs:element>
|
|
12
|
+
</xs:schema>
|
|
13
|
+
XSD
|
|
14
|
+
|
|
15
|
+
schema = Lutaml::Xml::Schema::Xsd.parse(xsd)
|
|
16
|
+
keyref = Array(schema.element.first.keyref).first
|
|
17
|
+
|
|
18
|
+
expect(keyref).not_to be_nil
|
|
19
|
+
expect(keyref.refer).to eq("itemKey")
|
|
20
|
+
end
|
|
21
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.121
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -155,6 +155,7 @@ files:
|
|
|
155
155
|
- ".envrc"
|
|
156
156
|
- ".github/scripts/test_installed_gem.rb"
|
|
157
157
|
- ".github/workflows/dependent-repos-todo.json"
|
|
158
|
+
- ".github/workflows/dependent-repos-tools.json"
|
|
158
159
|
- ".github/workflows/dependent-repos.json"
|
|
159
160
|
- ".github/workflows/dependent-tests.yml"
|
|
160
161
|
- ".github/workflows/docs.yml"
|
|
@@ -2021,6 +2022,7 @@ files:
|
|
|
2021
2022
|
- spec/lutaml/xml/schema/xsd/errors/suggestion_spec.rb
|
|
2022
2023
|
- spec/lutaml/xml/schema/xsd/file_validation_result_spec.rb
|
|
2023
2024
|
- spec/lutaml/xml/schema/xsd/glob_spec.rb
|
|
2025
|
+
- spec/lutaml/xml/schema/xsd/keyref_refer_spec.rb
|
|
2024
2026
|
- spec/lutaml/xml/schema/xsd/liquid_methods/attribute_and_group_spec.rb
|
|
2025
2027
|
- spec/lutaml/xml/schema/xsd/liquid_methods/complex_type_spec.rb
|
|
2026
2028
|
- spec/lutaml/xml/schema/xsd/liquid_methods/containers_spec.rb
|