lutaml-model 0.7.1 → 0.7.3

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.rubocop_todo.yml +49 -48
  4. data/Gemfile +4 -1
  5. data/README.adoc +791 -143
  6. data/RELEASE_NOTES.adoc +346 -0
  7. data/docs/custom_adapters.adoc +144 -0
  8. data/lib/lutaml/model/attribute.rb +17 -11
  9. data/lib/lutaml/model/config.rb +48 -42
  10. data/lib/lutaml/model/error/polymorphic_error.rb +7 -2
  11. data/lib/lutaml/model/format_registry.rb +41 -0
  12. data/lib/lutaml/model/hash/document.rb +11 -0
  13. data/lib/lutaml/model/hash/mapping.rb +19 -0
  14. data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
  15. data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
  16. data/lib/lutaml/model/hash/transform.rb +8 -0
  17. data/lib/lutaml/model/hash.rb +21 -0
  18. data/lib/lutaml/model/json/document.rb +11 -0
  19. data/lib/lutaml/model/json/mapping.rb +19 -0
  20. data/lib/lutaml/model/json/mapping_rule.rb +9 -0
  21. data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
  22. data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
  23. data/lib/lutaml/model/json/transform.rb +8 -0
  24. data/lib/lutaml/model/json.rb +21 -0
  25. data/lib/lutaml/model/key_value_document.rb +27 -0
  26. data/lib/lutaml/model/mapping/key_value_mapping.rb +8 -4
  27. data/lib/lutaml/model/mapping/mapping.rb +13 -0
  28. data/lib/lutaml/model/mapping/mapping_rule.rb +7 -6
  29. data/lib/lutaml/model/serialization_adapter.rb +22 -0
  30. data/lib/lutaml/model/serialize.rb +146 -521
  31. data/lib/lutaml/model/services/logger.rb +54 -0
  32. data/lib/lutaml/model/services/transformer.rb +48 -0
  33. data/lib/lutaml/model/services.rb +2 -0
  34. data/lib/lutaml/model/toml/document.rb +11 -0
  35. data/lib/lutaml/model/toml/mapping.rb +27 -0
  36. data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
  37. data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
  38. data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
  39. data/lib/lutaml/model/toml/transform.rb +8 -0
  40. data/lib/lutaml/model/toml.rb +30 -0
  41. data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
  42. data/lib/lutaml/model/transform/xml_transform.rb +239 -0
  43. data/lib/lutaml/model/transform.rb +78 -0
  44. data/lib/lutaml/model/type/value.rb +6 -9
  45. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  46. data/lib/lutaml/model/utils.rb +30 -0
  47. data/lib/lutaml/model/version.rb +1 -1
  48. data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
  49. data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
  50. data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
  51. data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +6 -7
  52. data/lib/lutaml/model/xml/element.rb +32 -0
  53. data/lib/lutaml/model/xml/mapping.rb +410 -0
  54. data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
  55. data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
  56. data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
  57. data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
  58. data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
  59. data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
  60. data/lib/lutaml/model/xml/transform.rb +8 -0
  61. data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
  62. data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +6 -3
  63. data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
  64. data/lib/lutaml/model/xml.rb +31 -0
  65. data/lib/lutaml/model/xml_adapter/element.rb +11 -25
  66. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
  67. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
  68. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
  69. data/lib/lutaml/model/yaml/document.rb +10 -0
  70. data/lib/lutaml/model/yaml/mapping.rb +19 -0
  71. data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
  72. data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
  73. data/lib/lutaml/model/yaml/transform.rb +8 -0
  74. data/lib/lutaml/model/yaml.rb +21 -0
  75. data/lib/lutaml/model.rb +39 -4
  76. data/lutaml-model.gemspec +0 -4
  77. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -4
  78. data/spec/lutaml/model/cdata_spec.rb +7 -7
  79. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
  80. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
  81. data/spec/lutaml/model/group_spec.rb +18 -7
  82. data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
  83. data/spec/lutaml/model/json_adapter_spec.rb +6 -6
  84. data/spec/lutaml/model/key_value_mapping_spec.rb +25 -1
  85. data/spec/lutaml/model/mixed_content_spec.rb +24 -24
  86. data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
  87. data/spec/lutaml/model/ordered_content_spec.rb +6 -6
  88. data/spec/lutaml/model/polymorphic_spec.rb +178 -0
  89. data/spec/lutaml/model/root_mappings_spec.rb +3 -3
  90. data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
  91. data/spec/lutaml/model/serializable_spec.rb +179 -103
  92. data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
  93. data/spec/lutaml/model/toml_spec.rb +51 -0
  94. data/spec/lutaml/model/transformation_spec.rb +72 -15
  95. data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
  96. data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
  97. data/spec/lutaml/model/xml/xml_element_spec.rb +1 -1
  98. data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
  99. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  100. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  101. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
  102. data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
  103. data/spec/lutaml/model/xml_mapping_rule_spec.rb +3 -3
  104. data/spec/lutaml/model/xml_mapping_spec.rb +26 -14
  105. data/spec/lutaml/model/xml_spec.rb +63 -0
  106. data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
  107. data/spec/spec_helper.rb +3 -3
  108. metadata +64 -59
  109. data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
  110. data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
  111. data/lib/lutaml/model/loggable.rb +0 -15
  112. data/lib/lutaml/model/mapping/json_mapping.rb +0 -17
  113. data/lib/lutaml/model/mapping/toml_mapping.rb +0 -25
  114. data/lib/lutaml/model/mapping/xml_mapping.rb +0 -389
  115. data/lib/lutaml/model/mapping/xml_mapping_rule.rb +0 -139
  116. data/lib/lutaml/model/mapping/yaml_mapping.rb +0 -17
  117. data/lib/lutaml/model/mapping.rb +0 -14
  118. data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
  119. data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
  120. data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
  121. data/lib/lutaml/model/toml_adapter.rb +0 -6
  122. data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
  123. data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
  124. data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -47,12 +47,63 @@ module PolymorphicSpec
47
47
  end
48
48
  end
49
49
 
50
+ module InvalidClasses
51
+ class AnchorReference < Lutaml::Model::Serializable
52
+ attribute :anchor_id, :string
53
+
54
+ xml do
55
+ map_element "anchor_id", to: :anchor_id
56
+ end
57
+
58
+ key_value do
59
+ map "anchor_id", to: :anchor_id
60
+ end
61
+ end
62
+
63
+ class DocumentReference < Reference
64
+ attribute :document_id, :string
65
+
66
+ xml do
67
+ map_element "document_id", to: :document_id
68
+ end
69
+
70
+ key_value do
71
+ map "document_id", to: :document_id
72
+ end
73
+ end
74
+ end
75
+
50
76
  class ReferenceSet < Lutaml::Model::Serializable
51
77
  attribute :references, Reference, collection: true, polymorphic: [
52
78
  DocumentReference,
53
79
  AnchorReference,
54
80
  ]
55
81
  end
82
+
83
+ class SimpleReferenceSet < Lutaml::Model::Serializable
84
+ attribute :references, Reference, collection: true, polymorphic: true
85
+
86
+ xml do
87
+ root "ReferenceSet"
88
+ map_element "references", to: :references, polymorphic: {
89
+ attribute: "reference-type",
90
+ class_map: {
91
+ "document-ref" => "PolymorphicSpec::Base::DocumentReference",
92
+ "anchor-ref" => "PolymorphicSpec::Base::AnchorReference",
93
+ },
94
+ }
95
+ end
96
+
97
+ key_value do
98
+ map "references", to: :references, polymorphic: {
99
+ attribute: "_class",
100
+ class_map: {
101
+ "Document" => "PolymorphicSpec::Base::DocumentReference",
102
+ "Anchor" => "PolymorphicSpec::Base::AnchorReference",
103
+ },
104
+ }
105
+ end
106
+ end
56
107
  end
57
108
 
58
109
  module Child
@@ -226,6 +277,133 @@ RSpec.describe "Polymorphic" do
226
277
  end
227
278
  end
228
279
 
280
+ context "when using polymorphic: true option" do
281
+ context "when key_value formats" do
282
+ let(:reference_set) do
283
+ PolymorphicSpec::Base::SimpleReferenceSet.new(
284
+ references: [
285
+ PolymorphicSpec::Base::DocumentReference.new(
286
+ _class: "Document",
287
+ document_id: "book:tbtd",
288
+ name: "The Tibetan Book of the Dead",
289
+ ),
290
+ PolymorphicSpec::Base::AnchorReference.new(
291
+ _class: "Anchor",
292
+ anchor_id: "book:tbtd:anchor-1",
293
+ name: "Chapter 1",
294
+ ),
295
+ ],
296
+ )
297
+ end
298
+
299
+ let(:invalid_reference_set) do
300
+ PolymorphicSpec::Base::SimpleReferenceSet.new(
301
+ references: [
302
+ PolymorphicSpec::Base::InvalidClasses::DocumentReference.new(
303
+ _class: "Document",
304
+ document_id: "book:tbtd",
305
+ name: "The Tibetan Book of the Dead",
306
+ ),
307
+ PolymorphicSpec::Base::InvalidClasses::AnchorReference.new(
308
+ _class: "Anchor",
309
+ anchor_id: "book:tbtd:anchor-1",
310
+ name: "Chapter 1",
311
+ ),
312
+ ],
313
+ )
314
+ end
315
+
316
+ let(:yaml) do
317
+ <<~YAML
318
+ ---
319
+ references:
320
+ - _class: Document
321
+ name: The Tibetan Book of the Dead
322
+ document_id: book:tbtd
323
+ - _class: Anchor
324
+ name: Chapter 1
325
+ anchor_id: book:tbtd:anchor-1
326
+ YAML
327
+ end
328
+
329
+ let(:parsed_yaml) do
330
+ PolymorphicSpec::Base::SimpleReferenceSet.from_yaml(yaml)
331
+ end
332
+
333
+ let(:error_message) do
334
+ "PolymorphicSpec::Base::InvalidClasses::AnchorReference is not " \
335
+ "valid sub class of PolymorphicSpec::Base::Reference"
336
+ end
337
+
338
+ it "deserializes correctly" do
339
+ expect(parsed_yaml).to eq(reference_set)
340
+ end
341
+
342
+ it "serializes correctly" do
343
+ expect(parsed_yaml.to_yaml).to eq(yaml)
344
+ end
345
+
346
+ it "raises error" do
347
+ expect do
348
+ invalid_reference_set.validate!
349
+ end.to raise_error(Lutaml::Model::ValidationError, error_message)
350
+ end
351
+ end
352
+
353
+ context "when XML format" do
354
+ let(:reference_set) do
355
+ PolymorphicSpec::Base::SimpleReferenceSet.new(
356
+ references: [
357
+ PolymorphicSpec::Base::DocumentReference.new(
358
+ _class: "document-ref",
359
+ document_id: "book:tbtd",
360
+ name: "The Tibetan Book of the Dead",
361
+ ),
362
+ PolymorphicSpec::Base::AnchorReference.new(
363
+ _class: "anchor-ref",
364
+ anchor_id: "book:tbtd:anchor-1",
365
+ name: "Chapter 1",
366
+ ),
367
+ ],
368
+ )
369
+ end
370
+ let(:xml) do
371
+ <<~XML
372
+ <ReferenceSet>
373
+ <references reference-type="document-ref">
374
+ <name>The Tibetan Book of the Dead</name>
375
+ <document_id>book:tbtd</document_id>
376
+ </references>
377
+ <references reference-type="anchor-ref">
378
+ <name>Chapter 1</name>
379
+ <anchor_id>book:tbtd:anchor-1</anchor_id>
380
+ </references>
381
+ </ReferenceSet>
382
+ XML
383
+ end
384
+
385
+ let(:parsed_xml) do
386
+ PolymorphicSpec::Base::SimpleReferenceSet.from_xml(xml)
387
+ end
388
+
389
+ it "deserializes correctly" do
390
+ expect(parsed_xml).to eq(reference_set)
391
+ end
392
+
393
+ it "serializes correctly" do
394
+ expect(parsed_xml.to_xml.strip).to be_equivalent_to(xml.strip)
395
+ end
396
+
397
+ it "does not raise error if polymorphic is set to true" do
398
+ expect { reference_set.validate! }.not_to raise_error
399
+ end
400
+
401
+ it "has empty errors array on validate" do
402
+ expect(reference_set.validate).to eq([])
403
+ end
404
+ end
405
+ end
406
+
229
407
  context "when defined in child class" do
230
408
  context "when key_value formats" do
231
409
  let(:reference_set) do
@@ -283,15 +283,15 @@ RSpec.describe "RootMapping" do
283
283
  end
284
284
  end
285
285
 
286
- describe Lutaml::Model::YamlAdapter::StandardYamlAdapter do
286
+ describe Lutaml::Model::Yaml::StandardAdapter do
287
287
  it_behaves_like "having root mappings", :yaml
288
288
  end
289
289
 
290
- describe Lutaml::Model::JsonAdapter::StandardJsonAdapter do
290
+ describe Lutaml::Model::Json::StandardAdapter do
291
291
  it_behaves_like "having root mappings", :json
292
292
  end
293
293
 
294
- describe Lutaml::Model::TomlAdapter::TomlRbAdapter do
294
+ describe Lutaml::Model::Toml::TomlRbAdapter do
295
295
  it_behaves_like "having root mappings", :toml
296
296
  end
297
297
  end
@@ -471,7 +471,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
471
471
  Lutaml::Xsd::SimpleContent.new.tap do |ct|
472
472
  ct.extension = Lutaml::Xsd::ExtensionSimpleContent.new(base: "test_extension")
473
473
  ct.element_order = [
474
- Lutaml::Model::XmlAdapter::Element.new("Element", "extension"),
474
+ Lutaml::Model::Xml::Element.new("Element", "extension"),
475
475
  ]
476
476
  end
477
477
  end
@@ -488,7 +488,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
488
488
  Lutaml::Xsd::SimpleContent.new.tap do |ct|
489
489
  ct.restriction = Lutaml::Xsd::RestrictionSimpleContent.new(base: "test_restriction")
490
490
  ct.element_order = [
491
- Lutaml::Model::XmlAdapter::Element.new("Element", "restriction"),
491
+ Lutaml::Model::Xml::Element.new("Element", "restriction"),
492
492
  ]
493
493
  end
494
494
  end
@@ -870,7 +870,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
870
870
  element.min_occurs = 0
871
871
  element.max_occurs = 1
872
872
  element.complex_type = Lutaml::Xsd::ComplexType.new(name: "test_complex_type")
873
- element.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "complex_type")]
873
+ element.element_order = [Lutaml::Model::Xml::Element.new("Element", "complex_type")]
874
874
  end
875
875
  end
876
876
 
@@ -910,7 +910,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
910
910
  element.type = "test_type"
911
911
  element.name = "test_name"
912
912
  element.complex_type = Lutaml::Xsd::ComplexType.new(name: "test_complex_type")
913
- element.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "complex_type")]
913
+ element.element_order = [Lutaml::Model::Xml::Element.new("Element", "complex_type")]
914
914
  end
915
915
  end
916
916
 
@@ -1143,7 +1143,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
1143
1143
  end
1144
1144
 
1145
1145
  it "raises an error when element_order contains elements that isn't an attribute of the instance" do
1146
- element.element_order << Lutaml::Model::XmlAdapter::Element.new("Element", "test_element")
1146
+ element.element_order << Lutaml::Model::Xml::Element.new("Element", "test_element")
1147
1147
  expect { resolved_element_order }.to raise_error(NoMethodError)
1148
1148
  end
1149
1149
 
@@ -1915,7 +1915,7 @@ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
1915
1915
  end
1916
1916
 
1917
1917
  def create_pattern_mapping(array)
1918
- array.map { |type, text| Lutaml::Model::XmlAdapter::Element.new(type, text) }
1918
+ array.map { |type, text| Lutaml::Model::Xml::Element.new(type, text) }
1919
1919
  end
1920
1920
 
1921
1921
  def to_mapping_hash(content)
@@ -96,6 +96,48 @@ module SerializeableSpec
96
96
  }
97
97
  end
98
98
  end
99
+
100
+ ### Single option serialization
101
+
102
+ class SingleOptionModel < Lutaml::Model::Serializable
103
+ attribute :name, :string
104
+ attribute :age, :integer
105
+ attribute :phone, :string
106
+ attribute :address, :string
107
+
108
+ json do
109
+ map "name", to: :name
110
+ map "age", to: :age
111
+ map "phone", to: :phone, with: { to: :phone_to_json }
112
+ map "address", to: :address, with: { from: :address_from_json }
113
+ end
114
+
115
+ xml do
116
+ root "person"
117
+ map_element "name", to: :name
118
+ map_element "age", to: :age
119
+ map_element "phone", to: :phone, with: { to: :phone_to_xml }
120
+ map_element "address", to: :address, with: { from: :address_from_xml }
121
+ end
122
+
123
+ def phone_to_json(model, doc)
124
+ doc["phone"] = "+1-#{model.phone}"
125
+ end
126
+
127
+ def address_from_json(model, value)
128
+ model.address = value.sub(/^Address: /, "")
129
+ end
130
+
131
+ def phone_to_xml(model, parent, doc)
132
+ el = doc.create_element("phone")
133
+ doc.add_text(el, "+1-#{model.phone}")
134
+ doc.add_element(parent, el)
135
+ end
136
+
137
+ def address_from_xml(model, value)
138
+ model.address = value.text.sub(/^Address: /, "")
139
+ end
140
+ end
99
141
  end
100
142
 
101
143
  RSpec.describe Lutaml::Model::Serializable do
@@ -151,48 +193,6 @@ RSpec.describe Lutaml::Model::Serializable do
151
193
  end
152
194
  end
153
195
 
154
- describe ".hash_representation" do
155
- context "when model is separate" do
156
- let(:instance) do
157
- SerializeableSpec::TestModel.new(name: "John", age: 18)
158
- end
159
-
160
- let(:expected_hash) do
161
- {
162
- "name" => "John",
163
- "age" => "18",
164
- }
165
- end
166
-
167
- it "return hash representation" do
168
- generate_hash = SerializeableSpec::TestModelMapper.hash_representation(
169
- instance, :yaml
170
- )
171
- expect(generate_hash).to eq(expected_hash)
172
- end
173
- end
174
-
175
- context "when model is self" do
176
- let(:instance) do
177
- SerializeableSpec::TestMapper.new(name: "John", age: 18)
178
- end
179
-
180
- let(:expected_hash) do
181
- {
182
- "na" => "John",
183
- "ag" => "18",
184
- }
185
- end
186
-
187
- it "return hash representation" do
188
- generate_hash = SerializeableSpec::TestMapper.hash_representation(
189
- instance, :yaml
190
- )
191
- expect(generate_hash).to eq(expected_hash)
192
- end
193
- end
194
- end
195
-
196
196
  describe ".mappings_for" do
197
197
  context "when mapping is defined" do
198
198
  it "returns the defined mapping" do
@@ -221,67 +221,68 @@ RSpec.describe Lutaml::Model::Serializable do
221
221
  end
222
222
  end
223
223
 
224
- describe ".translate_mappings" do
225
- let(:child_mappings) do
226
- {
227
- id: :key,
228
- path: %i[path link],
229
- name: %i[path name],
230
- }
231
- end
232
-
233
- let(:hash) do
234
- {
235
- "foo" => {
236
- "path" => {
237
- "link" => "link one",
238
- "name" => "one",
239
- },
240
- },
241
- "abc" => {
242
- "path" => {
243
- "link" => "link two",
244
- "name" => "two",
245
- },
246
- },
247
- "hello" => {
248
- "path" => {
249
- "link" => "link three",
250
- "name" => "three",
251
- },
252
- },
253
- }
254
- end
255
-
256
- let(:attr) { SerializeableSpec::TranslateMappings.attributes[:translate] }
257
-
258
- let(:expected_value) do
259
- [
260
- SerializeableSpec::TranslateHelper.new({
261
- "id" => "foo",
262
- "name" => "one",
263
- "path" => "link one",
264
- }),
265
- SerializeableSpec::TranslateHelper.new({
266
- "id" => "abc",
267
- "name" => "two",
268
- "path" => "link two",
269
- }),
270
- SerializeableSpec::TranslateHelper.new({
271
- "id" => "hello",
272
- "name" => "three",
273
- "path" => "link three",
274
- }),
275
- ]
276
- end
277
-
278
- it "generates hash based on child_mappings" do
279
- actual_value = described_class.translate_mappings(hash, child_mappings, attr, :yaml)
280
-
281
- expect(actual_value.map { |obj| [obj.id, obj.name, obj.path] })
282
- .to eq(expected_value.map { |obj| [obj.id, obj.name, obj.path] })
283
- end
284
- end
224
+ # TODO: Move to key_value_transform specs
225
+ # describe ".translate_mappings" do
226
+ # let(:child_mappings) do
227
+ # {
228
+ # id: :key,
229
+ # path: %i[path link],
230
+ # name: %i[path name],
231
+ # }
232
+ # end
233
+
234
+ # let(:hash) do
235
+ # {
236
+ # "foo" => {
237
+ # "path" => {
238
+ # "link" => "link one",
239
+ # "name" => "one",
240
+ # },
241
+ # },
242
+ # "abc" => {
243
+ # "path" => {
244
+ # "link" => "link two",
245
+ # "name" => "two",
246
+ # },
247
+ # },
248
+ # "hello" => {
249
+ # "path" => {
250
+ # "link" => "link three",
251
+ # "name" => "three",
252
+ # },
253
+ # },
254
+ # }
255
+ # end
256
+
257
+ # let(:attr) { SerializeableSpec::TranslateMappings.attributes[:translate] }
258
+
259
+ # let(:expected_value) do
260
+ # [
261
+ # SerializeableSpec::TranslateHelper.new({
262
+ # "id" => "foo",
263
+ # "name" => "one",
264
+ # "path" => "link one",
265
+ # }),
266
+ # SerializeableSpec::TranslateHelper.new({
267
+ # "id" => "abc",
268
+ # "name" => "two",
269
+ # "path" => "link two",
270
+ # }),
271
+ # SerializeableSpec::TranslateHelper.new({
272
+ # "id" => "hello",
273
+ # "name" => "three",
274
+ # "path" => "link three",
275
+ # }),
276
+ # ]
277
+ # end
278
+
279
+ # it "generates hash based on child_mappings" do
280
+ # actual_value = described_class.translate_mappings(hash, child_mappings, attr, :yaml)
281
+
282
+ # expect(actual_value.map { |obj| [obj.id, obj.name, obj.path] })
283
+ # .to eq(expected_value.map { |obj| [obj.id, obj.name, obj.path] })
284
+ # end
285
+ # end
285
286
 
286
287
  describe "#key_value" do
287
288
  let(:model) { SerializeableSpec::KeyValueMapper }
@@ -386,4 +387,79 @@ RSpec.describe Lutaml::Model::Serializable do
386
387
  end
387
388
  end
388
389
  end
390
+
391
+ describe "Single option serialization" do
392
+ let(:attributes) do
393
+ {
394
+ name: "John Doe",
395
+ age: 30,
396
+ phone: "123-456-7890",
397
+ address: "123 Main St",
398
+ }
399
+ end
400
+
401
+ let(:model) { SerializeableSpec::SingleOptionModel.new(attributes) }
402
+
403
+ describe "JSON serialization" do
404
+ let(:expected_json) do
405
+ {
406
+ name: "John Doe",
407
+ age: 30,
408
+ phone: "+1-123-456-7890",
409
+ address: "123 Main St",
410
+ }.to_json
411
+ end
412
+
413
+ let(:parsed) do
414
+ SerializeableSpec::SingleOptionModel.from_json(
415
+ {
416
+ name: "John Doe",
417
+ age: 30,
418
+ phone: "123-456-7890",
419
+ address: "Address: 123 Main St",
420
+ }.to_json,
421
+ )
422
+ end
423
+
424
+ it "serializes to JSON with custom name transformation" do
425
+ expect(model.to_json).to eq(expected_json)
426
+ end
427
+
428
+ it "deserializes from JSON with custom name transformation" do
429
+ expect(parsed).to eq(model)
430
+ end
431
+ end
432
+
433
+ describe "XML serialization" do
434
+ let(:expected_xml) do
435
+ <<~XML
436
+ <person>
437
+ <name>John Doe</name>
438
+ <age>30</age>
439
+ <phone>+1-123-456-7890</phone>
440
+ <address>123 Main St</address>
441
+ </person>
442
+ XML
443
+ end
444
+
445
+ let(:parsed) do
446
+ SerializeableSpec::SingleOptionModel.from_xml <<~XML
447
+ <person>
448
+ <name>John Doe</name>
449
+ <age>30</age>
450
+ <phone>123-456-7890</phone>
451
+ <address>Address: 123 Main St</address>
452
+ </person>
453
+ XML
454
+ end
455
+
456
+ it "serializes to XML with custom name transformation" do
457
+ expect(model.to_xml).to be_equivalent_to(expected_xml)
458
+ end
459
+
460
+ it "deserializes from XML with custom name transformation" do
461
+ expect(parsed).to eq(model)
462
+ end
463
+ end
464
+ end
389
465
  end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
- require "lutaml/model/toml_adapter/toml_rb_adapter"
3
- require "lutaml/model/toml_adapter/tomlib_adapter"
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::TomlAdapter::TomlRbAdapter
12
+ if adapter_class == Lutaml::Model::Toml::TomlRbAdapter
13
13
  TomlRB.dump(attributes)
14
- elsif adapter_class == Lutaml::Model::TomlAdapter::TomlibAdapter
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::TomlAdapter::TomlRbAdapter do
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::TomlAdapter::TomlibAdapter do
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