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.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos-todo.json +7 -0
  3. data/.github/workflows/dependent-repos.json +17 -9
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +51 -65
  6. data/Gemfile +4 -1
  7. data/README.adoc +5083 -2612
  8. data/RELEASE_NOTES.adoc +346 -0
  9. data/docs/custom_adapters.adoc +144 -0
  10. data/lib/lutaml/model/attribute.rb +101 -16
  11. data/lib/lutaml/model/choice.rb +7 -0
  12. data/lib/lutaml/model/comparable_model.rb +48 -9
  13. data/lib/lutaml/model/config.rb +48 -42
  14. data/lib/lutaml/model/error/collection_count_out_of_range_error.rb +1 -1
  15. data/lib/lutaml/model/error/polymorphic_error.rb +14 -0
  16. data/lib/lutaml/model/error.rb +1 -0
  17. data/lib/lutaml/model/format_registry.rb +41 -0
  18. data/lib/lutaml/model/hash/document.rb +11 -0
  19. data/lib/lutaml/model/hash/mapping.rb +19 -0
  20. data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
  21. data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
  22. data/lib/lutaml/model/hash/transform.rb +8 -0
  23. data/lib/lutaml/model/hash.rb +21 -0
  24. data/lib/lutaml/model/json/document.rb +11 -0
  25. data/lib/lutaml/model/json/mapping.rb +19 -0
  26. data/lib/lutaml/model/json/mapping_rule.rb +9 -0
  27. data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
  28. data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
  29. data/lib/lutaml/model/json/transform.rb +8 -0
  30. data/lib/lutaml/model/json.rb +21 -0
  31. data/lib/lutaml/model/key_value_document.rb +27 -0
  32. data/lib/lutaml/model/{key_value_mapping.rb → mapping/key_value_mapping.rb} +64 -16
  33. data/lib/lutaml/model/{key_value_mapping_rule.rb → mapping/key_value_mapping_rule.rb} +18 -2
  34. data/lib/lutaml/model/mapping/mapping.rb +13 -0
  35. data/lib/lutaml/model/mapping/mapping_rule.rb +300 -0
  36. data/lib/lutaml/model/schema/xml_compiler.rb +15 -15
  37. data/lib/lutaml/model/sequence.rb +2 -2
  38. data/lib/lutaml/model/serialization_adapter.rb +22 -0
  39. data/lib/lutaml/model/serialize.rb +219 -444
  40. data/lib/lutaml/model/services/logger.rb +54 -0
  41. data/lib/lutaml/model/services/transformer.rb +48 -0
  42. data/lib/lutaml/model/services.rb +2 -0
  43. data/lib/lutaml/model/toml/document.rb +11 -0
  44. data/lib/lutaml/model/toml/mapping.rb +27 -0
  45. data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
  46. data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
  47. data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
  48. data/lib/lutaml/model/toml/transform.rb +8 -0
  49. data/lib/lutaml/model/toml.rb +30 -0
  50. data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
  51. data/lib/lutaml/model/transform/xml_transform.rb +239 -0
  52. data/lib/lutaml/model/transform.rb +78 -0
  53. data/lib/lutaml/model/type/date.rb +1 -1
  54. data/lib/lutaml/model/type/date_time.rb +2 -2
  55. data/lib/lutaml/model/type/hash.rb +1 -1
  56. data/lib/lutaml/model/type/time.rb +2 -2
  57. data/lib/lutaml/model/type/time_without_date.rb +2 -2
  58. data/lib/lutaml/model/type/value.rb +6 -9
  59. data/lib/lutaml/model/uninitialized_class.rb +64 -0
  60. data/lib/lutaml/model/utils.rb +44 -0
  61. data/lib/lutaml/model/validation.rb +1 -0
  62. data/lib/lutaml/model/version.rb +1 -1
  63. data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
  64. data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
  65. data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
  66. data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +41 -21
  67. data/lib/lutaml/model/xml/element.rb +32 -0
  68. data/lib/lutaml/model/xml/mapping.rb +410 -0
  69. data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
  70. data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
  71. data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
  72. data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
  73. data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
  74. data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
  75. data/lib/lutaml/model/xml/transform.rb +8 -0
  76. data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
  77. data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +23 -10
  78. data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
  79. data/lib/lutaml/model/xml.rb +31 -0
  80. data/lib/lutaml/model/xml_adapter/element.rb +11 -25
  81. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
  82. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
  83. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
  84. data/lib/lutaml/model/yaml/document.rb +10 -0
  85. data/lib/lutaml/model/yaml/mapping.rb +19 -0
  86. data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
  87. data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
  88. data/lib/lutaml/model/yaml/transform.rb +8 -0
  89. data/lib/lutaml/model/yaml.rb +21 -0
  90. data/lib/lutaml/model.rb +40 -4
  91. data/lutaml-model.gemspec +0 -4
  92. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +7 -7
  93. data/spec/fixtures/person.rb +5 -5
  94. data/spec/lutaml/model/attribute_spec.rb +37 -1
  95. data/spec/lutaml/model/cdata_spec.rb +9 -9
  96. data/spec/lutaml/model/collection_spec.rb +50 -2
  97. data/spec/lutaml/model/comparable_model_spec.rb +92 -27
  98. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
  99. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
  100. data/spec/lutaml/model/defaults_spec.rb +1 -1
  101. data/spec/lutaml/model/enum_spec.rb +1 -1
  102. data/spec/lutaml/model/group_spec.rb +333 -20
  103. data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
  104. data/spec/lutaml/model/json_adapter_spec.rb +6 -6
  105. data/spec/lutaml/model/key_value_mapping_spec.rb +65 -3
  106. data/spec/lutaml/model/mixed_content_spec.rb +24 -24
  107. data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
  108. data/spec/lutaml/model/ordered_content_spec.rb +6 -6
  109. data/spec/lutaml/model/polymorphic_spec.rb +526 -0
  110. data/spec/lutaml/model/render_empty_spec.rb +194 -0
  111. data/spec/lutaml/model/render_nil_spec.rb +206 -22
  112. data/spec/lutaml/model/root_mappings_spec.rb +3 -3
  113. data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
  114. data/spec/lutaml/model/serializable_spec.rb +179 -103
  115. data/spec/lutaml/model/simple_model_spec.rb +9 -9
  116. data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
  117. data/spec/lutaml/model/toml_spec.rb +51 -0
  118. data/spec/lutaml/model/transformation_spec.rb +72 -15
  119. data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
  120. data/spec/lutaml/model/value_map_spec.rb +240 -0
  121. data/spec/lutaml/model/xml/namespace/nested_with_explicit_namespace_spec.rb +85 -0
  122. data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
  123. data/spec/lutaml/model/xml/xml_element_spec.rb +93 -0
  124. data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
  125. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  126. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  127. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
  128. data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
  129. data/spec/lutaml/model/xml_mapping_rule_spec.rb +105 -5
  130. data/spec/lutaml/model/xml_mapping_spec.rb +70 -16
  131. data/spec/lutaml/model/xml_spec.rb +63 -0
  132. data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
  133. data/spec/sample_model_spec.rb +3 -3
  134. data/spec/spec_helper.rb +3 -3
  135. metadata +76 -59
  136. data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
  137. data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
  138. data/lib/lutaml/model/loggable.rb +0 -15
  139. data/lib/lutaml/model/mapping_rule.rb +0 -109
  140. data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
  141. data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
  142. data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
  143. data/lib/lutaml/model/toml_adapter.rb +0 -6
  144. data/lib/lutaml/model/xml_mapping.rb +0 -307
  145. data/lib/lutaml/model/xml_mapping_rule.rb +0 -122
  146. data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
  147. data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
  148. data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -19,6 +19,11 @@ class ComparableCeramicCollection < Lutaml::Model::Serializable
19
19
  attribute :featured_piece, ComparableCeramic # This creates a two-level nesting
20
20
  end
21
21
 
22
+ class RecursiveNode < Lutaml::Model::Serializable
23
+ attribute :name, :string
24
+ attribute :next_node, RecursiveNode
25
+ end
26
+
22
27
  RSpec.describe Lutaml::Model::ComparableModel do
23
28
  describe "comparisons" do
24
29
  context "with simple types (Glaze)" do
@@ -68,38 +73,98 @@ RSpec.describe Lutaml::Model::ComparableModel do
68
73
  end
69
74
 
70
75
  context "with deeply nested Serializable objects (CeramicCollection)" do
76
+ let(:first_collection) do
77
+ ComparableCeramicCollection.new(
78
+ name: "Blue Collection",
79
+ featured_piece: ComparableCeramic.new(
80
+ type: "Bowl",
81
+ glaze: ComparableGlaze.new(
82
+ color: "Blue",
83
+ temperature: 1200,
84
+ food_safe: true,
85
+ ),
86
+ ),
87
+ )
88
+ end
89
+
90
+ let(:second_collection) do
91
+ ComparableCeramicCollection.new(
92
+ name: "Blue Collection",
93
+ featured_piece: ComparableCeramic.new(
94
+ type: "Bowl",
95
+ glaze: ComparableGlaze.new(
96
+ color: "Blue",
97
+ temperature: 1200,
98
+ food_safe: true,
99
+ ),
100
+ ),
101
+ )
102
+ end
103
+
71
104
  it "compares equal objects with two levels of nesting" do
72
105
  # This test compares CeramicCollection objects that contain Ceramic objects,
73
106
  # which in turn contain Glaze objects - a two-level deep nesting
74
- glaze1 = ComparableGlaze.new(color: "Blue", temperature: 1200,
75
- food_safe: true)
76
- glaze2 = ComparableGlaze.new(color: "Blue", temperature: 1200,
77
- food_safe: true)
78
- ceramic1 = ComparableCeramic.new(type: "Bowl", glaze: glaze1)
79
- ceramic2 = ComparableCeramic.new(type: "Bowl", glaze: glaze2)
80
- collection1 = ComparableCeramicCollection.new(name: "Blue Collection",
81
- featured_piece: ceramic1)
82
- collection2 = ComparableCeramicCollection.new(name: "Blue Collection",
83
- featured_piece: ceramic2)
84
- expect(collection1).to eq(collection2)
85
- expect(collection1.hash).to eq(collection2.hash)
107
+ expect(first_collection).to eq(second_collection)
86
108
  end
87
109
 
88
- it "compares unequal objects with two levels of nesting" do
89
- # This test compares CeramicCollection objects that are different at every level:
90
- # the collection name, the ceramic type, and the glaze properties
91
- glaze1 = ComparableGlaze.new(color: "Blue", temperature: 1200,
92
- food_safe: true)
93
- glaze2 = ComparableGlaze.new(color: "Red", temperature: 1000,
94
- food_safe: false)
95
- ceramic1 = ComparableCeramic.new(type: "Bowl", glaze: glaze1)
96
- ceramic2 = ComparableCeramic.new(type: "Plate", glaze: glaze2)
97
- collection1 = ComparableCeramicCollection.new(name: "Blue Collection",
98
- featured_piece: ceramic1)
99
- collection2 = ComparableCeramicCollection.new(name: "Red Collection",
100
- featured_piece: ceramic2)
101
- expect(collection1).not_to eq(collection2)
102
- expect(collection1.hash).not_to eq(collection2.hash)
110
+ it "generates same hash for objects with two levels of nesting" do
111
+ expect(first_collection.hash).to eq(second_collection.hash)
112
+ end
113
+
114
+ context "with deeply nested objects that are not equal" do
115
+ before do
116
+ second_collection.name = "Red Collection"
117
+ second_collection.featured_piece.type = "Plate"
118
+ second_collection.featured_piece.glaze.color = "Red"
119
+ end
120
+
121
+ it "compares unequal objects with two levels of nesting" do
122
+ # This test compares CeramicCollection objects that are different at every level:
123
+ # the collection name, the ceramic type, and the glaze properties
124
+ expect(first_collection).not_to eq(second_collection)
125
+ end
126
+
127
+ it "generates different hashes for objects with two levels of nesting" do
128
+ expect(first_collection.hash).not_to eq(second_collection.hash)
129
+ end
130
+ end
131
+ end
132
+
133
+ context "with recursive relationships" do
134
+ let(:first_recursive_node) do
135
+ node1 = RecursiveNode.new(name: "A")
136
+ node2 = RecursiveNode.new(name: "B", next_node: node1)
137
+ node1.next_node = node2
138
+ node1
139
+ end
140
+
141
+ let(:second_recursive_node) do
142
+ node1 = RecursiveNode.new(name: "A")
143
+ node2 = RecursiveNode.new(name: "B", next_node: node1)
144
+ node1.next_node = node2
145
+ node1
146
+ end
147
+
148
+ describe ".eql?" do
149
+ it "compares equal objects" do
150
+ expect(first_recursive_node).to eq(second_recursive_node)
151
+ end
152
+
153
+ it "compares unequal objects" do
154
+ second_recursive_node.name = "X"
155
+ expect(first_recursive_node).not_to eq(second_recursive_node)
156
+ end
157
+ end
158
+
159
+ describe ".hash" do
160
+ it "returns the same hash for equal objects" do
161
+ expect(first_recursive_node.hash).to eq(second_recursive_node.hash)
162
+ end
163
+
164
+ it "returns different hashes for unequal objects" do
165
+ second_recursive_node.name = "X"
166
+ expect(first_recursive_node.hash).not_to eq(second_recursive_node.hash)
167
+ end
103
168
  end
104
169
  end
105
170
  end