lutaml-model 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +49 -48
- data/Gemfile +4 -1
- data/README.adoc +791 -143
- data/RELEASE_NOTES.adoc +346 -0
- data/docs/custom_adapters.adoc +144 -0
- data/lib/lutaml/model/attribute.rb +17 -11
- data/lib/lutaml/model/config.rb +48 -42
- data/lib/lutaml/model/error/polymorphic_error.rb +7 -2
- data/lib/lutaml/model/format_registry.rb +41 -0
- data/lib/lutaml/model/hash/document.rb +11 -0
- data/lib/lutaml/model/hash/mapping.rb +19 -0
- data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
- data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
- data/lib/lutaml/model/hash/transform.rb +8 -0
- data/lib/lutaml/model/hash.rb +21 -0
- data/lib/lutaml/model/json/document.rb +11 -0
- data/lib/lutaml/model/json/mapping.rb +19 -0
- data/lib/lutaml/model/json/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
- data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
- data/lib/lutaml/model/json/transform.rb +8 -0
- data/lib/lutaml/model/json.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +27 -0
- data/lib/lutaml/model/mapping/key_value_mapping.rb +8 -4
- data/lib/lutaml/model/mapping/mapping.rb +13 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +7 -6
- data/lib/lutaml/model/serialization_adapter.rb +22 -0
- data/lib/lutaml/model/serialize.rb +146 -521
- data/lib/lutaml/model/services/logger.rb +54 -0
- data/lib/lutaml/model/services/transformer.rb +48 -0
- data/lib/lutaml/model/services.rb +2 -0
- data/lib/lutaml/model/toml/document.rb +11 -0
- data/lib/lutaml/model/toml/mapping.rb +27 -0
- data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
- data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
- data/lib/lutaml/model/toml/transform.rb +8 -0
- data/lib/lutaml/model/toml.rb +30 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
- data/lib/lutaml/model/transform/xml_transform.rb +239 -0
- data/lib/lutaml/model/transform.rb +78 -0
- data/lib/lutaml/model/type/value.rb +6 -9
- data/lib/lutaml/model/uninitialized_class.rb +1 -1
- data/lib/lutaml/model/utils.rb +30 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
- data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
- data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
- data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +6 -7
- data/lib/lutaml/model/xml/element.rb +32 -0
- data/lib/lutaml/model/xml/mapping.rb +410 -0
- data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
- data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
- data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
- data/lib/lutaml/model/xml/transform.rb +8 -0
- data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +6 -3
- data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
- data/lib/lutaml/model/xml.rb +31 -0
- data/lib/lutaml/model/xml_adapter/element.rb +11 -25
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
- data/lib/lutaml/model/yaml/document.rb +10 -0
- data/lib/lutaml/model/yaml/mapping.rb +19 -0
- data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
- data/lib/lutaml/model/yaml/transform.rb +8 -0
- data/lib/lutaml/model/yaml.rb +21 -0
- data/lib/lutaml/model.rb +39 -4
- data/lutaml-model.gemspec +0 -4
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -4
- data/spec/lutaml/model/cdata_spec.rb +7 -7
- data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
- data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
- data/spec/lutaml/model/group_spec.rb +18 -7
- data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
- data/spec/lutaml/model/json_adapter_spec.rb +6 -6
- data/spec/lutaml/model/key_value_mapping_spec.rb +25 -1
- data/spec/lutaml/model/mixed_content_spec.rb +24 -24
- data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
- data/spec/lutaml/model/ordered_content_spec.rb +6 -6
- data/spec/lutaml/model/polymorphic_spec.rb +178 -0
- data/spec/lutaml/model/root_mappings_spec.rb +3 -3
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
- data/spec/lutaml/model/serializable_spec.rb +179 -103
- data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/toml_spec.rb +51 -0
- data/spec/lutaml/model/transformation_spec.rb +72 -15
- data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
- data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
- data/spec/lutaml/model/xml/xml_element_spec.rb +1 -1
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +3 -3
- data/spec/lutaml/model/xml_mapping_spec.rb +26 -14
- data/spec/lutaml/model/xml_spec.rb +63 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
- data/spec/spec_helper.rb +3 -3
- metadata +64 -59
- data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
- data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
- data/lib/lutaml/model/loggable.rb +0 -15
- data/lib/lutaml/model/mapping/json_mapping.rb +0 -17
- data/lib/lutaml/model/mapping/toml_mapping.rb +0 -25
- data/lib/lutaml/model/mapping/xml_mapping.rb +0 -389
- data/lib/lutaml/model/mapping/xml_mapping_rule.rb +0 -139
- data/lib/lutaml/model/mapping/yaml_mapping.rb +0 -17
- data/lib/lutaml/model/mapping.rb +0 -14
- data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
- data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
- data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
- data/lib/lutaml/model/toml_adapter.rb +0 -6
- data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
- data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
- data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -1,10 +1,9 @@
|
|
1
|
-
require_relative "yaml_adapter"
|
2
1
|
require_relative "xml_adapter"
|
3
2
|
require_relative "config"
|
4
3
|
require_relative "type"
|
5
4
|
require_relative "attribute"
|
6
5
|
require_relative "mapping_hash"
|
7
|
-
require_relative "mapping"
|
6
|
+
# require_relative "mapping"
|
8
7
|
require_relative "json_adapter"
|
9
8
|
require_relative "comparable_model"
|
10
9
|
require_relative "schema_location"
|
@@ -13,6 +12,7 @@ require_relative "error"
|
|
13
12
|
require_relative "choice"
|
14
13
|
require_relative "sequence"
|
15
14
|
require_relative "liquefiable"
|
15
|
+
require_relative "transform"
|
16
16
|
|
17
17
|
module Lutaml
|
18
18
|
module Model
|
@@ -159,7 +159,8 @@ module Lutaml
|
|
159
159
|
mapping = model.mappings_for(format)
|
160
160
|
mapping = Utils.deep_dup(mapping)
|
161
161
|
|
162
|
-
|
162
|
+
klass = ::Lutaml::Model::Config.mappings_class_for(format)
|
163
|
+
@mappings[format] ||= klass.new
|
163
164
|
|
164
165
|
if format == :xml
|
165
166
|
@mappings[format].merge_mapping_attributes(mapping)
|
@@ -262,71 +263,68 @@ module Lutaml
|
|
262
263
|
attributes.select { |_, attr| attr.enum? }
|
263
264
|
end
|
264
265
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
mappings[format].instance_eval(&block)
|
266
|
+
def process_mapping(format, &block)
|
267
|
+
# klass = Lutaml::Model.const_get("#{format.to_s.capitalize}Mapping")
|
268
|
+
# mappings[format] ||= klass.new
|
269
|
+
# mappings[format].instance_eval(&block)
|
270
270
|
|
271
|
-
|
272
|
-
mappings[format].root(model.to_s)
|
273
|
-
end
|
274
|
-
end
|
271
|
+
# handle_root_assignment(mappings, format)
|
275
272
|
|
276
|
-
|
277
|
-
|
273
|
+
klass = ::Lutaml::Model::Config.mappings_class_for(format)
|
274
|
+
mappings[format] ||= klass.new
|
278
275
|
|
279
|
-
|
276
|
+
mappings[format].instance_eval(&block)
|
280
277
|
|
281
|
-
|
282
|
-
|
278
|
+
if mappings[format].respond_to?(:finalize)
|
279
|
+
mappings[format].finalize(self)
|
283
280
|
end
|
281
|
+
end
|
284
282
|
|
285
|
-
|
286
|
-
|
287
|
-
return doc.map { |item| send(:"of_#{format}", item) }
|
288
|
-
end
|
283
|
+
def from(format, data, options = {})
|
284
|
+
return data if Utils.uninitialized?(data)
|
289
285
|
|
290
|
-
|
291
|
-
raise Lutaml::Model::NoRootMappingError.new(self) unless root?
|
286
|
+
adapter = Lutaml::Model::Config.adapter_for(format)
|
292
287
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
288
|
+
doc = adapter.parse(data, options)
|
289
|
+
public_send(:"of_#{format}", doc, options)
|
290
|
+
end
|
291
|
+
|
292
|
+
def of(format, doc, options = {})
|
293
|
+
if doc.is_a?(Array)
|
294
|
+
return doc.map { |item| send(:"of_#{format}", item) }
|
298
295
|
end
|
299
296
|
|
300
|
-
|
301
|
-
|
302
|
-
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
297
|
+
if format == :xml
|
298
|
+
raise Lutaml::Model::NoRootMappingError.new(self) unless root?
|
303
299
|
|
304
|
-
|
305
|
-
xml_options = { mapper_class: self }
|
306
|
-
adapter.new(value).public_send(:"to_#{format}", xml_options)
|
307
|
-
else
|
308
|
-
adapter.new(value).public_send(:"to_#{format}")
|
309
|
-
end
|
300
|
+
options[:encoding] = doc.encoding
|
310
301
|
end
|
311
302
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
end
|
303
|
+
transformer = Lutaml::Model::Config.transformer_for(format)
|
304
|
+
transformer.data_to_model(self, doc, format, options)
|
305
|
+
end
|
316
306
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
end
|
307
|
+
def to(format, instance, options = {})
|
308
|
+
value = public_send(:"as_#{format}", instance, options)
|
309
|
+
adapter = Lutaml::Model::Config.adapter_for(format)
|
321
310
|
|
322
|
-
|
311
|
+
options[:mapper_class] = self if format == :xml
|
323
312
|
|
324
|
-
|
325
|
-
end
|
313
|
+
adapter.new(value).public_send(:"to_#{format}", options)
|
326
314
|
end
|
327
315
|
|
328
316
|
def as(format, instance, options = {})
|
329
|
-
|
317
|
+
if instance.is_a?(Array)
|
318
|
+
return instance.map { |item| public_send(:"as_#{format}", item) }
|
319
|
+
end
|
320
|
+
|
321
|
+
unless instance.is_a?(model)
|
322
|
+
msg = "argument is a '#{instance.class}' but should be a '#{model}'"
|
323
|
+
raise Lutaml::Model::IncorrectModelError, msg
|
324
|
+
end
|
325
|
+
|
326
|
+
transformer = Lutaml::Model::Config.transformer_for(format)
|
327
|
+
transformer.model_to_data(self, instance, format, options)
|
330
328
|
end
|
331
329
|
|
332
330
|
def key_value(&block)
|
@@ -336,93 +334,15 @@ module Lutaml
|
|
336
334
|
end
|
337
335
|
end
|
338
336
|
|
339
|
-
def hash_representation(instance, format, options = {})
|
340
|
-
only = options[:only]
|
341
|
-
except = options[:except]
|
342
|
-
mappings = mappings_for(format).mappings
|
343
|
-
|
344
|
-
mappings.each_with_object({}) do |rule, hash|
|
345
|
-
name = rule.to
|
346
|
-
attr = attributes[name]
|
347
|
-
|
348
|
-
next if except&.include?(name) || (only && !only.include?(name))
|
349
|
-
next handle_delegate(instance, rule, hash, format) if rule.delegate
|
350
|
-
|
351
|
-
if rule.custom_methods[:to]
|
352
|
-
next instance.send(rule.custom_methods[:to], instance, hash)
|
353
|
-
end
|
354
|
-
|
355
|
-
value = rule.serialize(instance)
|
356
|
-
|
357
|
-
if rule.raw_mapping?
|
358
|
-
adapter = Lutaml::Model::Config.send(:"#{format}_adapter")
|
359
|
-
return adapter.parse(value, options)
|
360
|
-
end
|
361
|
-
|
362
|
-
if export_method = rule.transform[:export] || attr.transform_export_method
|
363
|
-
value = export_method.call(value)
|
364
|
-
end
|
365
|
-
|
366
|
-
next hash.merge!(generate_hash_from_child_mappings(attr, value, format, rule.root_mappings)) if rule.root_mapping?
|
367
|
-
|
368
|
-
value = if rule.child_mappings
|
369
|
-
generate_hash_from_child_mappings(attr, value, format, rule.child_mappings)
|
370
|
-
else
|
371
|
-
attr.serialize(value, format, options)
|
372
|
-
end
|
373
|
-
|
374
|
-
next if !rule.render?(value, instance, options)
|
375
|
-
|
376
|
-
value = apply_value_map(value, rule.value_map(:to, options), attr)
|
377
|
-
|
378
|
-
rule_from_name = rule.multiple_mappings? ? rule.from.first.to_s : rule.from.to_s
|
379
|
-
hash[rule_from_name] = value
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
def apply_value_map(value, value_map, attr)
|
384
|
-
if value.nil?
|
385
|
-
value_for_option(value_map[:nil], attr)
|
386
|
-
elsif Utils.empty?(value)
|
387
|
-
value_for_option(value_map[:empty], attr, value)
|
388
|
-
elsif Utils.uninitialized?(value)
|
389
|
-
value_for_option(value_map[:omitted], attr)
|
390
|
-
else
|
391
|
-
value
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
def value_for_option(option, attr, empty_value = nil)
|
396
|
-
return nil if option == :nil
|
397
|
-
return empty_value || empty_object(attr) if option == :empty
|
398
|
-
|
399
|
-
Lutaml::Model::UninitializedClass.instance
|
400
|
-
end
|
401
|
-
|
402
|
-
def empty_object(attr)
|
403
|
-
return [] if attr.collection?
|
404
|
-
|
405
|
-
""
|
406
|
-
end
|
407
|
-
|
408
|
-
def handle_delegate(instance, rule, hash, format)
|
409
|
-
name = rule.to
|
410
|
-
value = instance.send(rule.delegate).send(name)
|
411
|
-
return if value.nil? && !rule.render_nil
|
412
|
-
|
413
|
-
attribute = instance.send(rule.delegate).class.attributes[name]
|
414
|
-
rule_from_name = rule.multiple_mappings? ? rule.from.first.to_s : rule.from.to_s
|
415
|
-
hash[rule_from_name] = attribute.serialize(value, format)
|
416
|
-
end
|
417
|
-
|
418
337
|
def mappings_for(format)
|
419
338
|
mappings[format] || default_mappings(format)
|
420
339
|
end
|
421
340
|
|
422
341
|
def default_mappings(format)
|
423
|
-
|
342
|
+
klass = ::Lutaml::Model::Config.mappings_class_for(format)
|
343
|
+
mappings = klass.new
|
424
344
|
|
425
|
-
|
345
|
+
mappings.tap do |mapping|
|
426
346
|
attributes&.each_key do |name|
|
427
347
|
mapping.map_element(
|
428
348
|
name.to_s,
|
@@ -434,110 +354,6 @@ module Lutaml
|
|
434
354
|
end
|
435
355
|
end
|
436
356
|
|
437
|
-
def translate_mappings(hash, child_mappings, attr, format)
|
438
|
-
return hash unless child_mappings
|
439
|
-
|
440
|
-
hash.map do |key, value|
|
441
|
-
child_hash = child_mappings.to_h do |attr_name, path|
|
442
|
-
attr_value = if path == :key
|
443
|
-
key
|
444
|
-
elsif path == :value
|
445
|
-
value
|
446
|
-
else
|
447
|
-
path = [path] unless path.is_a?(Array)
|
448
|
-
value.dig(*path.map(&:to_s))
|
449
|
-
end
|
450
|
-
|
451
|
-
attr_rule = attr.type.mappings_for(format).find_by_to(attr_name)
|
452
|
-
[attr_rule.from.to_s, attr_value]
|
453
|
-
end
|
454
|
-
|
455
|
-
if child_mappings.values == [:key] && hash.values.all?(Hash)
|
456
|
-
child_hash.merge!(value)
|
457
|
-
end
|
458
|
-
|
459
|
-
attr.type.apply_hash_mapping(
|
460
|
-
child_hash,
|
461
|
-
attr.type.model.new,
|
462
|
-
format,
|
463
|
-
{ mappings: attr.type.mappings_for(format).mappings },
|
464
|
-
)
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
|
-
def generate_hash_from_child_mappings(attr, value, format, child_mappings)
|
469
|
-
return value unless child_mappings
|
470
|
-
|
471
|
-
hash = {}
|
472
|
-
|
473
|
-
if child_mappings.values == [:key]
|
474
|
-
klass = value.first.class
|
475
|
-
mappings = klass.mappings_for(format)
|
476
|
-
|
477
|
-
klass.attributes.each_key do |name|
|
478
|
-
next if child_mappings.key?(name.to_sym) || child_mappings.key?(name.to_s)
|
479
|
-
|
480
|
-
child_mappings[name.to_sym] = mappings.find_by_to(name)&.name.to_s || name.to_s
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
value.each do |child_obj|
|
485
|
-
map_key = nil
|
486
|
-
map_value = {}
|
487
|
-
mapping_rules = attr.type.mappings_for(format)
|
488
|
-
|
489
|
-
child_mappings.each do |attr_name, path|
|
490
|
-
mapping_rule = mapping_rules.find_by_to(attr_name)
|
491
|
-
|
492
|
-
attr_value = child_obj.send(attr_name)
|
493
|
-
|
494
|
-
attr_value = if attr_value.is_a?(Lutaml::Model::Serialize)
|
495
|
-
attr_value.to_yaml_hash
|
496
|
-
elsif attr_value.is_a?(Array) && attr_value.first.is_a?(Lutaml::Model::Serialize)
|
497
|
-
attr_value.map(&:to_yaml_hash)
|
498
|
-
else
|
499
|
-
attr_value
|
500
|
-
end
|
501
|
-
|
502
|
-
next unless mapping_rule&.render?(attr_value, nil)
|
503
|
-
|
504
|
-
if path == :key
|
505
|
-
map_key = attr_value
|
506
|
-
elsif path == :value
|
507
|
-
map_value = attr_value
|
508
|
-
else
|
509
|
-
path = [path] unless path.is_a?(Array)
|
510
|
-
path[0...-1].inject(map_value) do |acc, k|
|
511
|
-
acc[k.to_s] ||= {}
|
512
|
-
end.public_send(:[]=, path.last.to_s, attr_value)
|
513
|
-
end
|
514
|
-
end
|
515
|
-
|
516
|
-
map_value = nil if map_value.empty?
|
517
|
-
hash[map_key] = map_value
|
518
|
-
end
|
519
|
-
|
520
|
-
hash
|
521
|
-
end
|
522
|
-
|
523
|
-
def valid_rule?(rule)
|
524
|
-
attribute = attribute_for_rule(rule)
|
525
|
-
|
526
|
-
!!attribute || rule.custom_methods[:from]
|
527
|
-
end
|
528
|
-
|
529
|
-
def attribute_for_rule(rule)
|
530
|
-
return attributes[rule.to] unless rule.delegate
|
531
|
-
|
532
|
-
attributes[rule.delegate].type.attributes[rule.to]
|
533
|
-
end
|
534
|
-
|
535
|
-
def attribute_for_child(child_name, format)
|
536
|
-
mapping_rule = mappings_for(format).find_by_name(child_name)
|
537
|
-
|
538
|
-
attribute_for_rule(mapping_rule) if mapping_rule
|
539
|
-
end
|
540
|
-
|
541
357
|
def apply_mappings(doc, format, options = {})
|
542
358
|
instance = options[:instance] || model.new
|
543
359
|
return instance if Utils.blank?(doc)
|
@@ -548,10 +364,9 @@ module Lutaml
|
|
548
364
|
return resolve_polymorphic(doc, format, mappings, instance, options)
|
549
365
|
end
|
550
366
|
|
551
|
-
options[:mappings] = mappings.mappings
|
552
|
-
|
553
|
-
|
554
|
-
apply_hash_mapping(doc, instance, format, options)
|
367
|
+
# options[:mappings] = mappings.mappings
|
368
|
+
transformer = Lutaml::Model::Config.transformer_for(format)
|
369
|
+
transformer.data_to_model(self, doc, format, options)
|
555
370
|
end
|
556
371
|
|
557
372
|
def resolve_polymorphic(doc, format, mappings, instance, options = {})
|
@@ -565,243 +380,29 @@ module Lutaml
|
|
565
380
|
klass.apply_mappings(doc, format, options)
|
566
381
|
end
|
567
382
|
|
568
|
-
def
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
validate_document!(doc, options)
|
576
|
-
|
577
|
-
set_instance_ordering(instance, doc, options)
|
578
|
-
set_schema_location(instance, doc)
|
579
|
-
|
580
|
-
defaults_used = []
|
581
|
-
validate_sequence!(doc.root.order)
|
582
|
-
|
583
|
-
mappings.each do |rule|
|
584
|
-
raise "Attribute '#{rule.to}' not found in #{self}" unless valid_rule?(rule)
|
585
|
-
|
586
|
-
attr = attribute_for_rule(rule)
|
587
|
-
next if attr&.derived?
|
588
|
-
|
589
|
-
new_opts = options.dup
|
590
|
-
if rule.namespace_set?
|
591
|
-
new_opts[:default_namespace] = rule.namespace
|
592
|
-
end
|
593
|
-
|
594
|
-
value = if rule.raw_mapping?
|
595
|
-
doc.root.inner_xml
|
596
|
-
elsif rule.content_mapping?
|
597
|
-
rule.cdata ? doc.cdata : doc.text
|
598
|
-
else
|
599
|
-
val = value_for_rule(doc, rule, new_opts, instance)
|
600
|
-
|
601
|
-
if (Utils.uninitialized?(val) || val.nil?) && (instance.using_default?(rule.to) || rule.render_default)
|
602
|
-
defaults_used << rule.to
|
603
|
-
attr&.default || rule.to_value_for(instance)
|
604
|
-
else
|
605
|
-
val
|
606
|
-
end
|
607
|
-
end
|
608
|
-
|
609
|
-
value = apply_value_map(value, rule.value_map(:from, new_opts), attr)
|
610
|
-
value = normalize_xml_value(value, rule, attr, new_opts)
|
611
|
-
rule.deserialize(instance, value, attributes, self)
|
612
|
-
end
|
613
|
-
|
614
|
-
defaults_used.each do |attr_name|
|
615
|
-
instance.using_default_for(attr_name)
|
616
|
-
end
|
617
|
-
|
618
|
-
instance
|
619
|
-
end
|
620
|
-
|
621
|
-
def prepare_options(options)
|
622
|
-
opts = Utils.deep_dup(options)
|
623
|
-
opts[:default_namespace] ||= mappings_for(:xml)&.namespace_uri
|
624
|
-
|
625
|
-
opts
|
626
|
-
end
|
627
|
-
|
628
|
-
def validate_document!(doc, options)
|
629
|
-
return unless doc.is_a?(Array)
|
630
|
-
|
631
|
-
raise Lutaml::Model::CollectionTrueMissingError(
|
632
|
-
self,
|
633
|
-
options[:caller_class],
|
634
|
-
)
|
635
|
-
end
|
636
|
-
|
637
|
-
def set_instance_ordering(instance, doc, options)
|
638
|
-
return unless instance.respond_to?(:ordered=)
|
639
|
-
|
640
|
-
instance.element_order = doc.root.order
|
641
|
-
instance.ordered = mappings_for(:xml).ordered? || options[:ordered]
|
642
|
-
instance.mixed = mappings_for(:xml).mixed_content? || options[:mixed_content]
|
643
|
-
end
|
644
|
-
|
645
|
-
def set_schema_location(instance, doc)
|
646
|
-
schema_location = doc.attributes.values.find do |a|
|
647
|
-
a.unprefixed_name == "schemaLocation"
|
648
|
-
end
|
649
|
-
|
650
|
-
return if schema_location.nil?
|
651
|
-
|
652
|
-
instance.schema_location = Lutaml::Model::SchemaLocation.new(
|
653
|
-
schema_location: schema_location.value,
|
654
|
-
prefix: schema_location.namespace_prefix,
|
655
|
-
namespace: schema_location.namespace,
|
656
|
-
)
|
657
|
-
end
|
658
|
-
|
659
|
-
def value_for_rule(doc, rule, options, instance)
|
660
|
-
rule_names = rule.namespaced_names(options[:default_namespace])
|
661
|
-
|
662
|
-
if rule.attribute?
|
663
|
-
doc.root.find_attribute_value(rule_names)
|
383
|
+
def apply_value_map(value, value_map, attr)
|
384
|
+
if value.nil?
|
385
|
+
value_for_option(value_map[:nil], attr)
|
386
|
+
elsif Utils.empty?(value)
|
387
|
+
value_for_option(value_map[:empty], attr, value)
|
388
|
+
elsif Utils.uninitialized?(value)
|
389
|
+
value_for_option(value_map[:omitted], attr)
|
664
390
|
else
|
665
|
-
|
666
|
-
children = doc.children.select do |child|
|
667
|
-
rule_names.include?(child.namespaced_name) && !child.text?
|
668
|
-
end
|
669
|
-
|
670
|
-
if rule.using_custom_methods? || attr.type == Lutaml::Model::Type::Hash
|
671
|
-
return_child = attr.type == Lutaml::Model::Type::Hash || !attr.collection? if attr
|
672
|
-
return return_child ? children.first : children
|
673
|
-
end
|
674
|
-
|
675
|
-
return handle_cdata(children) if rule.cdata
|
676
|
-
|
677
|
-
values = []
|
678
|
-
|
679
|
-
if Utils.present?(children)
|
680
|
-
instance.value_set_for(attr.name)
|
681
|
-
else
|
682
|
-
children = nil
|
683
|
-
values = Lutaml::Model::UninitializedClass.instance
|
684
|
-
end
|
685
|
-
|
686
|
-
children&.each do |child|
|
687
|
-
if !rule.using_custom_methods? && attr.type <= Serialize
|
688
|
-
cast_options = options.except(:mappings)
|
689
|
-
cast_options[:polymorphic] = rule.polymorphic if rule.polymorphic
|
690
|
-
|
691
|
-
values << attr.cast(child, :xml, cast_options)
|
692
|
-
elsif attr.raw?
|
693
|
-
values << inner_xml_of(child)
|
694
|
-
else
|
695
|
-
return nil if rule.render_nil_as_nil? && child.nil_element?
|
696
|
-
|
697
|
-
text = child.nil_element? ? nil : (child&.text&.+ child&.cdata)
|
698
|
-
values << text
|
699
|
-
end
|
700
|
-
end
|
701
|
-
|
702
|
-
normalized_value_for_attr(values, attr)
|
703
|
-
end
|
704
|
-
end
|
705
|
-
|
706
|
-
def handle_cdata(children)
|
707
|
-
values = children.map do |child|
|
708
|
-
child.cdata_children&.map(&:text)
|
709
|
-
end.flatten
|
710
|
-
|
711
|
-
children.count > 1 ? values : values.first
|
712
|
-
end
|
713
|
-
|
714
|
-
def normalized_value_for_attr(values, attr)
|
715
|
-
# for xml collection true cases like
|
716
|
-
# <store><items /></store>
|
717
|
-
# <store><items xsi:nil="true"/></store>
|
718
|
-
# <store><items></items></store>
|
719
|
-
#
|
720
|
-
# these are considered empty collection
|
721
|
-
return [] if attr&.collection? && [[nil], [""]].include?(values)
|
722
|
-
return values if attr&.collection?
|
723
|
-
|
724
|
-
values.is_a?(Array) ? values.first : values
|
725
|
-
end
|
726
|
-
|
727
|
-
def apply_hash_mapping(doc, instance, format, options = {})
|
728
|
-
mappings = options[:mappings] || mappings_for(format).mappings
|
729
|
-
mappings.each do |rule|
|
730
|
-
raise "Attribute '#{rule.to}' not found in #{self}" unless valid_rule?(rule)
|
731
|
-
|
732
|
-
attr = attribute_for_rule(rule)
|
733
|
-
next if attr&.derived?
|
734
|
-
|
735
|
-
names = rule.multiple_mappings? ? rule.name : [rule.name]
|
736
|
-
|
737
|
-
values = names.collect do |rule_name|
|
738
|
-
if rule.root_mapping?
|
739
|
-
doc
|
740
|
-
elsif rule.raw_mapping?
|
741
|
-
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
742
|
-
adapter.new(doc).public_send(:"to_#{format}")
|
743
|
-
elsif doc.key?(rule_name.to_s)
|
744
|
-
doc[rule_name.to_s]
|
745
|
-
elsif doc.key?(rule_name.to_sym)
|
746
|
-
doc[rule_name.to_sym]
|
747
|
-
elsif attr&.default_set?
|
748
|
-
attr&.default
|
749
|
-
else
|
750
|
-
Lutaml::Model::UninitializedClass.instance
|
751
|
-
end
|
752
|
-
end.compact
|
753
|
-
|
754
|
-
value = values.find { |v| Utils.initialized?(v) } || values.first
|
755
|
-
|
756
|
-
value = apply_value_map(value, rule.value_map(:from, options), attr)
|
757
|
-
|
758
|
-
if rule.using_custom_methods?
|
759
|
-
if Utils.present?(value)
|
760
|
-
value = new.send(rule.custom_methods[:from], instance, value)
|
761
|
-
end
|
762
|
-
|
763
|
-
next
|
764
|
-
end
|
765
|
-
|
766
|
-
value = translate_mappings(value, rule.hash_mappings, attr, format)
|
767
|
-
|
768
|
-
cast_options = {}
|
769
|
-
cast_options[:polymorphic] = rule.polymorphic if rule.polymorphic
|
770
|
-
|
771
|
-
value = attr.cast(value, format, cast_options) unless rule.hash_mappings
|
772
|
-
attr.valid_collection!(value, self)
|
773
|
-
|
774
|
-
rule.deserialize(instance, value, attributes, self)
|
391
|
+
value
|
775
392
|
end
|
776
|
-
|
777
|
-
instance
|
778
393
|
end
|
779
394
|
|
780
|
-
def
|
781
|
-
|
782
|
-
|
783
|
-
return value unless cast_value?(attr, rule)
|
784
|
-
|
785
|
-
options.merge(caller_class: self, mixed_content: rule.mixed_content)
|
786
|
-
attr.cast(
|
787
|
-
value,
|
788
|
-
:xml,
|
789
|
-
options,
|
790
|
-
)
|
791
|
-
end
|
395
|
+
def value_for_option(option, attr, empty_value = nil)
|
396
|
+
return nil if option == :nil
|
397
|
+
return empty_value || empty_object(attr) if option == :empty
|
792
398
|
|
793
|
-
|
794
|
-
attr &&
|
795
|
-
!rule.raw_mapping? &&
|
796
|
-
!rule.content_mapping? &&
|
797
|
-
!rule.custom_methods[:from]
|
399
|
+
Lutaml::Model::UninitializedClass.instance
|
798
400
|
end
|
799
401
|
|
800
|
-
def
|
801
|
-
return
|
802
|
-
return value.one? && value.text? unless attr
|
402
|
+
def empty_object(attr)
|
403
|
+
return [] if attr.collection?
|
803
404
|
|
804
|
-
|
405
|
+
""
|
805
406
|
end
|
806
407
|
|
807
408
|
def ensure_utf8(value)
|
@@ -821,62 +422,53 @@ module Lutaml
|
|
821
422
|
value
|
822
423
|
end
|
823
424
|
end
|
425
|
+
end
|
824
426
|
|
825
|
-
|
826
|
-
|
827
|
-
current_order = element_order.filter_map(&:element_tag)
|
427
|
+
def self.register_format_mapping_method(format)
|
428
|
+
method_name = format == :hash ? :hsh : format
|
828
429
|
|
829
|
-
|
830
|
-
|
831
|
-
end
|
430
|
+
::Lutaml::Model::Serialize::ClassMethods.define_method(method_name) do |&block|
|
431
|
+
process_mapping(format, &block)
|
832
432
|
end
|
433
|
+
end
|
833
434
|
|
834
|
-
|
435
|
+
def self.register_from_format_method(format)
|
436
|
+
ClassMethods.define_method(:"from_#{format}") do |data, options = {}|
|
437
|
+
from(format, data, options)
|
438
|
+
end
|
835
439
|
|
836
|
-
|
837
|
-
|
838
|
-
when XmlAdapter::XmlElement
|
839
|
-
node.inner_xml
|
840
|
-
else
|
841
|
-
node.children.map(&:to_xml).join
|
842
|
-
end
|
440
|
+
ClassMethods.define_method(:"of_#{format}") do |doc, options = {}|
|
441
|
+
of(format, doc, options)
|
843
442
|
end
|
844
443
|
end
|
845
444
|
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
@using_default = {}
|
851
|
-
|
852
|
-
return unless self.class.attributes
|
445
|
+
def self.register_to_format_method(format)
|
446
|
+
ClassMethods.define_method(:"to_#{format}") do |instance, options = {}|
|
447
|
+
to(format, instance, options)
|
448
|
+
end
|
853
449
|
|
854
|
-
|
855
|
-
|
856
|
-
@element_order = attrs.item_order
|
450
|
+
ClassMethods.define_method(:"as_#{format}") do |instance, options = {}|
|
451
|
+
as(format, instance, options)
|
857
452
|
end
|
858
453
|
|
859
|
-
|
860
|
-
self.
|
454
|
+
define_method(:"to_#{format}") do |options = {}|
|
455
|
+
raise Lutaml::Model::NoRootMappingError.new(self.class) if format == :xml && !self.class.root?
|
456
|
+
|
457
|
+
options[:parse_encoding] = encoding if encoding
|
458
|
+
self.class.to(format, self, options)
|
861
459
|
end
|
460
|
+
end
|
862
461
|
|
863
|
-
|
864
|
-
|
462
|
+
attr_accessor :element_order, :schema_location, :encoding
|
463
|
+
attr_writer :ordered, :mixed
|
865
464
|
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
using_default_for(name)
|
870
|
-
attr.default
|
871
|
-
else
|
872
|
-
Lutaml::Model::UninitializedClass.instance
|
873
|
-
end
|
465
|
+
def initialize(attrs = {}, options = {})
|
466
|
+
@using_default = {}
|
467
|
+
return unless self.class.attributes
|
874
468
|
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
using_default_for(name) if default
|
879
|
-
end
|
469
|
+
set_ordering(attrs)
|
470
|
+
set_schema_location(attrs)
|
471
|
+
initialize_attributes(attrs, options)
|
880
472
|
end
|
881
473
|
|
882
474
|
def value_map(options)
|
@@ -926,7 +518,7 @@ module Lutaml
|
|
926
518
|
end
|
927
519
|
|
928
520
|
def method_missing(method_name, *args)
|
929
|
-
if method_name.to_s.end_with?("=") &&
|
521
|
+
if method_name.to_s.end_with?("=") && attribute_exist?(method_name)
|
930
522
|
define_singleton_method(method_name) do |value|
|
931
523
|
instance_variable_set(:"@#{method_name.to_s.chomp('=')}", value)
|
932
524
|
end
|
@@ -936,6 +528,17 @@ module Lutaml
|
|
936
528
|
end
|
937
529
|
end
|
938
530
|
|
531
|
+
def respond_to_missing?(method_name, include_private = false)
|
532
|
+
(method_name.to_s.end_with?("=") && attribute_exist?(method_name)) ||
|
533
|
+
super
|
534
|
+
end
|
535
|
+
|
536
|
+
def attribute_exist?(name)
|
537
|
+
name = name.to_s.chomp("=").to_sym if name.end_with?("=")
|
538
|
+
|
539
|
+
self.class.attributes.key?(name)
|
540
|
+
end
|
541
|
+
|
939
542
|
def validate_attribute!(attr_name)
|
940
543
|
attr = self.class.attributes[attr_name]
|
941
544
|
value = instance_variable_get(:"@#{attr_name}")
|
@@ -966,20 +569,42 @@ module Lutaml
|
|
966
569
|
self.class.as_yaml(self)
|
967
570
|
end
|
968
571
|
|
969
|
-
|
970
|
-
define_method(:"to_#{format}") do |options = {}|
|
971
|
-
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
972
|
-
raise Lutaml::Model::NoRootMappingError.new(self.class) unless self.class.root?
|
572
|
+
private
|
973
573
|
|
974
|
-
|
975
|
-
|
976
|
-
else
|
977
|
-
self.class.hash_representation(self, format,
|
978
|
-
options)
|
979
|
-
end
|
574
|
+
def set_ordering(attrs)
|
575
|
+
return unless attrs.respond_to?(:ordered?)
|
980
576
|
|
981
|
-
|
982
|
-
|
577
|
+
@ordered = attrs.ordered?
|
578
|
+
@element_order = attrs.item_order
|
579
|
+
end
|
580
|
+
|
581
|
+
def set_schema_location(attrs)
|
582
|
+
return unless attrs.key?(:schema_location)
|
583
|
+
|
584
|
+
self.schema_location = attrs[:schema_location]
|
585
|
+
end
|
586
|
+
|
587
|
+
def initialize_attributes(attrs, options = {})
|
588
|
+
self.class.attributes.each do |name, attr|
|
589
|
+
next if attr.derived?
|
590
|
+
|
591
|
+
value = determine_value(attrs, name, attr)
|
592
|
+
|
593
|
+
default = using_default?(name)
|
594
|
+
value = self.class.apply_value_map(value, value_map(options), attr)
|
595
|
+
public_send(:"#{name}=", self.class.ensure_utf8(value))
|
596
|
+
using_default_for(name) if default
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
def determine_value(attrs, name, attr)
|
601
|
+
if attrs.key?(name) || attrs.key?(name.to_s)
|
602
|
+
attr_value(attrs, name, attr)
|
603
|
+
elsif attr.default_set?
|
604
|
+
using_default_for(name)
|
605
|
+
attr.default
|
606
|
+
else
|
607
|
+
Lutaml::Model::UninitializedClass.instance
|
983
608
|
end
|
984
609
|
end
|
985
610
|
end
|