lutaml-model 0.6.7 → 0.7.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.
- checksums.yaml +4 -4
- data/.github/workflows/dependent-repos-todo.json +7 -0
- data/.github/workflows/dependent-repos.json +17 -9
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +51 -65
- data/Gemfile +4 -1
- data/README.adoc +5083 -2612
- data/RELEASE_NOTES.adoc +346 -0
- data/docs/custom_adapters.adoc +144 -0
- data/lib/lutaml/model/attribute.rb +101 -16
- data/lib/lutaml/model/choice.rb +7 -0
- data/lib/lutaml/model/comparable_model.rb +48 -9
- data/lib/lutaml/model/config.rb +48 -42
- data/lib/lutaml/model/error/collection_count_out_of_range_error.rb +1 -1
- data/lib/lutaml/model/error/polymorphic_error.rb +14 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/format_registry.rb +41 -0
- data/lib/lutaml/model/hash/document.rb +11 -0
- data/lib/lutaml/model/hash/mapping.rb +19 -0
- data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
- data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
- data/lib/lutaml/model/hash/transform.rb +8 -0
- data/lib/lutaml/model/hash.rb +21 -0
- data/lib/lutaml/model/json/document.rb +11 -0
- data/lib/lutaml/model/json/mapping.rb +19 -0
- data/lib/lutaml/model/json/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
- data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
- data/lib/lutaml/model/json/transform.rb +8 -0
- data/lib/lutaml/model/json.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +27 -0
- data/lib/lutaml/model/{key_value_mapping.rb → mapping/key_value_mapping.rb} +64 -16
- data/lib/lutaml/model/{key_value_mapping_rule.rb → mapping/key_value_mapping_rule.rb} +18 -2
- data/lib/lutaml/model/mapping/mapping.rb +13 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +300 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +15 -15
- data/lib/lutaml/model/sequence.rb +2 -2
- data/lib/lutaml/model/serialization_adapter.rb +22 -0
- data/lib/lutaml/model/serialize.rb +219 -444
- data/lib/lutaml/model/services/logger.rb +54 -0
- data/lib/lutaml/model/services/transformer.rb +48 -0
- data/lib/lutaml/model/services.rb +2 -0
- data/lib/lutaml/model/toml/document.rb +11 -0
- data/lib/lutaml/model/toml/mapping.rb +27 -0
- data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
- data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
- data/lib/lutaml/model/toml/transform.rb +8 -0
- data/lib/lutaml/model/toml.rb +30 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
- data/lib/lutaml/model/transform/xml_transform.rb +239 -0
- data/lib/lutaml/model/transform.rb +78 -0
- data/lib/lutaml/model/type/date.rb +1 -1
- data/lib/lutaml/model/type/date_time.rb +2 -2
- data/lib/lutaml/model/type/hash.rb +1 -1
- data/lib/lutaml/model/type/time.rb +2 -2
- data/lib/lutaml/model/type/time_without_date.rb +2 -2
- data/lib/lutaml/model/type/value.rb +6 -9
- data/lib/lutaml/model/uninitialized_class.rb +64 -0
- data/lib/lutaml/model/utils.rb +44 -0
- data/lib/lutaml/model/validation.rb +1 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
- data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
- data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
- data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +41 -21
- data/lib/lutaml/model/xml/element.rb +32 -0
- data/lib/lutaml/model/xml/mapping.rb +410 -0
- data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
- data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
- data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
- data/lib/lutaml/model/xml/transform.rb +8 -0
- data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +23 -10
- data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
- data/lib/lutaml/model/xml.rb +31 -0
- data/lib/lutaml/model/xml_adapter/element.rb +11 -25
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
- data/lib/lutaml/model/yaml/document.rb +10 -0
- data/lib/lutaml/model/yaml/mapping.rb +19 -0
- data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
- data/lib/lutaml/model/yaml/transform.rb +8 -0
- data/lib/lutaml/model/yaml.rb +21 -0
- data/lib/lutaml/model.rb +40 -4
- data/lutaml-model.gemspec +0 -4
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +7 -7
- data/spec/fixtures/person.rb +5 -5
- data/spec/lutaml/model/attribute_spec.rb +37 -1
- data/spec/lutaml/model/cdata_spec.rb +9 -9
- data/spec/lutaml/model/collection_spec.rb +50 -2
- data/spec/lutaml/model/comparable_model_spec.rb +92 -27
- data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
- data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
- data/spec/lutaml/model/defaults_spec.rb +1 -1
- data/spec/lutaml/model/enum_spec.rb +1 -1
- data/spec/lutaml/model/group_spec.rb +333 -20
- data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
- data/spec/lutaml/model/json_adapter_spec.rb +6 -6
- data/spec/lutaml/model/key_value_mapping_spec.rb +65 -3
- data/spec/lutaml/model/mixed_content_spec.rb +24 -24
- data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
- data/spec/lutaml/model/ordered_content_spec.rb +6 -6
- data/spec/lutaml/model/polymorphic_spec.rb +526 -0
- data/spec/lutaml/model/render_empty_spec.rb +194 -0
- data/spec/lutaml/model/render_nil_spec.rb +206 -22
- data/spec/lutaml/model/root_mappings_spec.rb +3 -3
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
- data/spec/lutaml/model/serializable_spec.rb +179 -103
- data/spec/lutaml/model/simple_model_spec.rb +9 -9
- data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/toml_spec.rb +51 -0
- data/spec/lutaml/model/transformation_spec.rb +72 -15
- data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
- data/spec/lutaml/model/value_map_spec.rb +240 -0
- data/spec/lutaml/model/xml/namespace/nested_with_explicit_namespace_spec.rb +85 -0
- data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
- data/spec/lutaml/model/xml/xml_element_spec.rb +93 -0
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +105 -5
- data/spec/lutaml/model/xml_mapping_spec.rb +70 -16
- data/spec/lutaml/model/xml_spec.rb +63 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
- data/spec/sample_model_spec.rb +3 -3
- data/spec/spec_helper.rb +3 -3
- metadata +76 -59
- data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
- data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
- data/lib/lutaml/model/loggable.rb +0 -15
- data/lib/lutaml/model/mapping_rule.rb +0 -109
- data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
- data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
- data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
- data/lib/lutaml/model/toml_adapter.rb +0 -6
- data/lib/lutaml/model/xml_mapping.rb +0 -307
- data/lib/lutaml/model/xml_mapping_rule.rb +0 -122
- data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
- data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
- data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -62,26 +62,26 @@ module SimpleModel
|
|
62
62
|
xml do
|
63
63
|
root "building"
|
64
64
|
map_attribute "name", to: :name
|
65
|
-
map_element "address", to: :address
|
66
|
-
map_element "room", to: :rooms
|
65
|
+
map_element "address", to: :address, treat_omitted: :omited
|
66
|
+
map_element "room", to: :rooms, treat_omitted: :omited
|
67
67
|
end
|
68
68
|
|
69
69
|
yaml do
|
70
70
|
map "name", to: :name
|
71
|
-
map "address", to: :address
|
72
|
-
map "rooms", to: :rooms
|
71
|
+
map "address", to: :address, treat_omitted: :omited
|
72
|
+
map "rooms", to: :rooms, treat_omitted: :omited
|
73
73
|
end
|
74
74
|
|
75
75
|
json do
|
76
76
|
map "name", to: :name
|
77
|
-
map "address", to: :address
|
78
|
-
map "rooms", to: :rooms
|
77
|
+
map "address", to: :address, treat_omitted: :omited
|
78
|
+
map "rooms", to: :rooms, treat_omitted: :omited
|
79
79
|
end
|
80
80
|
|
81
81
|
toml do
|
82
82
|
map "name", to: :name
|
83
|
-
map "address", to: :address
|
84
|
-
map "rooms", to: :rooms
|
83
|
+
map "address", to: :address, treat_omitted: :omited
|
84
|
+
map "rooms", to: :rooms, treat_omitted: :omited
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -182,7 +182,7 @@ RSpec.describe SimpleModel do
|
|
182
182
|
default_model = SimpleModel::Building.new
|
183
183
|
expect(default_model.name).to eq("Unnamed building")
|
184
184
|
expect(default_model.address).to be_nil
|
185
|
-
expect(default_model.rooms).to
|
185
|
+
expect(default_model.rooms).to be_nil
|
186
186
|
end
|
187
187
|
|
188
188
|
it "serializes to XML" do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "lutaml/model/
|
3
|
-
require "lutaml/model/
|
2
|
+
require "lutaml/model/toml/toml_rb_adapter"
|
3
|
+
require "lutaml/model/toml/tomlib_adapter"
|
4
4
|
require_relative "../../fixtures/sample_model"
|
5
5
|
|
6
6
|
RSpec.describe "TomlAdapter" do
|
@@ -9,9 +9,9 @@ RSpec.describe "TomlAdapter" do
|
|
9
9
|
let(:model) { SampleModel.new(attributes) }
|
10
10
|
|
11
11
|
let(:expected_toml) do
|
12
|
-
if adapter_class == Lutaml::Model::
|
12
|
+
if adapter_class == Lutaml::Model::Toml::TomlRbAdapter
|
13
13
|
TomlRB.dump(attributes)
|
14
|
-
elsif adapter_class == Lutaml::Model::
|
14
|
+
elsif adapter_class == Lutaml::Model::Toml::TomlibAdapter
|
15
15
|
Tomlib.dump(attributes)
|
16
16
|
end
|
17
17
|
end
|
@@ -31,11 +31,11 @@ RSpec.describe "TomlAdapter" do
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
describe Lutaml::Model::
|
34
|
+
describe Lutaml::Model::Toml::TomlRbAdapter do
|
35
35
|
it_behaves_like "a TOML adapter", described_class
|
36
36
|
end
|
37
37
|
|
38
|
-
describe Lutaml::Model::
|
38
|
+
describe Lutaml::Model::Toml::TomlibAdapter do
|
39
39
|
it_behaves_like "a TOML adapter", described_class
|
40
40
|
end
|
41
41
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "lutaml/model/toml"
|
5
|
+
|
6
|
+
RSpec.describe Lutaml::Model::Toml do
|
7
|
+
describe ".detect_toml_adapter" do
|
8
|
+
before do
|
9
|
+
# Hide any existing constants first
|
10
|
+
hide_const("Tomlib") if Object.const_defined?(:Tomlib)
|
11
|
+
hide_const("TomlRb") if Object.const_defined?(:TomlRb)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when Tomlib is available" do
|
15
|
+
before do
|
16
|
+
stub_const("Tomlib", Module.new)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns :tomlib" do
|
20
|
+
expect(described_class.detect_toml_adapter).to eq(:tomlib)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when TomlRb is available" do
|
25
|
+
before do
|
26
|
+
stub_const("TomlRb", Module.new)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns :toml_rb" do
|
30
|
+
expect(described_class.detect_toml_adapter).to eq(:toml_rb)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when neither adapter is available" do
|
35
|
+
it "returns nil" do
|
36
|
+
expect(described_class.detect_toml_adapter).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when both adapters are available" do
|
41
|
+
before do
|
42
|
+
stub_const("Tomlib", Module.new)
|
43
|
+
stub_const("TomlRb", Module.new)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "prefers Tomlib" do
|
47
|
+
expect(described_class.detect_toml_adapter).to eq(:tomlib)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -56,7 +56,7 @@ module TransformationSpec
|
|
56
56
|
import: ->(value) { value.to_s.downcase },
|
57
57
|
}
|
58
58
|
attribute :email, :string, transform: {
|
59
|
-
export: lambda(&:
|
59
|
+
export: lambda(&:upcase),
|
60
60
|
import: lambda(&:downcase),
|
61
61
|
}
|
62
62
|
attribute :tags, :string, collection: true, transform: {
|
@@ -82,13 +82,36 @@ module TransformationSpec
|
|
82
82
|
export: ->(value) { "Prof. #{value}" },
|
83
83
|
import: ->(value) { value.gsub("Prof. ", "") },
|
84
84
|
}
|
85
|
-
|
85
|
+
map_attribute "contact-email", to: :email, transform: {
|
86
86
|
export: ->(value) { "contact+#{value}" },
|
87
87
|
import: ->(value) { value.gsub("contact+", "") },
|
88
88
|
}
|
89
89
|
map_element "skills", to: :tags
|
90
90
|
end
|
91
91
|
end
|
92
|
+
|
93
|
+
class RoundTripTransformations < Lutaml::Model::Serializable
|
94
|
+
attribute :number, :string, transform: {
|
95
|
+
import: ->(value) { (value.to_f + 1).to_s },
|
96
|
+
export: ->(value) { (value.to_f - 1).to_s },
|
97
|
+
}
|
98
|
+
|
99
|
+
json do
|
100
|
+
map "number", to: :number, transform: {
|
101
|
+
import: ->(value) { ((value.to_f * 10) + 1).to_s },
|
102
|
+
export: ->(value) { ((value.to_f - 1) / 10.0).to_s },
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
xml do
|
107
|
+
root "RoundTripTransformations"
|
108
|
+
|
109
|
+
map_element "number", to: :number, transform: {
|
110
|
+
import: ->(value) { ((value.to_f * 10) + 1).to_s },
|
111
|
+
export: ->(value) { ((value.to_f - 1) / 10.0).to_s },
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
92
115
|
end
|
93
116
|
|
94
117
|
RSpec.describe "Value Transformations" do
|
@@ -147,6 +170,18 @@ RSpec.describe "Value Transformations" do
|
|
147
170
|
)
|
148
171
|
end
|
149
172
|
|
173
|
+
let(:json) do
|
174
|
+
{
|
175
|
+
"fullName" => "Dr. bob",
|
176
|
+
"emailAddress" => "bobattest.com",
|
177
|
+
"labels" => "senior|lead",
|
178
|
+
}.to_json
|
179
|
+
end
|
180
|
+
|
181
|
+
let(:parsed) do
|
182
|
+
TransformationSpec::MappingTransformPerson.from_json(json)
|
183
|
+
end
|
184
|
+
|
150
185
|
let(:expected_xml) do
|
151
186
|
<<~XML
|
152
187
|
<person>
|
@@ -165,16 +200,15 @@ RSpec.describe "Value Transformations" do
|
|
165
200
|
expect(parsed["labels"]).to eq("developer-|-architect")
|
166
201
|
end
|
167
202
|
|
168
|
-
it "
|
169
|
-
json = {
|
170
|
-
"fullName" => "Dr. bob",
|
171
|
-
"emailAddress" => "bobattest.com",
|
172
|
-
"labels" => "senior|lead",
|
173
|
-
}.to_json
|
174
|
-
|
175
|
-
parsed = TransformationSpec::MappingTransformPerson.from_json(json)
|
203
|
+
it "correctly deserialize name from JSON" do
|
176
204
|
expect(parsed.name).to eq("Dr. bob")
|
205
|
+
end
|
206
|
+
|
207
|
+
it "correctly deserialize email from JSON" do
|
177
208
|
expect(parsed.email).to eq("bob@test.com")
|
209
|
+
end
|
210
|
+
|
211
|
+
it "correctly deserialize tags from JSON" do
|
178
212
|
expect(parsed.tags).to eq(["senior", "lead"])
|
179
213
|
end
|
180
214
|
|
@@ -195,9 +229,8 @@ RSpec.describe "Value Transformations" do
|
|
195
229
|
|
196
230
|
let(:expected_xml) do
|
197
231
|
<<~XML
|
198
|
-
<person>
|
199
|
-
<full-name>Prof.
|
200
|
-
<contact-email>contact+CAROL@TEST.COM</contact-email>
|
232
|
+
<person contact-email="contact+CAROL@TEST.COM">
|
233
|
+
<full-name>Prof. Carol</full-name>
|
201
234
|
<skills>MANAGER-1</skills>
|
202
235
|
<skills>AGILE-1</skills>
|
203
236
|
</person>
|
@@ -208,7 +241,7 @@ RSpec.describe "Value Transformations" do
|
|
208
241
|
json = combined_person.to_json
|
209
242
|
parsed = JSON.parse(json)
|
210
243
|
|
211
|
-
expect(parsed["fullName"]).to eq("Prof.
|
244
|
+
expect(parsed["fullName"]).to eq("Prof. Carol")
|
212
245
|
expect(parsed["contactEmail"]).to eq("contact+CAROL@TEST.COM")
|
213
246
|
end
|
214
247
|
|
@@ -217,7 +250,7 @@ RSpec.describe "Value Transformations" do
|
|
217
250
|
json = combined_person.to_json
|
218
251
|
parsed_json = TransformationSpec::CombinedTransformPerson.from_json(json)
|
219
252
|
expect(parsed_json.name).to eq("carol")
|
220
|
-
expect(parsed_json.email).to eq("
|
253
|
+
expect(parsed_json.email).to eq("carol@test.com")
|
221
254
|
expect(parsed_json.tags).to eq(["MANAGER-1", "AGILE-1"])
|
222
255
|
end
|
223
256
|
|
@@ -227,4 +260,28 @@ RSpec.describe "Value Transformations" do
|
|
227
260
|
expect(parsed_xml.to_xml).to be_equivalent_to(expected_xml)
|
228
261
|
end
|
229
262
|
end
|
263
|
+
|
264
|
+
describe "Custom Transformations all mappings applied" do
|
265
|
+
let(:xml) do
|
266
|
+
<<~XML
|
267
|
+
<RoundTripTransformations>
|
268
|
+
<number>10.0</number>
|
269
|
+
</RoundTripTransformations>
|
270
|
+
XML
|
271
|
+
end
|
272
|
+
|
273
|
+
let(:json) do
|
274
|
+
{ number: "10.0" }.to_json
|
275
|
+
end
|
276
|
+
|
277
|
+
it "correctly round trips XML" do
|
278
|
+
parsed = TransformationSpec::RoundTripTransformations.from_xml(xml)
|
279
|
+
expect(parsed.to_xml).to be_equivalent_to(xml)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "correctly round trips JSON" do
|
283
|
+
parsed = TransformationSpec::RoundTripTransformations.from_json(json)
|
284
|
+
expect(parsed.to_json).to be_equivalent_to(json)
|
285
|
+
end
|
286
|
+
end
|
230
287
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Lutaml::Model::UninitializedClass do
|
4
|
+
subject(:uninitialized) { described_class.instance }
|
5
|
+
|
6
|
+
describe "#to_s" do
|
7
|
+
it "returns self" do
|
8
|
+
expect(uninitialized.to_s).to eq(uninitialized)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#inspect" do
|
13
|
+
it "returns 'uninitialized'" do
|
14
|
+
expect(uninitialized.inspect).to eq("uninitialized")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#uninitialized?" do
|
19
|
+
it "returns true" do
|
20
|
+
expect(uninitialized.uninitialized?).to be true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#match?" do
|
25
|
+
it "returns false for any argument" do
|
26
|
+
expect(uninitialized).not_to match /pattern/
|
27
|
+
expect(uninitialized).not_to match "string"
|
28
|
+
expect(uninitialized).not_to match nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#include?" do
|
33
|
+
it "returns false for any argument" do
|
34
|
+
expect(uninitialized).not_to include "substring"
|
35
|
+
expect(uninitialized).not_to include nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#gsub" do
|
40
|
+
it "returns self regardless of arguments" do
|
41
|
+
expect(uninitialized.gsub("pattern", "replacement")).to eq(uninitialized)
|
42
|
+
expect(uninitialized.gsub("pattern", "replacement")).to eq(uninitialized)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#to_yaml" do
|
47
|
+
it "returns nil" do
|
48
|
+
expect(uninitialized.to_yaml).to be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#to_f" do
|
53
|
+
it "returns self" do
|
54
|
+
expect(uninitialized.to_f).to eq(uninitialized)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#size" do
|
59
|
+
it "returns 0" do
|
60
|
+
expect(uninitialized.size).to eq(0)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#encoding" do
|
65
|
+
it "returns the default string encoding" do
|
66
|
+
expect(uninitialized.encoding).to eq("".encoding)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "method_missing" do
|
71
|
+
context "when method ends with '?'" do
|
72
|
+
it "returns false" do
|
73
|
+
expect(uninitialized).not_to be_empty
|
74
|
+
expect(uninitialized).not_to be_nil
|
75
|
+
expect(uninitialized).not_to be_blank
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when method doesn't end with '?'" do
|
80
|
+
it "raises NoMethodError" do
|
81
|
+
expect { uninitialized.unknown_method }.to raise_error(NoMethodError)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#respond_to_missing?" do
|
87
|
+
it "returns true for methods ending with ?" do
|
88
|
+
expect(uninitialized.respond_to?(:empty?)).to be true
|
89
|
+
expect(uninitialized.respond_to?(:nil?)).to be true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns false for methods not ending with ?" do
|
93
|
+
expect(uninitialized.respond_to?(:unknown_method)).to be false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# map :x, to: :y, value_map: {
|
2
|
+
# from_xml: {omitted: :omitted, xsi_nil: nil, empty: [] },
|
3
|
+
# to_xml: {omitted: :omitted, nil: :nil, empty: :empty}
|
4
|
+
# }
|
5
|
+
|
6
|
+
module ValueMapSpec
|
7
|
+
class WithValueMaps < Lutaml::Model::Serializable
|
8
|
+
attribute :omitted_as_omitted, :string
|
9
|
+
attribute :omitted_as_nil, :string
|
10
|
+
attribute :omitted_as_empty, :string
|
11
|
+
|
12
|
+
attribute :nil_as_nil, :string
|
13
|
+
attribute :nil_as_omitted, :string
|
14
|
+
attribute :nil_as_empty, :string
|
15
|
+
|
16
|
+
attribute :empty_as_empty, :string
|
17
|
+
attribute :empty_as_nil, :string
|
18
|
+
attribute :empty_as_omitted, :string
|
19
|
+
|
20
|
+
xml do
|
21
|
+
root "WithValueMaps"
|
22
|
+
|
23
|
+
map_element "omittedAsOmitted", to: :omitted_as_omitted, value_map: {
|
24
|
+
from: { omitted: :omitted },
|
25
|
+
to: { omitted: :omitted },
|
26
|
+
}
|
27
|
+
map_element "omittedAsNil", to: :omitted_as_nil, value_map: {
|
28
|
+
from: { omitted: :nil },
|
29
|
+
to: { omitted: :nil },
|
30
|
+
}
|
31
|
+
map_element "omittedAsEmpty", to: :omitted_as_empty, value_map: {
|
32
|
+
from: { omitted: :empty },
|
33
|
+
to: { omitted: :empty },
|
34
|
+
}
|
35
|
+
|
36
|
+
map_element "nilAsNil", to: :nil_as_nil, value_map: {
|
37
|
+
from: { nil: :nil },
|
38
|
+
to: { nil: :nil },
|
39
|
+
}
|
40
|
+
map_element "nilAsOmitted", to: :nil_as_omitted, value_map: {
|
41
|
+
from: { nil: :omitted },
|
42
|
+
to: { nil: :omitted },
|
43
|
+
}
|
44
|
+
map_element "nilAsEmpty", to: :nil_as_empty, value_map: {
|
45
|
+
from: { nil: :empty },
|
46
|
+
to: { nil: :empty },
|
47
|
+
}
|
48
|
+
|
49
|
+
map_element "emptyAsEmpty", to: :empty_as_empty, value_map: {
|
50
|
+
from: { empty: :empty },
|
51
|
+
to: { empty: :empty },
|
52
|
+
}
|
53
|
+
map_element "emptyAsNil", to: :empty_as_nil, value_map: {
|
54
|
+
from: { empty: :nil },
|
55
|
+
to: { empty: :nil },
|
56
|
+
}
|
57
|
+
map_element "emptyAsOmitted", to: :empty_as_omitted, value_map: {
|
58
|
+
from: { empty: :omitted },
|
59
|
+
to: { empty: :omitted },
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
key_value do
|
64
|
+
map "omitted_as_omitted", to: :omitted_as_omitted, value_map: {
|
65
|
+
from: { omitted: :omitted },
|
66
|
+
to: { omitted: :omitted },
|
67
|
+
}
|
68
|
+
map "omitted_as_nil", to: :omitted_as_nil, value_map: {
|
69
|
+
from: { omitted: :omitted },
|
70
|
+
to: { omitted: :nil },
|
71
|
+
}
|
72
|
+
map "omitted_as_empty", to: :omitted_as_empty, value_map: {
|
73
|
+
from: { omitted: :omitted },
|
74
|
+
to: { omitted: :empty },
|
75
|
+
}
|
76
|
+
|
77
|
+
map "nil_as_nil", to: :nil_as_nil, value_map: {
|
78
|
+
from: { nil: :nil },
|
79
|
+
to: { nil: :nil },
|
80
|
+
}
|
81
|
+
map "nil_as_omitted", to: :nil_as_omitted, value_map: {
|
82
|
+
from: { nil: :nil },
|
83
|
+
to: { nil: :omitted },
|
84
|
+
}
|
85
|
+
map "nil_as_empty", to: :nil_as_empty, value_map: {
|
86
|
+
from: { nil: :nil },
|
87
|
+
to: { nil: :empty },
|
88
|
+
}
|
89
|
+
|
90
|
+
map "empty_as_empty", to: :empty_as_empty, value_map: {
|
91
|
+
from: { empty: :empty },
|
92
|
+
to: { empty: :empty },
|
93
|
+
}
|
94
|
+
map "empty_as_nil", to: :empty_as_nil, value_map: {
|
95
|
+
from: { empty: :empty },
|
96
|
+
to: { empty: :nil },
|
97
|
+
}
|
98
|
+
map "empty_as_omitted", to: :empty_as_omitted, value_map: {
|
99
|
+
from: { empty: :empty },
|
100
|
+
to: { empty: :omitted },
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
RSpec.describe "ValueMap" do
|
107
|
+
describe "YAML" do
|
108
|
+
let(:model) do
|
109
|
+
uninitialized = Lutaml::Model::UninitializedClass.instance
|
110
|
+
|
111
|
+
ValueMapSpec::WithValueMaps.new(
|
112
|
+
omitted_as_omitted: uninitialized,
|
113
|
+
omitted_as_nil: uninitialized,
|
114
|
+
omitted_as_empty: uninitialized,
|
115
|
+
nil_as_nil: nil,
|
116
|
+
nil_as_omitted: nil,
|
117
|
+
nil_as_empty: nil,
|
118
|
+
empty_as_empty: "",
|
119
|
+
empty_as_nil: "",
|
120
|
+
empty_as_omitted: "",
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
let(:parsed) { ValueMapSpec::WithValueMaps.from_yaml(yaml) }
|
125
|
+
|
126
|
+
let(:expected_yaml) do
|
127
|
+
<<~YAML
|
128
|
+
---
|
129
|
+
omitted_as_nil:
|
130
|
+
omitted_as_empty: ''
|
131
|
+
nil_as_nil:
|
132
|
+
nil_as_empty: ''
|
133
|
+
empty_as_empty: ''
|
134
|
+
empty_as_nil:
|
135
|
+
YAML
|
136
|
+
end
|
137
|
+
|
138
|
+
let(:yaml) do
|
139
|
+
<<~YAML
|
140
|
+
---
|
141
|
+
nil_as_nil:
|
142
|
+
nil_as_omitted:
|
143
|
+
nil_as_empty:
|
144
|
+
empty_as_empty: ''
|
145
|
+
empty_as_nil: ''
|
146
|
+
empty_as_omitted: ''
|
147
|
+
YAML
|
148
|
+
end
|
149
|
+
|
150
|
+
it "serializes correctly" do
|
151
|
+
expect(parsed.to_yaml).to eq(expected_yaml)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "deserializes correctly" do
|
155
|
+
expected = ValueMapSpec::WithValueMaps.new(
|
156
|
+
{
|
157
|
+
nil_as_nil: nil,
|
158
|
+
nil_as_omitted: nil,
|
159
|
+
nil_as_empty: nil,
|
160
|
+
empty_as_empty: "",
|
161
|
+
empty_as_nil: "",
|
162
|
+
empty_as_omitted: "",
|
163
|
+
},
|
164
|
+
{ omitted: :omitted },
|
165
|
+
)
|
166
|
+
|
167
|
+
expect(parsed).to eq(expected)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "XML" do
|
172
|
+
context "when serializing" do
|
173
|
+
let(:model) do
|
174
|
+
ValueMapSpec::WithValueMaps.new(
|
175
|
+
{
|
176
|
+
nil_as_nil: nil,
|
177
|
+
nil_as_omitted: nil,
|
178
|
+
nil_as_empty: nil,
|
179
|
+
empty_as_empty: "",
|
180
|
+
empty_as_nil: "",
|
181
|
+
empty_as_omitted: "",
|
182
|
+
},
|
183
|
+
{ omitted: :omitted },
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
let(:expected_xml) do
|
188
|
+
<<~XML.strip
|
189
|
+
<WithValueMaps>
|
190
|
+
<omittedAsNil xsi:nil="true"/>
|
191
|
+
<omittedAsEmpty/>
|
192
|
+
<nilAsNil xsi:nil="true"/>
|
193
|
+
<nilAsEmpty/>
|
194
|
+
<emptyAsEmpty/>
|
195
|
+
<emptyAsNil xsi:nil="true"/>
|
196
|
+
</WithValueMaps>
|
197
|
+
XML
|
198
|
+
end
|
199
|
+
|
200
|
+
it "sets correct values when serializing" do
|
201
|
+
expect(model.to_xml).to eq(expected_xml)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "when deserializing" do
|
206
|
+
let(:xml) do
|
207
|
+
<<~XML
|
208
|
+
<WithValueMaps>
|
209
|
+
<nilAsNil xsi:nil="true" />
|
210
|
+
<nilAsOmitted xsi:nil="true" />
|
211
|
+
<nilAsEmpty xsi:nil="true" />
|
212
|
+
<emptyAsEmpty/>
|
213
|
+
<emptyAsNil/>
|
214
|
+
<emptyAsOmitted/>
|
215
|
+
</WithValueMaps>
|
216
|
+
XML
|
217
|
+
end
|
218
|
+
|
219
|
+
let(:parsed) { ValueMapSpec::WithValueMaps.from_xml(xml) }
|
220
|
+
|
221
|
+
let(:expected) do
|
222
|
+
ValueMapSpec::WithValueMaps.new(
|
223
|
+
{
|
224
|
+
nil_as_nil: nil,
|
225
|
+
nil_as_empty: "",
|
226
|
+
empty_as_empty: "",
|
227
|
+
empty_as_nil: nil,
|
228
|
+
omitted_as_nil: nil,
|
229
|
+
omitted_as_empty: "",
|
230
|
+
},
|
231
|
+
{ omitted: :omitted },
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "sets correct values when deserializing" do
|
236
|
+
expect(parsed).to eq(expected)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# <Base xmlns:test="https://test-namespace">
|
2
|
+
# <test:Element1>
|
3
|
+
# <test:Element>Value</test:Element>
|
4
|
+
# <ElementWithoutNamespace>
|
5
|
+
# <NestedElementWithoutNamespace>
|
6
|
+
# Value for nested element without namespace
|
7
|
+
# </NestedElementWithoutNamespace>
|
8
|
+
# </ElementWithoutNamespace>
|
9
|
+
# </test:Element1>
|
10
|
+
# </Base>
|
11
|
+
|
12
|
+
module NestedWithExplicitNamespaceSpec
|
13
|
+
class NestedElementWithoutNamespace < Lutaml::Model::Serializable
|
14
|
+
attribute :nested_element_without_namespace, :string
|
15
|
+
|
16
|
+
xml do
|
17
|
+
map_element "NestedElementWithoutNamespace",
|
18
|
+
to: :nested_element_without_namespace
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ElementWithoutNamespace < Lutaml::Model::Serializable
|
23
|
+
attribute :nested_element_without_namespace, :string
|
24
|
+
|
25
|
+
xml do
|
26
|
+
map_element "NestedElementWithoutNamespace",
|
27
|
+
to: :nested_element_without_namespace
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Element1 < Lutaml::Model::Serializable
|
32
|
+
attribute :element, :string
|
33
|
+
attribute :element_without_namespace, ElementWithoutNamespace
|
34
|
+
|
35
|
+
xml do
|
36
|
+
map_element "Element", to: :element
|
37
|
+
map_element "ElementWithoutNamespace", to: :element_without_namespace,
|
38
|
+
namespace: nil,
|
39
|
+
prefix: nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Base < Lutaml::Model::Serializable
|
44
|
+
attribute :element1, Element1
|
45
|
+
|
46
|
+
xml do
|
47
|
+
root "Base"
|
48
|
+
namespace "https://test-namespace", "test"
|
49
|
+
|
50
|
+
map_element "Element1", to: :element1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
RSpec.describe "NestedWithExplicitNamespace" do
|
56
|
+
let(:xml) do
|
57
|
+
<<~XML
|
58
|
+
<Base xmlns:test="https://test-namespace">
|
59
|
+
<test:Element1>
|
60
|
+
<test:Element>Value</test:Element>
|
61
|
+
<ElementWithoutNamespace>
|
62
|
+
<NestedElementWithoutNamespace>
|
63
|
+
Value for nested element without namespace
|
64
|
+
</NestedElementWithoutNamespace>
|
65
|
+
</ElementWithoutNamespace>
|
66
|
+
</test:Element1>
|
67
|
+
</Base>
|
68
|
+
XML
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:parsed) { NestedWithExplicitNamespaceSpec::Base.from_xml(xml) }
|
72
|
+
|
73
|
+
it "parses namespaced element correctly" do
|
74
|
+
expect(parsed.element1.element).to eq("Value")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "parses nested element without namespace correclty" do
|
78
|
+
generated_value = parsed.element1
|
79
|
+
.element_without_namespace
|
80
|
+
.nested_element_without_namespace
|
81
|
+
.strip
|
82
|
+
|
83
|
+
expect(generated_value).to eq("Value for nested element without namespace")
|
84
|
+
end
|
85
|
+
end
|