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
@@ -0,0 +1,36 @@
1
+ module Lutaml
2
+ module Model
3
+ class Errors
4
+ include Enumerable
5
+
6
+ def initialize
7
+ @errors = {}
8
+ end
9
+
10
+ def add(attr, error)
11
+ @errors[attr] ||= []
12
+ @errors[attr] << error
13
+ end
14
+
15
+ def empty?
16
+ @errors.empty?
17
+ end
18
+
19
+ def each(&block)
20
+ @errors.each(&block)
21
+ end
22
+
23
+ def full_messages
24
+ @errors.map { |attr, errors| "#{attr}: #{errors.join(', ')}" }
25
+ end
26
+
27
+ def messages
28
+ @errors.map { |_, errors| errors.join(", ") }.flatten
29
+ end
30
+
31
+ def to_s
32
+ full_messages.join("\n")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ module Lutaml
2
+ module Model
3
+ class FormatRegistry
4
+ class << self
5
+ attr_reader :format, :mapping_class, :adapter_class
6
+
7
+ def register(format, mapping_class:, adapter_class:, transformer:)
8
+ registered_formats[format] = {
9
+ mapping_class: mapping_class,
10
+ transformer: transformer,
11
+ }
12
+
13
+ ::Lutaml::Model::Type::Value.register_format_to_from_methods(format)
14
+ ::Lutaml::Model::Serialize.register_format_mapping_method(format)
15
+ ::Lutaml::Model::Serialize.register_from_format_method(format)
16
+ ::Lutaml::Model::Serialize.register_to_format_method(format)
17
+
18
+ Lutaml::Model::Config.set_adapter_for(format, adapter_class)
19
+
20
+ Lutaml::Model::Config.define_singleton_method(:"#{format}_adapter") do
21
+ @adapters[format] || adapter_class
22
+ end
23
+
24
+ Lutaml::Model::Config.define_singleton_method(:"#{format}_adapter=") do |adapter_klass|
25
+ @adapters ||= {}
26
+ @adapters[format] = adapter_klass
27
+ end
28
+ end
29
+
30
+ def mappings_class_for(format)
31
+ registered_formats.dig(format, :mapping_class)
32
+ end
33
+
34
+ def transformer_for(format)
35
+ registered_formats.dig(format, :transformer)
36
+ end
37
+
38
+ def registered_formats
39
+ @registered_formats ||= {}
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ class GlobalRegister
6
+ include Singleton
7
+
8
+ def initialize
9
+ @registers = {}
10
+ default_register = Lutaml::Model::Register.new(:default)
11
+ register(default_register)
12
+ end
13
+
14
+ def register(model_register)
15
+ @registers[model_register.id] = model_register
16
+ end
17
+
18
+ def lookup(id)
19
+ @registers[id.to_sym]
20
+ end
21
+
22
+ def remove(id)
23
+ @registers.delete(id.to_sym)
24
+ end
25
+
26
+ class << self
27
+ def register(model_register)
28
+ instance.register(model_register)
29
+ end
30
+
31
+ def lookup(id)
32
+ instance.lookup(id)
33
+ end
34
+
35
+ def remove(id)
36
+ instance.remove(id)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module HashAdapter
6
+ # Base class for Hash documents
7
+ class Document < KeyValueDocument
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "../mapping/key_value_mapping"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module HashAdapter
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:hash)
9
+ end
10
+
11
+ def deep_dup
12
+ self.class.new.tap do |new_mapping|
13
+ new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../mapping/key_value_mapping_rule"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module HashAdapter
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "document"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module HashAdapter
6
+ class StandardAdapter < Document
7
+ def self.parse(hsh, _options = {})
8
+ hsh
9
+ end
10
+
11
+ def to_hash(_options = {})
12
+ @attributes
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module Lutaml
2
+ module Model
3
+ module HashAdapter
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module HashAdapter
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "hash_adapter/standard_adapter"
11
+ require_relative "hash_adapter/document"
12
+ require_relative "hash_adapter/mapping"
13
+ require_relative "hash_adapter/mapping_rule"
14
+ require_relative "hash_adapter/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :hash,
18
+ mapping_class: Lutaml::Model::HashAdapter::Mapping,
19
+ adapter_class: Lutaml::Model::HashAdapter::StandardAdapter,
20
+ transformer: Lutaml::Model::HashAdapter::Transform,
21
+ )
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Json
6
+ # Base class for JSON documents
7
+ class Document < Lutaml::Model::KeyValueDocument
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "../mapping/key_value_mapping"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Json
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:json)
9
+ end
10
+
11
+ def deep_dup
12
+ self.class.new.tap do |new_mapping|
13
+ new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../mapping/key_value_mapping_rule"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Json
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -1,13 +1,12 @@
1
1
  require "multi_json"
2
- require_relative "json_document"
2
+ require_relative "document"
3
3
 
4
4
  module Lutaml
5
5
  module Model
6
- module JsonAdapter
7
- class MultiJsonAdapter < JsonDocument
6
+ module Json
7
+ class MultiJsonAdapter < Document
8
8
  def self.parse(json, _options = {})
9
- data = MultiJson.load(json)
10
- new(data)
9
+ MultiJson.load(json)
11
10
  end
12
11
 
13
12
  def to_json(*args)
@@ -1,10 +1,12 @@
1
1
  require "json"
2
- require_relative "json_document"
2
+ require_relative "document"
3
3
 
4
4
  module Lutaml
5
5
  module Model
6
- module JsonAdapter
7
- class StandardJsonAdapter < JsonDocument
6
+ module Json
7
+ class StandardAdapter < Document
8
+ FORMAT_SYMBOL = :json
9
+
8
10
  def self.parse(json, _options = {})
9
11
  JSON.parse(json, create_additions: false)
10
12
  end
@@ -0,0 +1,8 @@
1
+ module Lutaml
2
+ module Model
3
+ module Json
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Json
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "json/standard_adapter"
11
+ require_relative "json/document"
12
+ require_relative "json/mapping"
13
+ require_relative "json/mapping_rule"
14
+ require_relative "json/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :json,
18
+ mapping_class: Lutaml::Model::Json::Mapping,
19
+ adapter_class: Lutaml::Model::Json::StandardAdapter,
20
+ transformer: Lutaml::Model::Json::Transform,
21
+ )
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Jsonl
6
+ class Document
7
+ def initialize(jsons = [], register: nil)
8
+ @jsons = jsons
9
+ @register = register || Lutaml::Model::Config.default_register
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "../mapping/key_value_mapping"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Jsonl
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:jsonl)
9
+ end
10
+
11
+ def deep_dup
12
+ self.class.new.tap do |new_mapping|
13
+ new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../mapping/key_value_mapping_rule"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Jsonl
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ require "json"
2
+ require_relative "document"
3
+
4
+ module Lutaml
5
+ module Model
6
+ module Jsonl
7
+ class StandardAdapter < Document
8
+ FORMAT_SYMBOL = :jsonl
9
+
10
+ def self.parse(jsonl, _options = {})
11
+ results = []
12
+ jsonl.split("\n").each do |line|
13
+ next if line.strip.empty?
14
+
15
+ begin
16
+ results << JSON.parse(line, create_additions: false)
17
+ rescue JSON::ParserError => e
18
+ warn "Skipping invalid line: #{e.message}"
19
+ end
20
+ end
21
+
22
+ results
23
+ end
24
+
25
+ def to_jsonl(*_args)
26
+ @jsons.map do |json|
27
+ JSON.generate(json)
28
+ end.join("\n")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Lutaml
2
+ module Model
3
+ module Jsonl
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ def data_to_model(data, format, options = {})
6
+ mappings = defined_mappings_for(:jsonl) || mappings_for(:json)
7
+
8
+ super(data, format, options.merge(mappings: mappings))
9
+ end
10
+
11
+ def model_to_data(instance, format, options = {})
12
+ mappings = defined_mappings_for(:jsonl) || mappings_for(:json)
13
+
14
+ super(instance, format, options.merge(mappings: mappings))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Jsonl
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "jsonl/standard_adapter"
11
+ require_relative "jsonl/document"
12
+ require_relative "jsonl/mapping"
13
+ require_relative "jsonl/mapping_rule"
14
+ require_relative "jsonl/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :jsonl,
18
+ mapping_class: Lutaml::Model::Jsonl::Mapping,
19
+ adapter_class: Lutaml::Model::Jsonl::StandardAdapter,
20
+ transformer: Lutaml::Model::Jsonl::Transform,
21
+ )
@@ -0,0 +1,28 @@
1
+ module Lutaml
2
+ module Model
3
+ class KeyValueDocument
4
+ attr_reader :attributes, :register
5
+
6
+ def initialize(attributes = {}, register: nil)
7
+ @attributes = attributes
8
+ @register = register || Lutaml::Model::Config.default_register
9
+ end
10
+
11
+ def [](key)
12
+ @attributes[key]
13
+ end
14
+
15
+ def []=(key, value)
16
+ @attributes[key] = value
17
+ end
18
+
19
+ def key?(key)
20
+ @attributes.key?(key)
21
+ end
22
+
23
+ def to_h
24
+ @attributes
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,15 +1,33 @@
1
+ require_relative "mapping"
1
2
  require_relative "key_value_mapping_rule"
2
3
 
3
4
  module Lutaml
4
5
  module Model
5
- class KeyValueMapping
6
- attr_reader :mappings, :format
6
+ class KeyValueMapping < Mapping
7
+ attr_reader :format, :key_mappings, :value_mappings
7
8
 
8
9
  def initialize(format = nil)
9
- @mappings = []
10
+ super()
11
+ @mappings = {}
10
12
  @format = format
11
13
  end
12
14
 
15
+ def root(name = nil)
16
+ @root = name
17
+ end
18
+
19
+ def no_root
20
+ @root = nil
21
+ end
22
+
23
+ def no_root?
24
+ @root.nil?
25
+ end
26
+
27
+ def root_name
28
+ @root
29
+ end
30
+
13
31
  def map(
14
32
  name = nil,
15
33
  to: nil,
@@ -31,7 +49,7 @@ module Lutaml
31
49
  mapping_name = name_for_mapping(root_mappings, name)
32
50
  validate!(mapping_name, to, with, render_nil, render_empty)
33
51
 
34
- @mappings << KeyValueMappingRule.new(
52
+ @mappings[mapping_name] = KeyValueMappingRule.new(
35
53
  mapping_name,
36
54
  to: to,
37
55
  render_nil: render_nil,
@@ -62,7 +80,7 @@ module Lutaml
62
80
  )
63
81
  @raw_mapping = true
64
82
  validate!(Constants::RAW_MAPPING_KEY, to, with, render_nil, nil)
65
- @mappings << KeyValueMappingRule.new(
83
+ @mappings[Constants::RAW_MAPPING_KEY] = KeyValueMappingRule.new(
66
84
  Constants::RAW_MAPPING_KEY,
67
85
  to: to,
68
86
  render_nil: render_nil,
@@ -74,12 +92,53 @@ module Lutaml
74
92
 
75
93
  alias map_all_content map_all
76
94
 
95
+ def map_instances(to:)
96
+ map(root_name || to, to: to)
97
+ end
98
+
99
+ def map_key(to_instance: nil, as_attribute: nil)
100
+ @key_mappings = KeyValueMappingRule.new(
101
+ Constants::KEY_MAPPING_KEY,
102
+ to: nil,
103
+ to_instance: to_instance,
104
+ as_attribute: as_attribute,
105
+ )
106
+ end
107
+
108
+ def map_value(to_instance: nil, as_attribute: nil)
109
+ @value_mappings = KeyValueMappingRule.new(
110
+ Constants::VALUE_MAPPING_KEY,
111
+ to: nil,
112
+ to_instance: to_instance,
113
+ as_attribute: as_attribute,
114
+ )
115
+ end
116
+
117
+ def key_value_mappings
118
+ {
119
+ key: @key_mappings,
120
+ value: @value_mappings,
121
+ }.compact
122
+ end
123
+
124
+ def key_value_mappings?
125
+ Utils.present?(@key_mappings) || Utils.present?(@value_mappings)
126
+ end
127
+
77
128
  def name_for_mapping(root_mappings, name)
78
129
  return "root_mapping" if root_mappings
79
130
 
80
131
  name
81
132
  end
82
133
 
134
+ def mappings
135
+ @mappings.values
136
+ end
137
+
138
+ def mappings_hash
139
+ @mappings
140
+ end
141
+
83
142
  def validate!(key, to, with, render_nil, render_empty)
84
143
  validate_mappings!(key)
85
144
  validate_to_and_with_arguments!(key, to, with)
@@ -96,10 +155,12 @@ module Lutaml
96
155
  )
97
156
  end
98
157
 
99
- validate_with_options!(key, with)
158
+ validate_with_options!(to, key, with)
100
159
  end
101
160
 
102
- def validate_with_options!(key, with)
161
+ def validate_with_options!(to, key, with)
162
+ return true if to
163
+
103
164
  if !with.empty? && (with[:from].nil? || with[:to].nil?) && !@raw_mapping
104
165
  raise IncorrectMappingArgumentsError.new(
105
166
  ":with argument for mapping '#{key}' requires :to and :from keys",
@@ -108,8 +169,10 @@ module Lutaml
108
169
  end
109
170
 
110
171
  def validate_root_mappings!(name)
111
- if @mappings.any?(&:root_mapping?) || (name == "root_mapping" && @mappings.any?)
112
- raise MultipleMappingsError.new("root_mappings cannot be used with other mappings")
172
+ if root_mapping || (name == "root_mapping" && @mappings.any?)
173
+ raise MultipleMappingsError.new(
174
+ "root_mappings cannot be used with other mappings",
175
+ )
113
176
  end
114
177
  end
115
178
 
@@ -122,7 +185,8 @@ module Lutaml
122
185
  end
123
186
 
124
187
  def validate_mappings!(_type)
125
- if (@raw_mapping && Utils.present?(@mappings)) || (!@raw_mapping && @mappings.any?(&:raw_mapping?))
188
+ if (@raw_mapping && Utils.present?(@mappings)) ||
189
+ (!@raw_mapping && mappings.any?(&:raw_mapping?))
126
190
  raise StandardError, "map_all is not allowed with other mappings"
127
191
  end
128
192
  end
@@ -134,15 +198,23 @@ module Lutaml
134
198
  end
135
199
 
136
200
  def duplicate_mappings
137
- @mappings.map(&:deep_dup)
201
+ Utils.deep_dup(@mappings)
138
202
  end
139
203
 
140
204
  def find_by_to(to)
141
- @mappings.find { |m| m.to.to_s == to.to_s }
205
+ mappings.find { |m| m.to.to_s == to.to_s }
206
+ end
207
+
208
+ def find_by_name(name)
209
+ @mappings.find { |m| m.name.to_s == name.to_s }
142
210
  end
143
211
 
144
212
  def polymorphic_mapping
145
- @mappings.find(&:polymorphic_mapping?)
213
+ mappings.find(&:polymorphic_mapping?)
214
+ end
215
+
216
+ def root_mapping
217
+ mappings.find(&:root_mapping?)
146
218
  end
147
219
 
148
220
  Lutaml::Model::Config::KEY_VALUE_FORMATS.each do |format|
@@ -9,6 +9,8 @@ module Lutaml
9
9
  def initialize(
10
10
  name,
11
11
  to:,
12
+ to_instance: nil,
13
+ as_attribute: nil,
12
14
  render_nil: false,
13
15
  render_default: false,
14
16
  render_empty: false,
@@ -27,6 +29,8 @@ module Lutaml
27
29
  super(
28
30
  name,
29
31
  to: to,
32
+ to_instance: to_instance,
33
+ as_attribute: as_attribute,
30
34
  render_nil: render_nil,
31
35
  render_default: render_default,
32
36
  render_empty: render_empty,
@@ -60,6 +64,7 @@ module Lutaml
60
64
  with: Utils.deep_dup(custom_methods),
61
65
  delegate: delegate,
62
66
  child_mappings: Utils.deep_dup(child_mappings),
67
+ root_mappings: Utils.deep_dup(root_mappings),
63
68
  value_map: Utils.deep_dup(@value_map),
64
69
  )
65
70
  end