lutaml-model 0.7.3 → 0.7.6

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 (185) 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_todo.yml +25 -52
  10. data/README.adoc +2294 -192
  11. data/docs/custom_registers.adoc +228 -0
  12. data/docs/schema_generation.adoc +898 -0
  13. data/docs/schema_import.adoc +364 -0
  14. data/flake.lock +114 -0
  15. data/flake.nix +103 -0
  16. data/lib/lutaml/model/attribute.rb +230 -94
  17. data/lib/lutaml/model/choice.rb +30 -0
  18. data/lib/lutaml/model/collection.rb +195 -0
  19. data/lib/lutaml/model/comparable_model.rb +3 -3
  20. data/lib/lutaml/model/config.rb +26 -3
  21. data/lib/lutaml/model/constants.rb +2 -0
  22. data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
  23. data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
  24. data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
  25. data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
  26. data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
  27. data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
  28. data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
  29. data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
  30. data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
  31. data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
  32. data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
  33. data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
  34. data/lib/lutaml/model/error.rb +10 -0
  35. data/lib/lutaml/model/errors.rb +36 -0
  36. data/lib/lutaml/model/format_registry.rb +5 -2
  37. data/lib/lutaml/model/global_register.rb +41 -0
  38. data/lib/lutaml/model/{hash.rb → hash_adapter.rb} +5 -5
  39. data/lib/lutaml/model/jsonl/document.rb +14 -0
  40. data/lib/lutaml/model/jsonl/mapping.rb +19 -0
  41. data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
  42. data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
  43. data/lib/lutaml/model/jsonl/transform.rb +19 -0
  44. data/lib/lutaml/model/jsonl.rb +21 -0
  45. data/lib/lutaml/model/key_value_document.rb +3 -2
  46. data/lib/lutaml/model/mapping/key_value_mapping.rb +64 -4
  47. data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +4 -0
  48. data/lib/lutaml/model/mapping/mapping_rule.rb +8 -3
  49. data/lib/lutaml/model/register.rb +105 -0
  50. data/lib/lutaml/model/registrable.rb +6 -0
  51. data/lib/lutaml/model/schema/base_schema.rb +64 -0
  52. data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
  53. data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
  54. data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
  55. data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
  56. data/lib/lutaml/model/schema/generator/definition.rb +53 -0
  57. data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
  58. data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
  59. data/lib/lutaml/model/schema/generator/property.rb +110 -0
  60. data/lib/lutaml/model/schema/generator/ref.rb +24 -0
  61. data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
  62. data/lib/lutaml/model/schema/json_schema.rb +42 -49
  63. data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
  64. data/lib/lutaml/model/schema/renderer.rb +36 -0
  65. data/lib/lutaml/model/schema/shared_methods.rb +24 -0
  66. data/lib/lutaml/model/schema/templates/model.erb +9 -0
  67. data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
  68. data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
  69. data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
  70. data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
  71. data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
  72. data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
  73. data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
  74. data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
  75. data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
  76. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
  77. data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
  78. data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
  79. data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
  80. data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
  81. data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
  82. data/lib/lutaml/model/schema.rb +1 -0
  83. data/lib/lutaml/model/sequence.rb +60 -30
  84. data/lib/lutaml/model/serialize.rb +177 -54
  85. data/lib/lutaml/model/services/base.rb +11 -0
  86. data/lib/lutaml/model/services/logger.rb +2 -2
  87. data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
  88. data/lib/lutaml/model/services/type/validator/number.rb +25 -0
  89. data/lib/lutaml/model/services/type/validator/string.rb +52 -0
  90. data/lib/lutaml/model/services/type/validator.rb +43 -0
  91. data/lib/lutaml/model/services/validator.rb +145 -0
  92. data/lib/lutaml/model/services.rb +3 -0
  93. data/lib/lutaml/model/transform/key_value_transform.rb +68 -62
  94. data/lib/lutaml/model/transform/xml_transform.rb +46 -57
  95. data/lib/lutaml/model/transform.rb +23 -8
  96. data/lib/lutaml/model/type/boolean.rb +1 -1
  97. data/lib/lutaml/model/type/date.rb +1 -1
  98. data/lib/lutaml/model/type/date_time.rb +1 -1
  99. data/lib/lutaml/model/type/decimal.rb +11 -9
  100. data/lib/lutaml/model/type/float.rb +2 -1
  101. data/lib/lutaml/model/type/integer.rb +24 -21
  102. data/lib/lutaml/model/type/string.rb +4 -2
  103. data/lib/lutaml/model/type/time.rb +1 -1
  104. data/lib/lutaml/model/type/time_without_date.rb +1 -1
  105. data/lib/lutaml/model/type/value.rb +5 -1
  106. data/lib/lutaml/model/type.rb +5 -2
  107. data/lib/lutaml/model/utils.rb +30 -8
  108. data/lib/lutaml/model/validation.rb +6 -4
  109. data/lib/lutaml/model/version.rb +1 -1
  110. data/lib/lutaml/model/xml/document.rb +37 -19
  111. data/lib/lutaml/model/xml/mapping.rb +74 -13
  112. data/lib/lutaml/model/xml/mapping_rule.rb +10 -2
  113. data/lib/lutaml/model/xml/nokogiri_adapter.rb +5 -3
  114. data/lib/lutaml/model/xml/oga/element.rb +4 -1
  115. data/lib/lutaml/model/xml/oga_adapter.rb +4 -3
  116. data/lib/lutaml/model/xml/ox_adapter.rb +20 -6
  117. data/lib/lutaml/model/xml/xml_element.rb +3 -28
  118. data/lib/lutaml/model/xml_adapter/element.rb +1 -1
  119. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +1 -1
  120. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +1 -1
  121. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +1 -1
  122. data/lib/lutaml/model/yamls/document.rb +14 -0
  123. data/lib/lutaml/model/yamls/mapping.rb +19 -0
  124. data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
  125. data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
  126. data/lib/lutaml/model/yamls/transform.rb +19 -0
  127. data/lib/lutaml/model/yamls.rb +21 -0
  128. data/lib/lutaml/model.rb +7 -31
  129. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -5
  130. data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
  131. data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
  132. data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
  133. data/spec/fixtures/xml/product_catalog.xsd +151 -0
  134. data/spec/fixtures/xml/specifications_schema.xsd +38 -0
  135. data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
  136. data/spec/lutaml/model/attribute_spec.rb +41 -44
  137. data/spec/lutaml/model/choice_spec.rb +44 -0
  138. data/spec/lutaml/model/custom_collection_spec.rb +830 -0
  139. data/spec/lutaml/model/global_register_spec.rb +108 -0
  140. data/spec/lutaml/model/group_spec.rb +9 -3
  141. data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
  142. data/spec/lutaml/model/jsonl_spec.rb +229 -0
  143. data/spec/lutaml/model/multiple_mapping_spec.rb +1 -1
  144. data/spec/lutaml/model/register/key_value_spec.rb +275 -0
  145. data/spec/lutaml/model/register/xml_spec.rb +185 -0
  146. data/spec/lutaml/model/register_spec.rb +147 -0
  147. data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
  148. data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
  149. data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
  150. data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
  151. data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
  152. data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
  153. data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
  154. data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
  155. data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
  156. data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
  157. data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
  158. data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
  159. data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
  160. data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
  161. data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
  162. data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
  163. data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
  164. data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
  165. data/spec/lutaml/model/sequence_spec.rb +36 -0
  166. data/spec/lutaml/model/serializable_spec.rb +31 -0
  167. data/spec/lutaml/model/type_spec.rb +8 -4
  168. data/spec/lutaml/model/utils_spec.rb +3 -3
  169. data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
  170. data/spec/lutaml/model/xml/root_mappings/nested_child_mappings_spec.rb +164 -0
  171. data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
  172. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
  173. data/spec/lutaml/model/xml_adapter_spec.rb +24 -0
  174. data/spec/lutaml/model/xml_mapping_rule_spec.rb +11 -4
  175. data/spec/lutaml/model/xml_mapping_spec.rb +1 -1
  176. data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
  177. data/spec/lutaml/model/yamls_spec.rb +294 -0
  178. data/spec/spec_helper.rb +1 -0
  179. metadata +106 -9
  180. data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
  181. /data/lib/lutaml/model/{hash → hash_adapter}/document.rb +0 -0
  182. /data/lib/lutaml/model/{hash → hash_adapter}/mapping.rb +0 -0
  183. /data/lib/lutaml/model/{hash → hash_adapter}/mapping_rule.rb +0 -0
  184. /data/lib/lutaml/model/{hash → hash_adapter}/standard_adapter.rb +0 -0
  185. /data/lib/lutaml/model/{hash → hash_adapter}/transform.rb +0 -0
@@ -8,11 +8,12 @@ module Lutaml
8
8
  module Model
9
9
  module Xml
10
10
  class Document
11
- attr_reader :root, :encoding
11
+ attr_reader :root, :encoding, :register
12
12
 
13
- def initialize(root, encoding = nil)
13
+ def initialize(root, encoding = nil, register: nil)
14
14
  @root = root
15
15
  @encoding = encoding
16
+ @register = setup_register(register)
16
17
  end
17
18
 
18
19
  def self.parse(xml, _options = {})
@@ -79,7 +80,7 @@ module Lutaml
79
80
  options[:mixed_content] = rule.mixed_content
80
81
  options[:tag_name] = rule.name
81
82
 
82
- options[:mapper_class] = attribute&.type if attribute
83
+ options[:mapper_class] = attribute&.type(register) if attribute
83
84
  options[:set_namespace] = set_namespace?(rule)
84
85
 
85
86
  options
@@ -107,7 +108,7 @@ module Lutaml
107
108
  result["elements"] ||= Lutaml::Model::MappingHash.new
108
109
  result["elements"].assign_or_append_value(
109
110
  self.class.namespaced_name_of(child),
110
- parse_element(child, attr&.type || klass, format),
111
+ parse_element(child, attr&.type(register) || klass, format),
111
112
  )
112
113
  end
113
114
 
@@ -127,9 +128,9 @@ module Lutaml
127
128
  prefix: attr.namespace_prefix,
128
129
  schema_location: attr.value,
129
130
  }
131
+ else
132
+ result[attr.namespaced_name] = attr.value
130
133
  end
131
-
132
- result[attr.namespaced_name] = attr.value
133
134
  end
134
135
 
135
136
  result
@@ -148,17 +149,16 @@ module Lutaml
148
149
  rule = options[:rule]
149
150
 
150
151
  if rule.custom_methods[:to]
151
- options[:mapper_class].new.send(rule.custom_methods[:to], element,
152
- xml.parent, xml)
152
+ options[:mapper_class].new.send(rule.custom_methods[:to], element, xml.parent, xml)
153
153
  return
154
154
  end
155
155
 
156
156
  # Only transform when recursion is not called
157
- if !attribute.collection? || value.is_a?(Array)
157
+ if !attribute.collection? || attribute.collection_instance?(value)
158
158
  value = ExportTransformer.call(value, rule, attribute)
159
159
  end
160
160
 
161
- if value.is_a?(Array) && !Utils.empty_collection?(value)
161
+ if attribute.collection_instance?(value) && !Utils.empty_collection?(value)
162
162
  value.each do |item|
163
163
  add_to_xml(xml, element, prefix, item, options)
164
164
  end
@@ -170,7 +170,7 @@ module Lutaml
170
170
 
171
171
  value = rule.render_value_for(value)
172
172
 
173
- if value && (attribute&.type&.<= Lutaml::Model::Serialize)
173
+ if value && (attribute&.type(register)&.<= Lutaml::Model::Serialize)
174
174
  handle_nested_elements(
175
175
  xml,
176
176
  value,
@@ -195,10 +195,10 @@ module Lutaml
195
195
 
196
196
  def add_value(xml, value, attribute, cdata: false)
197
197
  if !value.nil?
198
- serialized_value = attribute.serialize(value, :xml)
198
+ serialized_value = attribute.serialize(value, :xml, register)
199
199
  if attribute.raw?
200
200
  xml.add_xml_fragment(xml, value)
201
- elsif attribute.type == Lutaml::Model::Type::Hash
201
+ elsif attribute.type(register) == Lutaml::Model::Type::Hash
202
202
  serialized_value.each do |key, val|
203
203
  xml.create_and_add_element(key) do |element|
204
204
  element.text(val)
@@ -242,7 +242,7 @@ module Lutaml
242
242
 
243
243
  next if !element_rule.render?(value, element)
244
244
 
245
- value = [value] if attribute_def.collection? && !value.is_a?(Array)
245
+ value = attribute_def.build_collection(value) if attribute_def.collection? && !attribute_def.collection_instance?(value)
246
246
  end
247
247
 
248
248
  add_to_xml(
@@ -264,8 +264,12 @@ module Lutaml
264
264
  return unless content_rule
265
265
 
266
266
  if content_rule.custom_methods[:to]
267
- mapper_class.new.send(content_rule.custom_methods[:to], element,
268
- xml.parent, xml)
267
+ mapper_class.new.send(
268
+ content_rule.custom_methods[:to],
269
+ element,
270
+ xml.parent,
271
+ xml,
272
+ )
269
273
  else
270
274
  text = content_rule.serialize(element)
271
275
  text = text.join if text.is_a?(Array)
@@ -320,9 +324,10 @@ module Lutaml
320
324
  processed[klass][mapping_rule.name] = true
321
325
 
322
326
  type = if mapping_rule.delegate
323
- attributes[mapping_rule.delegate].type.attributes[mapping_rule.to].type
327
+ attributes[mapping_rule.delegate].type(register)
328
+ .attributes[mapping_rule.to].type(register)
324
329
  else
325
- attributes[mapping_rule.to]&.type
330
+ attributes[mapping_rule.to]&.type(register)
326
331
  end
327
332
 
328
333
  next unless type
@@ -363,7 +368,7 @@ module Lutaml
363
368
 
364
369
  value = mapping_rule.to_value_for(element)
365
370
  attr = attribute_definition_for(element, mapping_rule, mapper_class: options[:mapper_class])
366
- value = attr.serialize(value, :xml) if attr
371
+ value = attr.serialize(value, :xml, register) if attr
367
372
 
368
373
  value = ExportTransformer.call(value, mapping_rule, attr)
369
374
 
@@ -433,6 +438,19 @@ module Lutaml
433
438
 
434
439
  private
435
440
 
441
+ def setup_register(register)
442
+ return register if register.is_a?(Symbol)
443
+
444
+ return_register = if register.is_a?(Lutaml::Model::Register)
445
+ register.id
446
+ elsif @root.respond_to?(:__register)
447
+ @root.__register
448
+ elsif @root.instance_variable_defined?(:@__register)
449
+ @root.instance_variable_get(:@__register)
450
+ end
451
+ return_register || Lutaml::Model::Config.default_register
452
+ end
453
+
436
454
  def determine_mapper_class(element, options)
437
455
  if options[:mapper_class] && element.is_a?(options[:mapper_class])
438
456
  element.class
@@ -17,7 +17,8 @@ module Lutaml
17
17
  :namespace_prefix,
18
18
  :mixed_content,
19
19
  :ordered,
20
- :element_sequence
20
+ :element_sequence,
21
+ :mappings_imported
21
22
 
22
23
  def initialize
23
24
  super
@@ -29,12 +30,19 @@ module Lutaml
29
30
  @raw_mapping = nil
30
31
  @mixed_content = false
31
32
  @format = :xml
33
+ @mappings_imported = true
34
+ @finalized = false
32
35
  end
33
36
 
34
37
  def finalize(mapper_class)
35
38
  if !root_element && !no_root?
36
39
  root(mapper_class.model.to_s)
37
40
  end
41
+ @finalized = true
42
+ end
43
+
44
+ def finalized?
45
+ @finalized
38
46
  end
39
47
 
40
48
  alias mixed_content? mixed_content
@@ -73,6 +81,10 @@ module Lutaml
73
81
  @namespace_prefix = prefix
74
82
  end
75
83
 
84
+ def map_instances(to:)
85
+ map_element(to, to: to)
86
+ end
87
+
76
88
  # rubocop:disable Metrics/ParameterLists
77
89
  def map_element(
78
90
  name,
@@ -244,12 +256,11 @@ module Lutaml
244
256
  alias map_all_content map_all
245
257
 
246
258
  def sequence(&block)
247
- @element_sequence << Sequence.new(self).tap do |s|
248
- s.instance_eval(&block)
249
- end
259
+ @element_sequence << Sequence.new(self).tap { |s| s.instance_eval(&block) }
250
260
  end
251
261
 
252
262
  def import_model_mappings(model)
263
+ return import_mappings_later(model) if model_importable?(model)
253
264
  raise Lutaml::Model::ImportModelWithRootError.new(model) if model.root?
254
265
 
255
266
  mappings = model.mappings_for(:xml)
@@ -258,6 +269,10 @@ module Lutaml
258
269
  (@element_sequence << mappings.element_sequence).flatten!
259
270
  end
260
271
 
272
+ def set_mappings_imported(value)
273
+ @mappings_imported = value
274
+ end
275
+
261
276
  def validate!(key, to, with, render_nil, render_empty, type: nil)
262
277
  validate_raw_mappings!(type)
263
278
  validate_to_and_with_arguments!(key, to, with)
@@ -316,24 +331,49 @@ module Lutaml
316
331
  @raw_mapping
317
332
  end
318
333
 
319
- def mappings
334
+ def mappings(register_id = nil)
335
+ ensure_mappings_imported!(register_id) if finalized?
320
336
  elements + attributes + [content_mapping, raw_mapping].compact
321
337
  end
322
338
 
323
- def element(name)
324
- elements.detect do |rule|
325
- name == rule.to
339
+ def ensure_mappings_imported!(register_id = nil)
340
+ return if @mappings_imported
341
+
342
+ importable_mappings.each do |model|
343
+ import_model_mappings(
344
+ register(register_id).get_class_without_register(model),
345
+ )
346
+ end
347
+
348
+ sequence_importable_mappings.each do |sequence, models|
349
+ models.each do |model|
350
+ sequence.import_model_mappings(
351
+ register(register_id).get_class_without_register(model),
352
+ )
353
+ end
326
354
  end
355
+
356
+ @mappings_imported = true
357
+ end
358
+
359
+ def importable_mappings
360
+ @importable_mappings ||= []
361
+ end
362
+
363
+ def sequence_importable_mappings
364
+ @sequence_importable_mappings ||= Hash.new { |h, k| h[k] = [] }
365
+ end
366
+
367
+ def element(name)
368
+ elements.detect { |rule| name == rule.to }
327
369
  end
328
370
 
329
371
  def attribute(name)
330
- attributes.detect do |rule|
331
- name == rule.to
332
- end
372
+ attributes.detect { |rule| name == rule.to }
333
373
  end
334
374
 
335
- def find_by_name(name)
336
- if ["text", "#cdata-section"].include?(name.to_s)
375
+ def find_by_name(name, type: "Text")
376
+ if ["text", "#cdata-section"].include?(name.to_s) && type == "Text"
337
377
  content_mapping
338
378
  else
339
379
  mappings.detect do |rule|
@@ -342,6 +382,10 @@ module Lutaml
342
382
  end
343
383
  end
344
384
 
385
+ def find_by_to(to)
386
+ mappings.detect { |rule| rule.to.to_s == to.to_s }
387
+ end
388
+
345
389
  def mapping_attributes_hash
346
390
  @attributes
347
391
  end
@@ -378,6 +422,7 @@ module Lutaml
378
422
  value = instance_variable_get(var_name)
379
423
  xml_mapping.instance_variable_set(var_name, Utils.deep_dup(value))
380
424
  end
425
+ xml_mapping.instance_variable_set(:@finalized, true)
381
426
  end
382
427
  end
383
428
 
@@ -404,6 +449,22 @@ module Lutaml
404
449
 
405
450
  new_mappings
406
451
  end
452
+
453
+ private
454
+
455
+ def register(register_id = nil)
456
+ register_id ||= Lutaml::Model::Config.default_register
457
+ Lutaml::Model::GlobalRegister.lookup(register_id)
458
+ end
459
+
460
+ def model_importable?(model)
461
+ model.is_a?(Symbol) || model.is_a?(String)
462
+ end
463
+
464
+ def import_mappings_later(model)
465
+ importable_mappings << model.to_sym
466
+ @mappings_imported = false
467
+ end
407
468
  end
408
469
  end
409
470
  end
@@ -4,7 +4,11 @@ module Lutaml
4
4
  module Model
5
5
  module Xml
6
6
  class MappingRule < MappingRule
7
- attr_reader :namespace, :prefix, :mixed_content, :default_namespace, :cdata
7
+ attr_reader :namespace,
8
+ :prefix,
9
+ :mixed_content,
10
+ :default_namespace,
11
+ :cdata
8
12
 
9
13
  def initialize(
10
14
  name,
@@ -80,6 +84,10 @@ module Lutaml
80
84
  cdata ? "#cdata-section" : "text"
81
85
  end
82
86
 
87
+ def castable?
88
+ !raw_mapping? && !content_mapping? && !custom_methods[:from]
89
+ end
90
+
83
91
  def mixed_content?
84
92
  !!@mixed_content
85
93
  end
@@ -103,7 +111,7 @@ module Lutaml
103
111
 
104
112
  def namespaced_name(parent_namespace = nil, name = self.name)
105
113
  if name.to_s == "lang"
106
- "#{prefix}:#{name}"
114
+ Utils.blank?(prefix) ? name.to_s : "#{prefix}:#{name}"
107
115
  elsif namespace_set? || @attribute
108
116
  [namespace, name].compact.join(":")
109
117
  elsif default_namespace
@@ -72,10 +72,11 @@ module Lutaml
72
72
  content = []
73
73
 
74
74
  element.element_order.each do |object|
75
- index_hash[object.name] ||= -1
76
- curr_index = index_hash[object.name] += 1
75
+ object_key = "#{object.name}-#{object.type}"
76
+ index_hash[object_key] ||= -1
77
+ curr_index = index_hash[object_key] += 1
77
78
 
78
- element_rule = xml_mapping.find_by_name(object.name)
79
+ element_rule = xml_mapping.find_by_name(object.name, type: object.type)
79
80
  next if element_rule.nil?
80
81
 
81
82
  attribute_def = attribute_definition_for(element, element_rule,
@@ -153,6 +154,7 @@ module Lutaml
153
154
  parse_all_children(node, root_node: root_node || self,
154
155
  default_namespace: default_namespace),
155
156
  node.text,
157
+ name: node.name,
156
158
  parent_document: root_node,
157
159
  namespace_prefix: node.namespace&.prefix,
158
160
  default_namespace: default_namespace
@@ -19,11 +19,14 @@ module Lutaml
19
19
  when Moxml::Text
20
20
  node.content
21
21
  end
22
+
23
+ name = OgaAdapter.name_of(node)
22
24
  super(
23
- OgaAdapter.name_of(node),
25
+ name,
24
26
  Hash(attributes),
25
27
  Array(children),
26
28
  text,
29
+ name: name,
27
30
  parent_document: parent,
28
31
  namespace_prefix: namespace_name,
29
32
  )
@@ -126,10 +126,11 @@ module Lutaml
126
126
  content = []
127
127
 
128
128
  element.element_order.each do |object|
129
- index_hash[object.name] ||= -1
130
- curr_index = index_hash[object.name] += 1
129
+ object_key = "#{object.name}-#{object.type}"
130
+ index_hash[object_key] ||= -1
131
+ curr_index = index_hash[object_key] += 1
131
132
 
132
- element_rule = xml_mapping.find_by_name(object.name)
133
+ element_rule = xml_mapping.find_by_name(object.name, type: object.type)
133
134
  next if element_rule.nil?
134
135
 
135
136
  attribute_def = attribute_definition_for(element, element_rule,
@@ -59,10 +59,11 @@ module Lutaml
59
59
  content = []
60
60
 
61
61
  element.element_order.each do |object|
62
- index_hash[object.name] ||= -1
63
- curr_index = index_hash[object.name] += 1
62
+ object_key = "#{object.name}-#{object.type}"
63
+ index_hash[object_key] ||= -1
64
+ curr_index = index_hash[object_key] += 1
64
65
 
65
- element_rule = xml_mapping.find_by_name(object.name)
66
+ element_rule = xml_mapping.find_by_name(object.name, type: object.type)
66
67
  next if element_rule.nil?
67
68
 
68
69
  attribute_def = attribute_definition_for(element, element_rule,
@@ -103,11 +104,11 @@ module Lutaml
103
104
  def initialize(node, root_node: nil)
104
105
  case node
105
106
  when String
106
- super("text", {}, [], node, parent_document: root_node)
107
+ super("text", {}, [], node, parent_document: root_node, name: "text")
107
108
  when Ox::Comment
108
- super("comment", {}, [], node.value, parent_document: root_node)
109
+ super("comment", {}, [], node.value, parent_document: root_node, name: "comment")
109
110
  when Ox::CData
110
- super("#cdata-section", {}, [], node.value, parent_document: root_node)
111
+ super("#cdata-section", {}, [], node.value, parent_document: root_node, name: "#cdata-section")
111
112
  else
112
113
  namespace_attributes(node.attributes).each do |(name, value)|
113
114
  if root_node
@@ -135,16 +136,29 @@ module Lutaml
135
136
  )
136
137
  end
137
138
 
139
+ prefix, name = separate_name_and_prefix(node)
140
+
138
141
  super(
139
142
  node,
140
143
  attributes,
141
144
  parse_children(node, root_node: root_node || self),
142
145
  node.text,
143
146
  parent_document: root_node,
147
+ name: name,
148
+ namespace_prefix: prefix,
144
149
  )
145
150
  end
146
151
  end
147
152
 
153
+ def separate_name_and_prefix(node)
154
+ name = node.name.to_s
155
+
156
+ return [nil, name] unless name.include?(":")
157
+
158
+ prefix, _, name = name.partition(":")
159
+ [prefix, name]
160
+ end
161
+
148
162
  def to_xml
149
163
  return text if text?
150
164
 
@@ -19,12 +19,13 @@ module Lutaml
19
19
  attributes = {},
20
20
  children = [],
21
21
  text = nil,
22
+ name: nil,
22
23
  parent_document: nil,
23
24
  namespace_prefix: nil,
24
25
  default_namespace: nil
25
26
  )
26
- @name = extract_name(node)
27
- @namespace_prefix = namespace_prefix || extract_namespace_prefix(node)
27
+ @name = name
28
+ @namespace_prefix = namespace_prefix
28
29
  @attributes = attributes
29
30
  @children = children
30
31
  @text = text
@@ -92,32 +93,6 @@ module Lutaml
92
93
  namespaces[nil] || @parent_document&.namespaces&.dig(nil)
93
94
  end
94
95
 
95
- def extract_name(node)
96
- name = name_from_node(node)
97
-
98
- n = name.split(":")
99
- return name if n.length <= 1
100
-
101
- n[1..].join(":")
102
- end
103
-
104
- def extract_namespace_prefix(node)
105
- name = name_from_node(node)
106
-
107
- n = name.to_s.split(":")
108
- return if n.length <= 1
109
-
110
- n.first
111
- end
112
-
113
- def name_from_node(node)
114
- if node.is_a?(String)
115
- node
116
- else
117
- node.name.to_s
118
- end
119
- end
120
-
121
96
  def order
122
97
  children.map do |child|
123
98
  type = child.text? ? "Text" : "Element"
@@ -8,7 +8,7 @@ module Lutaml
8
8
  module Model
9
9
  module XmlAdapter
10
10
  class Element < ::Lutaml::Model::Xml::Element
11
- Logger.warn_future_deprication(
11
+ Logger.warn_future_deprecation(
12
12
  old: "Lutaml::Model::XmlAdapter::Element",
13
13
  replacement: "Lutaml::Model::Xml::Element",
14
14
  )
@@ -5,7 +5,7 @@ module Lutaml
5
5
  module Model
6
6
  module XmlAdapter
7
7
  class NokogiriAdapter < ::Lutaml::Model::Xml::NokogiriAdapter
8
- Logger.warn_future_deprication(
8
+ Logger.warn_future_deprecation(
9
9
  old: "Lutaml::Model::XmlAdapter::NokogiriAdapter",
10
10
  replacement: "Lutaml::Model::Xml::NokogiriAdapter",
11
11
  )
@@ -11,7 +11,7 @@ module Lutaml
11
11
  module Model
12
12
  module XmlAdapter
13
13
  class OgaAdapter < ::Lutaml::Model::Xml::OgaAdapter
14
- Logger.warn_future_deprication(
14
+ Logger.warn_future_deprecation(
15
15
  old: "Lutaml::Model::XmlAdapter::OgaAdapter",
16
16
  replacement: "Lutaml::Model::Xml::OgaAdapter",
17
17
  )
@@ -8,7 +8,7 @@ module Lutaml
8
8
  module Model
9
9
  module XmlAdapter
10
10
  class OxAdapter < ::Lutaml::Model::Xml::OxAdapter
11
- Logger.warn_future_deprication(
11
+ Logger.warn_future_deprecation(
12
12
  old: "Lutaml::Model::XmlAdapter::OxAdapter",
13
13
  replacement: "Lutaml::Model::Xml::OxAdapter",
14
14
  )
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yamls
6
+ class Document
7
+ def initialize(yamls = [], register: nil)
8
+ @yamls = yamls
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 Yamls
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:yaml)
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 Yamls
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ require "yaml"
2
+ require_relative "document"
3
+
4
+ module Lutaml
5
+ module Model
6
+ module Yamls
7
+ class StandardAdapter < Document
8
+ FORMAT_SYMBOL = :yaml
9
+
10
+ def self.parse(yamls, _options = {})
11
+ results = []
12
+
13
+ yamls.split(/^---\n/).each do |yaml|
14
+ next if yaml.strip.empty?
15
+
16
+ begin
17
+ results << YAML.safe_load(yaml, aliases: true)
18
+ rescue Psych::SyntaxError => e
19
+ warn "Skipping invalid yaml: #{e.message}"
20
+ end
21
+ end
22
+
23
+ results
24
+ end
25
+
26
+ def to_yamls(*_args)
27
+ @yamls.map do |yaml|
28
+ YAML.dump(yaml).strip
29
+ end.join("\n")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module Lutaml
2
+ module Model
3
+ module Yamls
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ def data_to_model(data, format, options = {})
6
+ mappings = defined_mappings_for(:yamls) || mappings_for(:yaml)
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(:yamls) || mappings_for(:yaml)
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 Yamls
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "yamls/standard_adapter"
11
+ require_relative "yamls/document"
12
+ require_relative "yamls/mapping"
13
+ require_relative "yamls/mapping_rule"
14
+ require_relative "yamls/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :yamls,
18
+ mapping_class: Lutaml::Model::Yamls::Mapping,
19
+ adapter_class: Lutaml::Model::Yamls::StandardAdapter,
20
+ transformer: Lutaml::Model::Yamls::Transform,
21
+ )