lutaml-model 0.8.142 → 0.8.144

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: 4ddbdf9b831babcd7fd6bd41314ea8b4f2352503f0302b2420942d9d144dc0bb
4
- data.tar.gz: 4704a4bac05aef07a9a0a0a939180cd10d15ad4a8ab086dc218b126c68f97d2f
3
+ metadata.gz: ff4c24c792fe315c6798bf64b67dbc4924fc919fc447e4a0264467d169a80315
4
+ data.tar.gz: 15621c39ad1d06dddbca3c9b0ef809b1a87d13222ef850c0cdb557da3317ca1d
5
5
  SHA512:
6
- metadata.gz: 817089bc912e7a85d912ecdffc09e8d894cadb3ca416450f6b5cab6d3b2463e4d9210ccf8ca0af1710a4de088562ef5628ec5896ff9585dc0ad6798444897a77
7
- data.tar.gz: b1196728958dfc2e8be4ed6da1a70c4b5e09079c7c1d3940398e4c1c97adbd5bfa34d74a829ae51c9ad8a85d09ddcad5028050eca1de432f897b98fbdce5ff60
6
+ metadata.gz: 21de2545ba67ce8357cd0216e70a085648ea24153cff022a805005b677d7d90ab51af50869cfc6335d6aad5404f4bb4fde30ed9f6389a31ff9b7ac51580646b4
7
+ data.tar.gz: d46faf8a708c88622abb2d560bf2f533da86815553c81049b8d432f71d60cfad67a65e567858454a7ecad721b2d2e02c2c3d6bd8bc173416903dc5d4faab7065
@@ -184,12 +184,16 @@ module Lutaml
184
184
  end
185
185
  end
186
186
 
187
- private
188
-
189
187
  # Replace a shared structure with a class-owned copy. The copy
190
188
  # becomes the snapshot for every existing subclass, which is what
191
189
  # keeps post-fork mutations invisible to them (the eager-copy
192
190
  # semantics).
191
+ #
192
+ # Public on purpose: code that mutates `mappings`, `attributes`,
193
+ # `choices` or `registers` outside the DSL — sibling classes pruning
194
+ # inherited elements (relaton's Item-header prunes) or importing
195
+ # models — must fork the structure first, or the mutation lands on
196
+ # the object shared with the superclass and every sibling class.
193
197
  def lutaml_cow_fork!(structure)
194
198
  return if lutaml_cow_status(structure) == 1
195
199
 
@@ -220,8 +224,6 @@ module Lutaml
220
224
  lutaml_cow_set_status!(structure, 1)
221
225
  end
222
226
 
223
- public
224
-
225
227
  # Return the mapping object a format DSL may mutate. Forking
226
228
  # the mappings structure copies every entry, so the object
227
229
  # returned here is this class's own.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.142"
5
+ VERSION = "0.8.144"
6
6
  end
7
7
  end
@@ -17,8 +17,8 @@ module Lutaml
17
17
  namespace Lutaml::Xml::Schema::XsdNamespace
18
18
 
19
19
  map_attribute :id, to: :id
20
- map_attribute :max_occurs, to: :max_occurs
21
- map_attribute :min_occurs, to: :min_occurs
20
+ map_attribute :maxOccurs, to: :max_occurs
21
+ map_attribute :minOccurs, to: :min_occurs
22
22
  map_element :annotation, to: :annotation
23
23
  map_element :element, to: :element
24
24
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # Copy-on-write inheritance shares a subclass's structures with its
6
+ # superclass until the class's own DSL forks them. External mutators — a
7
+ # library pruning an inherited attribute on one subclass (relaton's
8
+ # Item-header prunes) — need a supported way to claim ownership first, or
9
+ # the mutation erases the attribute for every sibling class.
10
+ RSpec.describe "Lutaml::Model::Serializable#lutaml_cow_fork!" do
11
+ let(:parent_class) do
12
+ Class.new(Lutaml::Model::Serializable) do
13
+ attribute :id, :string
14
+ attribute :shared, :string
15
+
16
+ xml do
17
+ root "parent"
18
+ map_attribute "id", to: :id
19
+ map_element "shared", to: :shared
20
+ end
21
+ end
22
+ end
23
+
24
+ let(:child_class) do
25
+ Class.new(parent_class)
26
+ end
27
+
28
+ it "is callable from outside the DSL" do
29
+ expect(child_class).to respond_to(:lutaml_cow_fork!)
30
+ end
31
+
32
+ it "gives the class a private copy without touching the superclass" do
33
+ parent_attributes = parent_class.class_attributes
34
+ child_class.lutaml_cow_fork!(:attributes)
35
+
36
+ expect(child_class.class_attributes).not_to equal(parent_attributes)
37
+ expect(parent_class.class_attributes).to equal(parent_attributes)
38
+ end
39
+
40
+ it "keeps post-fork mutations private to the forking class" do
41
+ child_class.lutaml_cow_fork!(:attributes)
42
+ child_class.lutaml_cow_fork!(:mappings)
43
+ child_class.class_attributes.delete(:id)
44
+ xml_attrs = child_class.mappings[:xml].instance_variable_get(:@attributes)
45
+ xml_attrs.delete("id")
46
+
47
+ expect(parent_class.class_attributes).to be_key(:id)
48
+ expect(parent_class.mappings[:xml]
49
+ .instance_variable_get(:@attributes)).to be_key("id")
50
+ expect(child_class.class_attributes).not_to be_key(:id)
51
+ end
52
+
53
+ it "does not fork an already-owned structure into a new object" do
54
+ child_class.lutaml_cow_fork!(:attributes)
55
+ owned = child_class.class_attributes
56
+ child_class.lutaml_cow_fork!(:attributes)
57
+
58
+ expect(child_class.class_attributes).to equal(owned)
59
+ end
60
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../spec_helper"
4
+ require "lutaml/xml/schema/xsd"
5
+
6
+ # #1046: xs:all carried its occurrence bounds mapped by their Ruby names
7
+ # (min_occurs/max_occurs), so minOccurs="0" was silently dropped at parse
8
+ # and never re-emitted. Sequence, choice and group already map the XML
9
+ # names; all now does too.
10
+ RSpec.describe "Xsd::All occurrence attributes" do
11
+ let(:xsd) do
12
+ <<~XSD
13
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
14
+ <xsd:element name="elt1">
15
+ <xsd:complexType>
16
+ <xsd:all minOccurs="0" maxOccurs="1">
17
+ <xsd:element name="elt2"/>
18
+ </xsd:all>
19
+ </xsd:complexType>
20
+ </xsd:element>
21
+ </xsd:schema>
22
+ XSD
23
+ end
24
+
25
+ it "reads the occurrence bounds" do
26
+ doc = Lutaml::Xml::Schema::Xsd.parse(xsd)
27
+ all = doc.element.first.complex_type.all
28
+
29
+ expect(all.min_occurs).to eq("0")
30
+ expect(all.max_occurs).to eq("1")
31
+ end
32
+
33
+ it "round-trips them as the XML attribute names" do
34
+ xml = Lutaml::Xml::Schema::Xsd.parse(xsd).to_xml
35
+
36
+ expect(xml).to include('minOccurs="0"')
37
+ expect(xml).to include('maxOccurs="1"')
38
+ expect(xml).not_to include("min_occurs")
39
+ expect(xml).not_to include("max_occurs")
40
+ end
41
+
42
+ it "keeps an xs:all without bounds boundless" do
43
+ doc = Lutaml::Xml::Schema::Xsd.parse(
44
+ <<~XSD,
45
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
46
+ <xsd:element name="elt1">
47
+ <xsd:complexType>
48
+ <xsd:all><xsd:element name="elt2"/></xsd:all>
49
+ </xsd:complexType>
50
+ </xsd:element>
51
+ </xsd:schema>
52
+ XSD
53
+ )
54
+
55
+ all = doc.element.first.complex_type.all
56
+
57
+ expect(all.min_occurs).to be_nil
58
+ expect(all.max_occurs).to be_nil
59
+ end
60
+ end
@@ -14,6 +14,15 @@ require "lutaml/xml/schema/xsd"
14
14
  # registered model's element and attribute rules to declared attributes
15
15
  # so the whole typo family fails here, at spec time.
16
16
  RSpec.describe "XSD schema model mapping integrity" do
17
+ # The registry fills at class-definition time and Xsd.parse is what
18
+ # force-loads the classes; without this hook the sweeps below see an
19
+ # empty register whenever they run before any parsing spec.
20
+ before do
21
+ Lutaml::Xml::Schema::Xsd::XSD_AUTOLOAD_CLASSES.each do |name|
22
+ Lutaml::Xml::Schema::Xsd.const_get(name) unless name == :VERSION
23
+ end
24
+ end
25
+
17
26
  it "maps every element rule of every registered model to a declared attribute" do
18
27
  broken = []
19
28
 
@@ -60,6 +69,34 @@ RSpec.describe "XSD schema model mapping integrity" do
60
69
  MSG
61
70
  end
62
71
 
72
+ # #1046 family: xs:all mapped its occurrence bounds by their Ruby names
73
+ # (min_occurs/max_occurs), so minOccurs="0" was dropped at parse. The
74
+ # XSD vocabulary has no snake_case attribute names — every multi-word
75
+ # XML attribute is camelCase — so a snake_case rule name is always a
76
+ # Ruby name that leaked into the wire.
77
+ it "spells every multi-word XML attribute name in camelCase" do
78
+ broken = []
79
+
80
+ Lutaml::Xml::Schema::Xsd.register.models.each_value do |klass|
81
+ next unless klass.is_a?(Class) && klass.include?(Lutaml::Model::Serialize)
82
+
83
+ mapping = klass.mappings_for(:xml)
84
+ mapping.mapping_attributes_hash.each_value do |rule_or_array|
85
+ Array(rule_or_array).each do |rule|
86
+ next unless rule.name.to_s.include?("_")
87
+
88
+ broken << "#{klass.name}: map_attribute #{rule.name.inspect} -> " \
89
+ "#{rule.to.inspect}"
90
+ end
91
+ end
92
+ end
93
+
94
+ expect(broken).to be_empty, <<~MSG
95
+ attribute rules spelled with snake_case wire names:
96
+ #{broken.join("\n")}
97
+ MSG
98
+ end
99
+
63
100
  # #1025: the regression that motivated the sweep — a redefine with a
64
101
  # group child parses, and each redefined member kind lands on its
65
102
  # declared attribute.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.142
4
+ version: 0.8.144
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -1753,6 +1753,7 @@ files:
1753
1753
  - spec/lutaml/model/consolidation_spec.rb
1754
1754
  - spec/lutaml/model/context_registry_spec.rb
1755
1755
  - spec/lutaml/model/conversion_caching_spec.rb
1756
+ - spec/lutaml/model/cow_fork_public_spec.rb
1756
1757
  - spec/lutaml/model/custom_bibtex_adapter_spec.rb
1757
1758
  - spec/lutaml/model/custom_collection_spec.rb
1758
1759
  - spec/lutaml/model/custom_from_empty_values_spec.rb
@@ -2047,6 +2048,7 @@ files:
2047
2048
  - spec/lutaml/xml/schema/facet_round_trip_spec.rb
2048
2049
  - spec/lutaml/xml/schema/rnc_compiler_spec.rb
2049
2050
  - spec/lutaml/xml/schema/rng_compiler_spec.rb
2051
+ - spec/lutaml/xml/schema/xsd/all_occurrence_attributes_spec.rb
2050
2052
  - spec/lutaml/xml/schema/xsd/any_attribute_spec.rb
2051
2053
  - spec/lutaml/xml/schema/xsd/errors/error_context_spec.rb
2052
2054
  - spec/lutaml/xml/schema/xsd/errors/suggestion_spec.rb