lutaml-model 0.7.1 → 0.7.7

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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.github/workflows/dependent-tests.yml +4 -0
  4. data/.github/workflows/rake.yml +12 -0
  5. data/.github/workflows/release.yml +3 -0
  6. data/.gitignore +6 -1
  7. data/.irbrc +1 -0
  8. data/.pryrc +1 -0
  9. data/.rubocop.yml +1 -1
  10. data/.rubocop_todo.yml +58 -84
  11. data/Gemfile +4 -1
  12. data/README.adoc +3115 -365
  13. data/RELEASE_NOTES.adoc +346 -0
  14. data/docs/custom_adapters.adoc +144 -0
  15. data/docs/custom_registers.adoc +228 -0
  16. data/docs/schema_generation.adoc +898 -0
  17. data/docs/schema_import.adoc +364 -0
  18. data/flake.lock +114 -0
  19. data/flake.nix +103 -0
  20. data/lib/lutaml/model/attribute.rb +242 -100
  21. data/lib/lutaml/model/choice.rb +30 -0
  22. data/lib/lutaml/model/collection.rb +212 -0
  23. data/lib/lutaml/model/comparable_model.rb +3 -3
  24. data/lib/lutaml/model/config.rb +71 -42
  25. data/lib/lutaml/model/constants.rb +2 -0
  26. data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
  27. data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
  28. data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
  29. data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
  30. data/lib/lutaml/model/error/polymorphic_error.rb +7 -2
  31. data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
  32. data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
  33. data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
  34. data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
  35. data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
  36. data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
  37. data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
  38. data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
  39. data/lib/lutaml/model/error.rb +10 -0
  40. data/lib/lutaml/model/errors.rb +36 -0
  41. data/lib/lutaml/model/format_registry.rb +44 -0
  42. data/lib/lutaml/model/global_register.rb +41 -0
  43. data/lib/lutaml/model/hash_adapter/document.rb +11 -0
  44. data/lib/lutaml/model/hash_adapter/mapping.rb +19 -0
  45. data/lib/lutaml/model/hash_adapter/mapping_rule.rb +9 -0
  46. data/lib/lutaml/model/hash_adapter/standard_adapter.rb +17 -0
  47. data/lib/lutaml/model/hash_adapter/transform.rb +8 -0
  48. data/lib/lutaml/model/hash_adapter.rb +21 -0
  49. data/lib/lutaml/model/json/document.rb +11 -0
  50. data/lib/lutaml/model/json/mapping.rb +19 -0
  51. data/lib/lutaml/model/json/mapping_rule.rb +9 -0
  52. data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
  53. data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
  54. data/lib/lutaml/model/json/transform.rb +8 -0
  55. data/lib/lutaml/model/json.rb +21 -0
  56. data/lib/lutaml/model/jsonl/document.rb +14 -0
  57. data/lib/lutaml/model/jsonl/mapping.rb +19 -0
  58. data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
  59. data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
  60. data/lib/lutaml/model/jsonl/transform.rb +19 -0
  61. data/lib/lutaml/model/jsonl.rb +21 -0
  62. data/lib/lutaml/model/key_value_document.rb +28 -0
  63. data/lib/lutaml/model/mapping/key_value_mapping.rb +85 -13
  64. data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +5 -0
  65. data/lib/lutaml/model/mapping/mapping.rb +13 -0
  66. data/lib/lutaml/model/mapping/mapping_rule.rb +15 -9
  67. data/lib/lutaml/model/register.rb +105 -0
  68. data/lib/lutaml/model/{toml_adapter.rb → registrable.rb} +1 -1
  69. data/lib/lutaml/model/schema/base_schema.rb +64 -0
  70. data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
  71. data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
  72. data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
  73. data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
  74. data/lib/lutaml/model/schema/generator/definition.rb +53 -0
  75. data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
  76. data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
  77. data/lib/lutaml/model/schema/generator/property.rb +110 -0
  78. data/lib/lutaml/model/schema/generator/ref.rb +24 -0
  79. data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
  80. data/lib/lutaml/model/schema/json_schema.rb +42 -49
  81. data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
  82. data/lib/lutaml/model/schema/renderer.rb +36 -0
  83. data/lib/lutaml/model/schema/shared_methods.rb +24 -0
  84. data/lib/lutaml/model/schema/templates/model.erb +9 -0
  85. data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
  86. data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
  87. data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
  88. data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
  89. data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
  90. data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
  91. data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
  92. data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
  93. data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
  94. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
  95. data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
  96. data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
  97. data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
  98. data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
  99. data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
  100. data/lib/lutaml/model/schema.rb +1 -0
  101. data/lib/lutaml/model/sequence.rb +60 -30
  102. data/lib/lutaml/model/serialization_adapter.rb +22 -0
  103. data/lib/lutaml/model/serialize.rb +296 -548
  104. data/lib/lutaml/model/services/base.rb +11 -0
  105. data/lib/lutaml/model/services/logger.rb +54 -0
  106. data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
  107. data/lib/lutaml/model/services/transformer.rb +48 -0
  108. data/lib/lutaml/model/services/type/validator/number.rb +25 -0
  109. data/lib/lutaml/model/services/type/validator/string.rb +52 -0
  110. data/lib/lutaml/model/services/type/validator.rb +43 -0
  111. data/lib/lutaml/model/services/validator.rb +145 -0
  112. data/lib/lutaml/model/services.rb +5 -0
  113. data/lib/lutaml/model/toml/document.rb +11 -0
  114. data/lib/lutaml/model/toml/mapping.rb +27 -0
  115. data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
  116. data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
  117. data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
  118. data/lib/lutaml/model/toml/transform.rb +8 -0
  119. data/lib/lutaml/model/toml.rb +30 -0
  120. data/lib/lutaml/model/transform/key_value_transform.rb +297 -0
  121. data/lib/lutaml/model/transform/xml_transform.rb +228 -0
  122. data/lib/lutaml/model/transform.rb +93 -0
  123. data/lib/lutaml/model/type/boolean.rb +1 -1
  124. data/lib/lutaml/model/type/date.rb +1 -1
  125. data/lib/lutaml/model/type/date_time.rb +1 -1
  126. data/lib/lutaml/model/type/decimal.rb +11 -9
  127. data/lib/lutaml/model/type/float.rb +2 -1
  128. data/lib/lutaml/model/type/integer.rb +24 -21
  129. data/lib/lutaml/model/type/string.rb +4 -2
  130. data/lib/lutaml/model/type/time.rb +1 -1
  131. data/lib/lutaml/model/type/time_without_date.rb +1 -1
  132. data/lib/lutaml/model/type/value.rb +11 -10
  133. data/lib/lutaml/model/type.rb +5 -2
  134. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  135. data/lib/lutaml/model/utils.rb +56 -4
  136. data/lib/lutaml/model/validation.rb +6 -4
  137. data/lib/lutaml/model/version.rb +1 -1
  138. data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
  139. data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
  140. data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
  141. data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +42 -25
  142. data/lib/lutaml/model/xml/element.rb +32 -0
  143. data/lib/lutaml/model/xml/mapping.rb +471 -0
  144. data/lib/lutaml/model/xml/mapping_rule.rb +149 -0
  145. data/lib/lutaml/model/xml/nokogiri_adapter.rb +234 -0
  146. data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
  147. data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +7 -2
  148. data/lib/lutaml/model/xml/oga_adapter.rb +172 -0
  149. data/lib/lutaml/model/xml/ox_adapter.rb +229 -0
  150. data/lib/lutaml/model/xml/transform.rb +8 -0
  151. data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
  152. data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +9 -31
  153. data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
  154. data/lib/lutaml/model/xml.rb +31 -0
  155. data/lib/lutaml/model/xml_adapter/element.rb +11 -25
  156. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
  157. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
  158. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
  159. data/lib/lutaml/model/yaml/document.rb +10 -0
  160. data/lib/lutaml/model/yaml/mapping.rb +19 -0
  161. data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
  162. data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
  163. data/lib/lutaml/model/yaml/transform.rb +8 -0
  164. data/lib/lutaml/model/yaml.rb +21 -0
  165. data/lib/lutaml/model/yamls/document.rb +14 -0
  166. data/lib/lutaml/model/yamls/mapping.rb +19 -0
  167. data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
  168. data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
  169. data/lib/lutaml/model/yamls/transform.rb +19 -0
  170. data/lib/lutaml/model/yamls.rb +21 -0
  171. data/lib/lutaml/model.rb +15 -4
  172. data/lutaml-model.gemspec +0 -4
  173. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +5 -6
  174. data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
  175. data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
  176. data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
  177. data/spec/fixtures/xml/product_catalog.xsd +151 -0
  178. data/spec/fixtures/xml/specifications_schema.xsd +38 -0
  179. data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
  180. data/spec/lutaml/model/attribute_spec.rb +41 -44
  181. data/spec/lutaml/model/cdata_spec.rb +7 -7
  182. data/spec/lutaml/model/choice_spec.rb +44 -0
  183. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
  184. data/spec/lutaml/model/custom_collection_spec.rb +830 -0
  185. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
  186. data/spec/lutaml/model/global_register_spec.rb +108 -0
  187. data/spec/lutaml/model/group_spec.rb +27 -10
  188. data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
  189. data/spec/lutaml/model/json_adapter_spec.rb +6 -6
  190. data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
  191. data/spec/lutaml/model/jsonl_spec.rb +229 -0
  192. data/spec/lutaml/model/key_value_mapping_spec.rb +25 -1
  193. data/spec/lutaml/model/mixed_content_spec.rb +24 -24
  194. data/spec/lutaml/model/multiple_mapping_spec.rb +6 -6
  195. data/spec/lutaml/model/ordered_content_spec.rb +6 -6
  196. data/spec/lutaml/model/polymorphic_spec.rb +178 -0
  197. data/spec/lutaml/model/register/key_value_spec.rb +275 -0
  198. data/spec/lutaml/model/register/xml_spec.rb +185 -0
  199. data/spec/lutaml/model/register_spec.rb +147 -0
  200. data/spec/lutaml/model/root_mappings_spec.rb +3 -3
  201. data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
  202. data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
  203. data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
  204. data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
  205. data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
  206. data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
  207. data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
  208. data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
  209. data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
  210. data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
  211. data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
  212. data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
  213. data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
  214. data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
  215. data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
  216. data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
  217. data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
  218. data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
  219. data/spec/lutaml/model/sequence_spec.rb +36 -0
  220. data/spec/lutaml/model/serializable_spec.rb +201 -94
  221. data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
  222. data/spec/lutaml/model/toml_spec.rb +51 -0
  223. data/spec/lutaml/model/transformation_spec.rb +72 -15
  224. data/spec/lutaml/model/type_spec.rb +8 -4
  225. data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
  226. data/spec/lutaml/model/utils_spec.rb +3 -3
  227. data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
  228. data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
  229. data/spec/lutaml/model/xml/root_mappings/nested_child_mappings_spec.rb +217 -0
  230. data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
  231. data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
  232. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  233. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  234. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +12 -12
  235. data/spec/lutaml/model/xml_adapter_spec.rb +30 -6
  236. data/spec/lutaml/model/xml_mapping_rule_spec.rb +14 -7
  237. data/spec/lutaml/model/xml_mapping_spec.rb +27 -15
  238. data/spec/lutaml/model/xml_spec.rb +63 -0
  239. data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
  240. data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
  241. data/spec/lutaml/model/yamls_spec.rb +294 -0
  242. data/spec/spec_helper.rb +4 -3
  243. metadata +162 -60
  244. data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
  245. data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
  246. data/lib/lutaml/model/loggable.rb +0 -15
  247. data/lib/lutaml/model/mapping/json_mapping.rb +0 -17
  248. data/lib/lutaml/model/mapping/toml_mapping.rb +0 -25
  249. data/lib/lutaml/model/mapping/xml_mapping.rb +0 -389
  250. data/lib/lutaml/model/mapping/xml_mapping_rule.rb +0 -139
  251. data/lib/lutaml/model/mapping/yaml_mapping.rb +0 -17
  252. data/lib/lutaml/model/mapping.rb +0 -14
  253. data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
  254. data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
  255. data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
  256. data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
  257. data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
  258. data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
  259. data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
  require "oga"
3
- require_relative "../../../../lib/lutaml/model/xml_adapter/oga_adapter"
3
+ require_relative "../../../../lib/lutaml/model/xml/oga_adapter"
4
4
 
5
- RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do
5
+ RSpec.describe Lutaml::Model::Xml::OgaAdapter do
6
6
  let(:xml_string) do
7
7
  <<~XML
8
8
  <root xmlns="http://example.com/default" xmlns:prefix="http://example.com/prefixed">
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
  require "ox"
3
- require_relative "../../../../lib/lutaml/model/xml_adapter/ox_adapter"
3
+ require_relative "../../../../lib/lutaml/model/xml/ox_adapter"
4
4
 
5
- RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
5
+ RSpec.describe Lutaml::Model::Xml::OxAdapter do
6
6
  let(:xml_string) do
7
7
  <<-XML
8
8
  <root xmlns="http://example.com/default" xmlns:prefix="http://example.com/prefixed">
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
- require "lutaml/model/xml_adapter/nokogiri_adapter"
3
- require "lutaml/model/xml_adapter/ox_adapter"
4
- require "lutaml/model/xml_adapter/oga_adapter"
2
+ require "lutaml/model/xml/nokogiri_adapter"
3
+ require "lutaml/model/xml/ox_adapter"
4
+ require "lutaml/model/xml/oga_adapter"
5
5
  require "lutaml/model"
6
6
 
7
7
  RSpec.describe "XmlNamespace" do
@@ -164,15 +164,15 @@ RSpec.describe "XmlNamespace" do
164
164
  end
165
165
 
166
166
  context "with no prefix" do
167
- include_examples "XML serialization with namespace",
168
- TestModelNoPrefix,
169
- '<test xmlns="http://example.com/test"><name>Test Name</name></test>'
167
+ it_behaves_like "XML serialization with namespace",
168
+ TestModelNoPrefix,
169
+ '<test xmlns="http://example.com/test"><name>Test Name</name></test>'
170
170
  end
171
171
 
172
172
  context "with prefix" do
173
- include_examples "XML serialization with namespace",
174
- TestModelWithPrefix,
175
- '<test:test xmlns:test="http://example.com/test"><test:name>Test Name</test:name></test:test>'
173
+ it_behaves_like "XML serialization with namespace",
174
+ TestModelWithPrefix,
175
+ '<test:test xmlns:test="http://example.com/test"><test:name>Test Name</test:name></test:test>'
176
176
  end
177
177
 
178
178
  context "with prefixed namespace" do
@@ -354,15 +354,15 @@ RSpec.describe "XmlNamespace" do
354
354
  end
355
355
  end
356
356
 
357
- describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
357
+ describe Lutaml::Model::Xml::NokogiriAdapter do
358
358
  it_behaves_like "an XML namespace parser", described_class
359
359
  end
360
360
 
361
- describe Lutaml::Model::XmlAdapter::OxAdapter do
361
+ describe Lutaml::Model::Xml::OxAdapter do
362
362
  it_behaves_like "an XML namespace parser", described_class
363
363
  end
364
364
 
365
- describe Lutaml::Model::XmlAdapter::OgaAdapter do
365
+ describe Lutaml::Model::Xml::OgaAdapter do
366
366
  it_behaves_like "an XML namespace parser", described_class
367
367
  end
368
368
  end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
- require "lutaml/model/xml_adapter/nokogiri_adapter"
3
- require "lutaml/model/xml_adapter/ox_adapter"
4
- require "lutaml/model/xml_adapter/oga_adapter"
2
+ require "lutaml/model/xml/nokogiri_adapter"
3
+ require "lutaml/model/xml/ox_adapter"
4
+ require "lutaml/model/xml/oga_adapter"
5
5
  require_relative "../../fixtures/sample_model"
6
6
 
7
7
  module XmlAdapterSpec
@@ -130,6 +130,30 @@ RSpec.describe "XmlAdapter" do
130
130
  end
131
131
  end
132
132
 
133
+ context "when xml has `lang` attribute" do
134
+ before do
135
+ title_class = Class.new(Lutaml::Model::Serializable) do
136
+ attribute :lang, :string
137
+ attribute :content, :string
138
+
139
+ xml do
140
+ root "title"
141
+
142
+ map_attribute "lang", to: :lang
143
+ map_content to: :content
144
+ end
145
+ end
146
+
147
+ stub_const("Title", title_class)
148
+ end
149
+
150
+ let(:xml_input) { "<title lang='en'>Title</title>" }
151
+ let(:parsed) { Title.from_xml(xml_input) }
152
+
153
+ it { expect(parsed.lang).to eq("en") }
154
+ it { expect(parsed.content).to eq("Title") }
155
+ end
156
+
133
157
  it "serializes to XML" do
134
158
  expected_xml = <<~XML
135
159
  <SampleModel>
@@ -172,15 +196,15 @@ RSpec.describe "XmlAdapter" do
172
196
  end
173
197
  end
174
198
 
175
- describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
199
+ describe Lutaml::Model::Xml::NokogiriAdapter do
176
200
  it_behaves_like "an XML adapter", described_class
177
201
  end
178
202
 
179
- describe Lutaml::Model::XmlAdapter::OxAdapter do
203
+ describe Lutaml::Model::Xml::OxAdapter do
180
204
  it_behaves_like "an XML adapter", described_class
181
205
  end
182
206
 
183
- describe Lutaml::Model::XmlAdapter::OgaAdapter do
207
+ describe Lutaml::Model::Xml::OgaAdapter do
184
208
  it_behaves_like "an XML adapter", described_class
185
209
  end
186
210
  end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
- require "lutaml/model/xml_adapter/ox_adapter"
4
- require "lutaml/model/xml_adapter/oga_adapter"
3
+ require "lutaml/model/xml/ox_adapter"
4
+ require "lutaml/model/xml/oga_adapter"
5
5
 
6
6
  def content_to_xml(model, parent, doc)
7
7
  content = model.all_content.sub(/^<div>/, "").sub(/<\/div>$/, "")
@@ -12,19 +12,26 @@ def content_from_xml(model, value)
12
12
  model.all_content = "<div>#{value}</div>"
13
13
  end
14
14
 
15
- RSpec.describe Lutaml::Model::XmlMappingRule do
15
+ RSpec.describe Lutaml::Model::Xml::MappingRule do
16
16
  describe "#namespaced_name" do
17
17
  let(:namespaced_name) do
18
18
  mapping_rule.namespaced_name
19
19
  end
20
20
 
21
21
  context "when attribute name is string 'lang'" do
22
- let(:mapping_rule) do
23
- described_class.new("lang", to: :lang, prefix: "xml")
22
+ it "returns `xml:lang` when prefix is set" do
23
+ mapping_rule = described_class.new("lang", to: :lang, prefix: "xml")
24
+ expect(mapping_rule.namespaced_name).to eq("xml:lang")
24
25
  end
25
26
 
26
- it "returns `xml:lang`" do
27
- expect(namespaced_name).to eq("xml:lang")
27
+ it "returns `lang` when prefix is empty string" do
28
+ mapping_rule = described_class.new("lang", to: :lang, prefix: "")
29
+ expect(mapping_rule.namespaced_name).to eq("lang")
30
+ end
31
+
32
+ it "returns `lang` when prefix is nil" do
33
+ mapping_rule = described_class.new("lang", to: :lang, prefix: nil)
34
+ expect(mapping_rule.namespaced_name).to eq("lang")
28
35
  end
29
36
  end
30
37
 
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
- require "lutaml/model/xml_adapter/ox_adapter"
4
- require "lutaml/model/xml_adapter/oga_adapter"
3
+ require "lutaml/model/xml/ox_adapter"
4
+ require "lutaml/model/xml/oga_adapter"
5
5
 
6
6
  # Define a sample class for testing map_content
7
7
  class Italic < Lutaml::Model::Serializable
@@ -320,7 +320,7 @@ module XmlMapping
320
320
  end
321
321
  end
322
322
 
323
- RSpec.describe Lutaml::Model::XmlMapping do
323
+ RSpec.describe Lutaml::Model::Xml::Mapping do
324
324
  shared_examples "having XML Mappings" do |adapter_class|
325
325
  around do |example|
326
326
  old_adapter = Lutaml::Model::Config.xml_adapter
@@ -331,7 +331,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
331
331
  Lutaml::Model::Config.xml_adapter = old_adapter
332
332
  end
333
333
 
334
- let(:mapping) { Lutaml::Model::XmlMapping.new }
334
+ let(:mapping) { Lutaml::Model::Xml::Mapping.new }
335
335
 
336
336
  context "with attribute having namespace" do
337
337
  input_xml = <<~XML
@@ -365,7 +365,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
365
365
  end
366
366
 
367
367
  # Skipping for OX because it does not handle namespaces
368
- context "when overriding child namespace prefix", skip: adapter_class == Lutaml::Model::XmlAdapter::OxAdapter do
368
+ context "when overriding child namespace prefix", skip: adapter_class == Lutaml::Model::Xml::OxAdapter do
369
369
  let(:input_xml) do
370
370
  <<~XML
371
371
  <OverrideDefaultNamespacePrefix
@@ -496,9 +496,9 @@ RSpec.describe Lutaml::Model::XmlMapping do
496
496
  ])
497
497
 
498
498
  {
499
- Lutaml::Model::XmlAdapter::NokogiriAdapter => nokogiri_pattern,
500
- Lutaml::Model::XmlAdapter::OxAdapter => oga_ox_pattern,
501
- Lutaml::Model::XmlAdapter::OgaAdapter => oga_ox_pattern,
499
+ Lutaml::Model::Xml::NokogiriAdapter => nokogiri_pattern,
500
+ Lutaml::Model::Xml::OxAdapter => oga_ox_pattern,
501
+ Lutaml::Model::Xml::OgaAdapter => oga_ox_pattern,
502
502
  }
503
503
  end
504
504
 
@@ -508,7 +508,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
508
508
 
509
509
  def create_pattern_mapping(array)
510
510
  array.map do |type, text|
511
- Lutaml::Model::XmlAdapter::Element.new(type, text)
511
+ Lutaml::Model::Xml::Element.new(type, text)
512
512
  end
513
513
  end
514
514
 
@@ -732,7 +732,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
732
732
  end
733
733
 
734
734
  it "prints warning if defined explicitly in class" do
735
- error_regex = /\[Lutaml::Model\] WARN: `schemaLocation` is handled by default\. No need to explecitly define at `xml_mapping_spec.rb:\d+`/
735
+ error_regex = /\[Lutaml::Model\] WARN: `schemaLocation` is handled by default\. No need to explicitly define at `xml_mapping_spec.rb:\d+`/
736
736
 
737
737
  expect do
738
738
  mapping.map_attribute("schemaLocation", to: :schema_location)
@@ -845,7 +845,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
845
845
  end
846
846
 
847
847
  let(:expected_street) do
848
- if Lutaml::Model::Config.xml_adapter == Lutaml::Model::XmlAdapter::NokogiriAdapter
848
+ if Lutaml::Model::Config.xml_adapter == Lutaml::Model::Xml::NokogiriAdapter
849
849
  "\n <a>N</a>\n <p>adf</p>\n "
850
850
  else
851
851
  "<a>N</a><p>adf</p>"
@@ -1248,7 +1248,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
1248
1248
  end
1249
1249
 
1250
1250
  describe "validation errors" do
1251
- let(:mapping) { Lutaml::Model::XmlMapping.new }
1251
+ let(:mapping) { Lutaml::Model::Xml::Mapping.new }
1252
1252
 
1253
1253
  it "raises error when neither :to nor :with provided" do
1254
1254
  expect do
@@ -1268,6 +1268,12 @@ RSpec.describe Lutaml::Model::XmlMapping do
1268
1268
  )
1269
1269
  end
1270
1270
 
1271
+ it "does not raise error when :to is provided" do
1272
+ expect do
1273
+ mapping.map_element("test", to: :test, with: { from: "value" })
1274
+ end.not_to raise_error
1275
+ end
1276
+
1271
1277
  describe "map_attribute validations" do
1272
1278
  it "raises error for invalid :with argument" do
1273
1279
  expect do
@@ -1277,6 +1283,12 @@ RSpec.describe Lutaml::Model::XmlMapping do
1277
1283
  ":with argument for mapping 'test' requires :to and :from keys",
1278
1284
  )
1279
1285
  end
1286
+
1287
+ it "does not raise error if to is provided" do
1288
+ expect do
1289
+ mapping.map_attribute("test", to: :test, with: { from: "value" })
1290
+ end.not_to raise_error
1291
+ end
1280
1292
  end
1281
1293
 
1282
1294
  describe "map_content validations" do
@@ -1292,15 +1304,15 @@ RSpec.describe Lutaml::Model::XmlMapping do
1292
1304
  end
1293
1305
  end
1294
1306
 
1295
- describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
1307
+ describe Lutaml::Model::Xml::NokogiriAdapter do
1296
1308
  it_behaves_like "having XML Mappings", described_class
1297
1309
  end
1298
1310
 
1299
- describe Lutaml::Model::XmlAdapter::OxAdapter do
1311
+ describe Lutaml::Model::Xml::OxAdapter do
1300
1312
  it_behaves_like "having XML Mappings", described_class
1301
1313
  end
1302
1314
 
1303
- describe Lutaml::Model::XmlAdapter::OgaAdapter do
1315
+ describe Lutaml::Model::Xml::OgaAdapter do
1304
1316
  it_behaves_like "having XML Mappings", described_class
1305
1317
  end
1306
1318
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/model/xml"
5
+
6
+ RSpec.describe Lutaml::Model::Xml do
7
+ describe ".detect_xml_adapter" do
8
+ before do
9
+ # Hide any existing constants first
10
+ hide_const("Nokogiri") if Object.const_defined?(:Nokogiri)
11
+ hide_const("Ox") if Object.const_defined?(:Ox)
12
+ hide_const("Oga") if Object.const_defined?(:Oga)
13
+ end
14
+
15
+ context "when Nokogiri is available" do
16
+ before do
17
+ stub_const("Nokogiri", Module.new)
18
+ end
19
+
20
+ it "returns :nokogiri" do
21
+ expect(described_class.detect_xml_adapter).to eq(:nokogiri)
22
+ end
23
+ end
24
+
25
+ context "when Ox is available" do
26
+ before do
27
+ stub_const("Ox", Module.new)
28
+ end
29
+
30
+ it "returns :ox" do
31
+ expect(described_class.detect_xml_adapter).to eq(:ox)
32
+ end
33
+ end
34
+
35
+ context "when Oga is available" do
36
+ before do
37
+ stub_const("Oga", Module.new)
38
+ end
39
+
40
+ it "returns :oga" do
41
+ expect(described_class.detect_xml_adapter).to eq(:oga)
42
+ end
43
+ end
44
+
45
+ context "when no adapters are available" do
46
+ it "returns nil" do
47
+ expect(described_class.detect_xml_adapter).to be_nil
48
+ end
49
+ end
50
+
51
+ context "when multiple adapters are available" do
52
+ before do
53
+ stub_const("Nokogiri", Module.new)
54
+ stub_const("Ox", Module.new)
55
+ stub_const("Oga", Module.new)
56
+ end
57
+
58
+ it "prefers Nokogiri" do
59
+ expect(described_class.detect_xml_adapter).to eq(:nokogiri)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,5 +1,4 @@
1
1
  require "spec_helper"
2
- require "lutaml/model/yaml_adapter"
3
2
  require_relative "../../fixtures/sample_model"
4
3
 
5
4
  RSpec.shared_examples "a YAML adapter" do |adapter_class|
@@ -7,7 +6,7 @@ RSpec.shared_examples "a YAML adapter" do |adapter_class|
7
6
  let(:model) { SampleModel.new(attributes) }
8
7
 
9
8
  let(:expected_yaml) do
10
- if adapter_class == Lutaml::Model::YamlAdapter::StandardYamlAdapter
9
+ if adapter_class == Lutaml::Model::Yaml::StandardAdapter
11
10
  attributes.to_yaml
12
11
  end
13
12
  end
@@ -20,11 +19,10 @@ RSpec.shared_examples "a YAML adapter" do |adapter_class|
20
19
 
21
20
  it "deserializes from YAML" do
22
21
  new_model = adapter_class.parse(expected_yaml)
23
- expect(new_model["name"]).to eq("John Doe")
24
- expect(new_model["age"]).to eq(30)
22
+ expect(new_model).to eq(attributes)
25
23
  end
26
24
  end
27
25
 
28
- RSpec.describe Lutaml::Model::YamlAdapter::StandardYamlAdapter do
26
+ RSpec.describe Lutaml::Model::Yaml::StandardAdapter do
29
27
  it_behaves_like "a YAML adapter", described_class
30
28
  end
@@ -0,0 +1,183 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Yamls::StandardAdapter do
4
+ let(:valid_yamls_content) do
5
+ <<~YAMLS
6
+ name: John
7
+ age: 30
8
+ ---
9
+ name: Jane
10
+ age: 25
11
+ ---
12
+ name: Bob
13
+ age: 35
14
+ YAMLS
15
+ end
16
+
17
+ let(:invalid_yamls_content) do
18
+ <<~YAMLS
19
+ name: John
20
+ age: 30
21
+ ---
22
+ invalid yaml: [
23
+ ---
24
+ name: Bob
25
+ age: 35
26
+ YAMLS
27
+ end
28
+
29
+ describe ".parse" do
30
+ context "with valid YAMLS content" do
31
+ it "parses each YAML document as a separate object" do
32
+ results = described_class.parse(valid_yamls_content)
33
+ expect(results).to be_an(Array)
34
+ expect(results.length).to eq(3)
35
+ expect(results.first).to eq({ "name" => "John", "age" => 30 })
36
+ expect(results.last).to eq({ "name" => "Bob", "age" => 35 })
37
+ end
38
+ end
39
+
40
+ context "with invalid YAMLS content" do
41
+ it "skips invalid YAML documents and continues parsing" do
42
+ results = described_class.parse(invalid_yamls_content)
43
+ expect(results).to be_an(Array)
44
+ expect(results.length).to eq(2)
45
+ expect(results.first).to eq({ "name" => "John", "age" => 30 })
46
+ expect(results.last).to eq({ "name" => "Bob", "age" => 35 })
47
+ end
48
+ end
49
+
50
+ context "with empty documents" do
51
+ let(:yamls_with_empty_docs) do
52
+ <<~YAMLS
53
+ name: John
54
+ ---
55
+
56
+ ---
57
+ name: Jane
58
+ YAMLS
59
+ end
60
+
61
+ it "skips empty documents" do
62
+ results = described_class.parse(yamls_with_empty_docs)
63
+ expect(results).to be_an(Array)
64
+ expect(results.length).to eq(2)
65
+ end
66
+ end
67
+
68
+ context "with single document" do
69
+ let(:single_yaml_doc) do
70
+ <<~YAMLS
71
+ name: John
72
+ age: 30
73
+ YAMLS
74
+ end
75
+
76
+ it "parses single document correctly" do
77
+ results = described_class.parse(single_yaml_doc)
78
+ expect(results).to be_an(Array)
79
+ expect(results.length).to eq(1)
80
+ expect(results.first).to eq({ "name" => "John", "age" => 30 })
81
+ end
82
+ end
83
+
84
+ context "with complex YAML structures" do
85
+ let(:complex_yamls_content) do
86
+ <<~YAMLS
87
+ name: John
88
+ address:
89
+ street: 123 Main St
90
+ city: New York
91
+ hobbies:
92
+ - reading
93
+ - swimming
94
+ ---
95
+ name: Jane
96
+ address:
97
+ street: 456 Oak Ave
98
+ city: Los Angeles
99
+ hobbies:
100
+ - hiking
101
+ - cooking
102
+ YAMLS
103
+ end
104
+
105
+ it "parses complex YAML structures" do
106
+ results = described_class.parse(complex_yamls_content)
107
+ expect(results).to be_an(Array)
108
+ expect(results.length).to eq(2)
109
+
110
+ expect(results.first).to eq({
111
+ "name" => "John",
112
+ "address" => {
113
+ "street" => "123 Main St",
114
+ "city" => "New York",
115
+ },
116
+ "hobbies" => ["reading", "swimming"],
117
+ })
118
+
119
+ expect(results.last).to eq({
120
+ "name" => "Jane",
121
+ "address" => {
122
+ "street" => "456 Oak Ave",
123
+ "city" => "Los Angeles",
124
+ },
125
+ "hobbies" => ["hiking", "cooking"],
126
+ })
127
+ end
128
+ end
129
+ end
130
+
131
+ describe "#to_yamls" do
132
+ let(:john) { { "name" => "John", "age" => 30 } }
133
+ let(:adapter) { described_class.new([john]) }
134
+
135
+ it "generates YAMLS format" do
136
+ expect(adapter.to_yamls.strip).to eq(john.to_yaml.strip)
137
+ end
138
+
139
+ context "with multiple objects" do
140
+ let(:jane) { { "name" => "Jane", "age" => 25 } }
141
+ let(:adapter) { described_class.new([john, jane]) }
142
+
143
+ let(:expected_yamls) do
144
+ <<~YAMLS.strip
145
+ #{john.to_yaml.strip}
146
+ #{jane.to_yaml.strip}
147
+ YAMLS
148
+ end
149
+
150
+ it "generates multiple YAML documents" do
151
+ expect(adapter.to_yamls.strip).to eq(expected_yamls.strip)
152
+ end
153
+ end
154
+
155
+ context "with complex data structures" do
156
+ let(:adapter) do
157
+ described_class.new([
158
+ {
159
+ "name" => "John",
160
+ "address" => {
161
+ "street" => "123 Main St",
162
+ "city" => "New York",
163
+ },
164
+ "hobbies" => ["reading", "swimming"],
165
+ },
166
+ ])
167
+ end
168
+
169
+ it "generates complex YAML structures" do
170
+ result = adapter.to_yamls
171
+ expect(result).to include("name")
172
+ expect(result).to include("address")
173
+ expect(result).to include("hobbies")
174
+ end
175
+ end
176
+ end
177
+
178
+ describe "FORMAT_SYMBOL" do
179
+ it "returns :yaml" do
180
+ expect(described_class::FORMAT_SYMBOL).to eq(:yaml)
181
+ end
182
+ end
183
+ end