lutaml-model 0.6.0 → 0.6.2

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos.json +2 -1
  3. data/.rubocop_todo.yml +10 -80
  4. data/lib/lutaml/model/attribute.rb +9 -5
  5. data/lib/lutaml/model/schema/xml_compiler.rb +3 -1
  6. data/lib/lutaml/model/serialize.rb +6 -8
  7. data/lib/lutaml/model/type/float.rb +0 -4
  8. data/lib/lutaml/model/version.rb +1 -1
  9. data/lib/lutaml/model/xml_adapter/xml_document.rb +0 -4
  10. data/lib/lutaml/model/xml_adapter/xml_element.rb +1 -3
  11. data/spec/address_spec.rb +3 -3
  12. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +3 -3
  13. data/spec/lutaml/model/collection_spec.rb +0 -16
  14. data/spec/lutaml/model/custom_model_spec.rb +49 -1
  15. data/spec/lutaml/model/json_adapter_spec.rb +26 -24
  16. data/spec/lutaml/model/key_value_mapping_spec.rb +1 -13
  17. data/spec/lutaml/model/schema/json_schema_spec.rb +12 -12
  18. data/spec/lutaml/model/schema/relaxng_schema_spec.rb +12 -12
  19. data/spec/lutaml/model/schema/xml_compiler_spec.rb +447 -147
  20. data/spec/lutaml/model/schema/xsd_schema_spec.rb +12 -12
  21. data/spec/lutaml/model/schema/yaml_schema_spec.rb +12 -12
  22. data/spec/lutaml/model/sequence_spec.rb +129 -113
  23. data/spec/lutaml/model/toml_adapter_spec.rb +27 -25
  24. data/spec/lutaml/model/transformation_spec.rb +80 -80
  25. data/spec/lutaml/model/type/boolean_spec.rb +4 -10
  26. data/spec/lutaml/model/type/decimal_spec.rb +3 -3
  27. data/spec/lutaml/model/type/hash_spec.rb +39 -26
  28. data/spec/lutaml/model/type/integer_spec.rb +2 -2
  29. data/spec/lutaml/model/type/time_without_date_spec.rb +0 -6
  30. data/spec/lutaml/model/type_spec.rb +6 -26
  31. data/spec/lutaml/model/utils_spec.rb +25 -30
  32. data/spec/lutaml/model/validation_spec.rb +9 -6
  33. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  34. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  35. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +280 -281
  36. data/spec/lutaml/model/xml_adapter_spec.rb +128 -120
  37. data/spec/lutaml/model/xml_mapping_spec.rb +47 -16
  38. data/spec/person_spec.rb +6 -16
  39. metadata +2 -2
@@ -33,146 +33,154 @@ module XmlAdapterSpec
33
33
  end
34
34
  end
35
35
 
36
- RSpec.shared_examples "an XML adapter" do |adapter_class|
37
- around do |example|
38
- old_adapter = Lutaml::Model::Config.xml_adapter
39
- Lutaml::Model::Config.xml_adapter = adapter_class
40
-
41
- example.run
42
- ensure
43
- Lutaml::Model::Config.xml_adapter = old_adapter
44
- end
45
-
46
- before do
47
- # Ensure BigDecimal is loaded because it is being used in sample model
48
- require "bigdecimal"
49
- end
50
-
51
- let(:attributes) { { name: "John Doe", age: 30 } }
52
- let(:model) { SampleModel.new(attributes) }
53
-
54
- context "with default value" do
55
- it "set display attribute correctly, other attributes default" do
56
- xml = "<math display='true'></math>"
57
-
58
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
59
- expect(parsed.display).to eq("true")
60
- expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
61
- expect(parsed.style.displaystyle).to eq("true")
36
+ RSpec.describe "XmlAdapter" do
37
+ shared_examples "an XML adapter" do |adapter_class|
38
+ around do |example|
39
+ old_adapter = Lutaml::Model::Config.xml_adapter
40
+ Lutaml::Model::Config.xml_adapter = adapter_class
41
+
42
+ example.run
43
+ ensure
44
+ Lutaml::Model::Config.xml_adapter = old_adapter
62
45
  end
63
46
 
64
- it "set style attribute correctly, other attributes default" do
65
- xml = "<math> <mstyle displaystyle='false'> </mstyle> </math>"
66
-
67
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
68
- expect(parsed.display).to eq("block")
69
- expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
70
- expect(parsed.style.displaystyle).to eq("false")
71
- end
72
-
73
- it "sets attributes default values" do
74
- xml = "<math> </math>"
75
-
76
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
77
- expect(parsed.display).to eq("block")
78
- expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
79
- expect(parsed.style.displaystyle).to eq("true")
47
+ before do
48
+ # Ensure BigDecimal is loaded because it is being used in sample model
49
+ require "bigdecimal"
80
50
  end
81
51
 
82
- it "delegate attributes with value" do
83
- xml = "<math color='blue' finish='no'></math>"
84
-
85
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
86
- expect(parsed.style.color).to eq("blue")
87
- expect(parsed.style.finish).to eq("no")
88
- expect(parsed.style.displaystyle).to eq("true")
52
+ let(:attributes) { { name: "John Doe", age: 30 } }
53
+ let(:model) { SampleModel.new(attributes) }
54
+
55
+ context "with default value" do
56
+ it "set display attribute correctly, other attributes default" do
57
+ xml = "<math display='true'></math>"
58
+
59
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
60
+ expect(parsed.display).to eq("true")
61
+ expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
62
+ expect(parsed.style.displaystyle).to eq("true")
63
+ end
64
+
65
+ it "set style attribute correctly, other attributes default" do
66
+ xml = "<math> <mstyle displaystyle='false'> </mstyle> </math>"
67
+
68
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
69
+ expect(parsed.display).to eq("block")
70
+ expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
71
+ expect(parsed.style.displaystyle).to eq("false")
72
+ end
73
+
74
+ it "sets attributes default values" do
75
+ xml = "<math> </math>"
76
+
77
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
78
+ expect(parsed.display).to eq("block")
79
+ expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
80
+ expect(parsed.style.displaystyle).to eq("true")
81
+ end
82
+
83
+ it "delegate attributes with value" do
84
+ xml = "<math color='blue' finish='no'></math>"
85
+
86
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
87
+ expect(parsed.style.color).to eq("blue")
88
+ expect(parsed.style.finish).to eq("no")
89
+ expect(parsed.style.displaystyle).to eq("true")
90
+ end
91
+
92
+ it "delegate attributes with one value" do
93
+ xml = "<math color='blue'></math>"
94
+
95
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
96
+ expect(parsed.style.color).to eq("blue")
97
+ expect(parsed.style.finish).to eq("yes")
98
+ expect(parsed.style.displaystyle).to eq("true")
99
+ end
100
+
101
+ it "delegate attributes with no value" do
102
+ xml = "<math></math>"
103
+
104
+ parsed = XmlAdapterSpec::Maths.from_xml(xml)
105
+ expect(parsed.style.color).to be_nil
106
+ expect(parsed.style.finish).to eq("yes")
107
+ expect(parsed.style.displaystyle).to eq("true")
108
+ end
109
+
110
+ context "when round-trips" do
111
+ let(:parsed) do
112
+ XmlAdapterSpec::Maths.from_xml(xml)
113
+ end
114
+
115
+ let(:xml) do
116
+ "<math display='true'></math>"
117
+ end
118
+
119
+ let(:expected_xml) do
120
+ <<~XML
121
+ <math display="true" finish="yes">
122
+ <mstyle displaystyle="true"/>
123
+ </math>
124
+ XML
125
+ end
126
+
127
+ it "add default values" do
128
+ expect(parsed.to_xml.strip).to be_equivalent_to(expected_xml.strip)
129
+ end
130
+ end
89
131
  end
90
132
 
91
- it "delegate attributes with one value" do
92
- xml = "<math color='blue'></math>"
133
+ it "serializes to XML" do
134
+ expected_xml = <<~XML
135
+ <SampleModel>
136
+ <Name>John Doe</Name>
137
+ <Age>30</Age>
138
+ </SampleModel>
139
+ XML
93
140
 
94
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
95
- expect(parsed.style.color).to eq("blue")
96
- expect(parsed.style.finish).to eq("yes")
97
- expect(parsed.style.displaystyle).to eq("true")
141
+ doc = adapter_class.parse(expected_xml)
142
+ xml = doc.to_xml
143
+ expect(xml).to be_equivalent_to(expected_xml)
98
144
  end
99
145
 
100
- it "delegate attributes with no value" do
101
- xml = "<math></math>"
146
+ it "serializes to XML with only content" do
147
+ expected_xml = <<~XML
148
+ <Tag>
149
+ Bug
150
+ </Tag>
151
+ XML
102
152
 
103
- parsed = XmlAdapterSpec::Maths.from_xml(xml)
104
- expect(parsed.style.color).to be_nil
105
- expect(parsed.style.finish).to eq("yes")
106
- expect(parsed.style.displaystyle).to eq("true")
153
+ doc = SampleModelTag.from_xml(expected_xml)
154
+ xml = doc.to_xml
155
+ expect(xml).to be_equivalent_to(expected_xml)
107
156
  end
108
157
 
109
- it "round-trips XML and add default values" do
110
- input_xml = <<~XML
111
- <math display='true'></math>
112
- XML
113
-
114
- output_xml = <<~XML
115
- <math display="true" finish="yes">
116
- <mstyle displaystyle="true"/>
117
- </math>
158
+ it "deserializes from XML" do
159
+ xml = <<~XML
160
+ <SampleModel>
161
+ <Name>John Doe</Name>
162
+ <Age>30</Age>
163
+ </SampleModel>
118
164
  XML
119
165
 
120
- parsed = XmlAdapterSpec::Maths.from_xml(input_xml)
121
-
122
- expect(parsed.to_xml.strip).to be_equivalent_to(output_xml.strip)
166
+ doc = adapter_class.parse(xml)
167
+ new_model = SampleModel.new(doc.root.children.to_h do |child|
168
+ [child.name.downcase.to_sym, child.text]
169
+ end)
170
+ expect(new_model.name).to eq("John Doe")
171
+ expect(new_model.age).to eq(30)
123
172
  end
124
173
  end
125
174
 
126
- it "serializes to XML" do
127
- expected_xml = <<~XML
128
- <SampleModel>
129
- <Name>John Doe</Name>
130
- <Age>30</Age>
131
- </SampleModel>
132
- XML
133
-
134
- doc = adapter_class.parse(expected_xml)
135
- xml = doc.to_xml
136
- expect(xml).to be_equivalent_to(expected_xml)
175
+ describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
176
+ it_behaves_like "an XML adapter", described_class
137
177
  end
138
178
 
139
- it "serializes to XML with only content" do
140
- expected_xml = <<~XML
141
- <Tag>
142
- Bug
143
- </Tag>
144
- XML
145
-
146
- doc = SampleModelTag.from_xml(expected_xml)
147
- xml = doc.to_xml
148
- expect(xml).to be_equivalent_to(expected_xml)
179
+ describe Lutaml::Model::XmlAdapter::OxAdapter do
180
+ it_behaves_like "an XML adapter", described_class
149
181
  end
150
182
 
151
- it "deserializes from XML" do
152
- xml = <<~XML
153
- <SampleModel>
154
- <Name>John Doe</Name>
155
- <Age>30</Age>
156
- </SampleModel>
157
- XML
158
-
159
- doc = adapter_class.parse(xml)
160
- new_model = SampleModel.new(doc.root.children.to_h do |child|
161
- [child.name.downcase.to_sym, child.text]
162
- end)
163
- expect(new_model.name).to eq("John Doe")
164
- expect(new_model.age).to eq(30)
183
+ describe Lutaml::Model::XmlAdapter::OgaAdapter do
184
+ it_behaves_like "an XML adapter", described_class
165
185
  end
166
186
  end
167
-
168
- RSpec.describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
169
- it_behaves_like "an XML adapter", described_class
170
- end
171
-
172
- RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
173
- it_behaves_like "an XML adapter", described_class
174
- end
175
-
176
- RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do
177
- it_behaves_like "an XML adapter", described_class
178
- end
@@ -57,6 +57,7 @@ module XmlMapping
57
57
  class Address < Lutaml::Model::Serializable
58
58
  attribute :street, ::Lutaml::Model::Type::String, raw: true
59
59
  attribute :city, :string, raw: true
60
+ attribute :text, :string
60
61
  attribute :address, Address
61
62
 
62
63
  xml do
@@ -64,6 +65,7 @@ module XmlMapping
64
65
 
65
66
  map_element "street", to: :street
66
67
  map_element "city", to: :city
68
+ map_element "text", to: :text
67
69
  end
68
70
  end
69
71
 
@@ -334,7 +336,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
334
336
 
335
337
  let(:mapping) { Lutaml::Model::XmlMapping.new }
336
338
 
337
- context "attribute namespace" do
339
+ context "with attribute having namespace" do
338
340
  input_xml = <<~XML
339
341
  <ns1:example ex1:alpha="hello"
340
342
  beta="bye"
@@ -352,7 +354,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
352
354
  end
353
355
  end
354
356
 
355
- context "explicit namespace" do
357
+ context "with explicit namespace" do
356
358
  mml = <<~XML
357
359
  <math xmlns="http://www.w3.org/1998/Math/MathML">
358
360
  <mfenced open="("></mfenced>
@@ -366,7 +368,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
366
368
  end
367
369
 
368
370
  # Skipping for OX because it does not handle namespaces
369
- context "overriding child namespace prefix", skip: adapter_class == Lutaml::Model::XmlAdapter::OxAdapter do
371
+ context "when overriding child namespace prefix", skip: adapter_class == Lutaml::Model::XmlAdapter::OxAdapter do
370
372
  let(:input_xml) do
371
373
  <<~XML
372
374
  <OverrideDefaultNamespacePrefix
@@ -838,6 +840,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
838
840
  <p>adf</p>
839
841
  </street>
840
842
  <city><a>M</a></city>
843
+ <text>Building near ABC</text>
841
844
  </address>
842
845
  </person>
843
846
  XML
@@ -859,6 +862,27 @@ RSpec.describe Lutaml::Model::XmlMapping do
859
862
  end
860
863
  end
861
864
 
865
+ context "with element named `text`" do
866
+ let(:input_xml) do
867
+ <<~XML
868
+ <address>
869
+ <street>
870
+ <a>N</a>
871
+ <p>adf</p>
872
+ </street>
873
+ <city><a>M</a></city>
874
+ <text>Building near ABC</text>
875
+ </address>
876
+ XML
877
+ end
878
+
879
+ let(:model) { XmlMapping::Address.from_xml(input_xml) }
880
+
881
+ it "expect to contain raw xml" do
882
+ expect(model.text).to eq("Building near ABC")
883
+ end
884
+ end
885
+
862
886
  context "with content mapping" do
863
887
  let(:xml_data) { "<i>my text <b>bold</b> is in italics</i>" }
864
888
  let(:italic) { Italic.from_xml(xml_data) }
@@ -1083,23 +1107,30 @@ RSpec.describe Lutaml::Model::XmlMapping do
1083
1107
  end
1084
1108
  end
1085
1109
 
1086
- it "maps all the content including tags" do
1087
- inner_xml = if adapter_class.type == "ox"
1088
- "Str<sub>2</sub> text<sup>1</sup> 123"
1089
- else
1090
- "Str<sub>2</sub>text<sup>1</sup>123"
1091
- end
1092
- xml = "<WithMapAll>#{inner_xml}</WithMapAll>"
1110
+ context "without custom methods" do
1111
+ let(:inner_xml) do
1112
+ if adapter_class.type == "ox"
1113
+ "Str<sub>2</sub> text<sup>1</sup> 123"
1114
+ else
1115
+ "Str<sub>2</sub>text<sup>1</sup>123"
1116
+ end
1117
+ end
1093
1118
 
1094
- parsed = XmlMapping::WithMapAll.from_xml(xml)
1119
+ let(:xml) do
1120
+ "<WithMapAll>#{inner_xml}</WithMapAll>"
1121
+ end
1095
1122
 
1096
- expect(parsed.all_content).to eq(inner_xml)
1097
- end
1123
+ let(:parsed) do
1124
+ XmlMapping::WithMapAll.from_xml(xml)
1125
+ end
1098
1126
 
1099
- it "round-trips xml" do
1100
- xml = "<WithMapAll>Str<sub>2</sub>text<sup>1</sup>123</WithMapAll>"
1127
+ it "maps all the content including tags" do
1128
+ expect(parsed.all_content).to eq(inner_xml)
1129
+ end
1101
1130
 
1102
- expect(XmlMapping::WithMapAll.from_xml(xml).to_xml.chomp).to eq(xml)
1131
+ it "round-trips xml" do
1132
+ expect(parsed.to_xml.chomp).to eq(xml)
1133
+ end
1103
1134
  end
1104
1135
 
1105
1136
  context "when nested content has map_all" do
data/spec/person_spec.rb CHANGED
@@ -29,6 +29,7 @@ RSpec.describe Person do
29
29
  "active" => true,
30
30
  }
31
31
  end
32
+
32
33
  let(:attributes_json) do
33
34
  {
34
35
  firstName: "John",
@@ -42,8 +43,8 @@ RSpec.describe Person do
42
43
  }
43
44
  end
44
45
 
45
- it "serializes to XML" do
46
- expected_xml = <<~XML
46
+ let(:xml) do
47
+ <<~XML
47
48
  <p:Person xmlns:p="http://example.com/person" xmlns:nsp1="http://example.com/nsp1">
48
49
  <nsp1:FirstName>John</nsp1:FirstName>
49
50
  <nsp1:LastName>Doe</nsp1:LastName>
@@ -55,24 +56,13 @@ RSpec.describe Person do
55
56
  <p:Active>true</p:Active>
56
57
  </p:Person>
57
58
  XML
59
+ end
58
60
 
59
- expect(model.to_xml).to be_equivalent_to(expected_xml)
61
+ it "serializes to XML" do
62
+ expect(model.to_xml).to be_equivalent_to(xml)
60
63
  end
61
64
 
62
65
  it "deserializes from XML" do
63
- xml = <<~XML
64
- <p:Person xmlns:p="http://example.com/person" xmlns:nsp1="http://example.com/nsp1">
65
- <nsp1:FirstName>John</nsp1:FirstName>
66
- <nsp1:LastName>Doe</nsp1:LastName>
67
- <p:Age>30</p:Age>
68
- <p:Height>5.9</p:Height>
69
- <p:Birthdate>1990-01-01</p:Birthdate>
70
- <p:LastLogin>2023-06-08T10:00:00+00:00</p:LastLogin>
71
- <p:WakeupTime>07:00:00</p:WakeupTime>
72
- <p:Active>true</p:Active>
73
- </p:Person>
74
- XML
75
-
76
66
  person = described_class.from_xml(xml)
77
67
  expect(person.first_name).to eq("John")
78
68
  expect(person.age).to eq(30)
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.6.0
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-10 00:00:00.000000000 Z
11
+ date: 2025-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64