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
@@ -0,0 +1,54 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
class Logger
|
4
|
+
def self.warn(message)
|
5
|
+
new.call(message, :warn)
|
6
|
+
end
|
7
|
+
|
8
|
+
# @param [String] old: The name of the deprecated class or method
|
9
|
+
# @param [String] replacement: The name of the replacement class or method
|
10
|
+
#
|
11
|
+
# Outputs a warning message that
|
12
|
+
# Usage of `old` name is deprecated will be removed in the next major
|
13
|
+
# release. Please use the `replacement`` instead.
|
14
|
+
def self.warn_future_deprication(old:, replacement:)
|
15
|
+
warn("Usage of `#{old}` is deprecated and will be removed in the next major release. Please use `#{replacement}` instead.")
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [String] name
|
19
|
+
# @param [String] caller_file
|
20
|
+
# @param [Integer] caller_line
|
21
|
+
#
|
22
|
+
# Outputs a warning message that
|
23
|
+
# `<name>` is handled by default. No need to explicitly
|
24
|
+
# define at `<caller_file>:<caller_line>`.
|
25
|
+
def self.warn_auto_handling(name:, caller_file:, caller_line:)
|
26
|
+
warn("`#{name}` is handled by default. No need to explecitly define at `#{caller_file}:#{caller_line}`")
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(message, type)
|
30
|
+
Warning.warn format_message(message, type)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def colorize(message, type)
|
36
|
+
type_color = {
|
37
|
+
error: 31, # Red: 31
|
38
|
+
success: 32, # Green: 32
|
39
|
+
warn: 33, # Yellow: 33
|
40
|
+
}
|
41
|
+
|
42
|
+
io = type == :warn ? $stderr : $stdout
|
43
|
+
return message unless io.tty?
|
44
|
+
|
45
|
+
color = type_color[type]
|
46
|
+
"\e[#{color}m#{message}\e[0m"
|
47
|
+
end
|
48
|
+
|
49
|
+
def format_message(message, type)
|
50
|
+
colorize("\n[Lutaml::Model] #{type.upcase}: #{message}\n", type)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
class Transformer
|
4
|
+
class << self
|
5
|
+
def call(value, rule, attribute)
|
6
|
+
new(rule, attribute).call(value)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :rule, :attribute
|
11
|
+
|
12
|
+
def initialize(rule, attribute)
|
13
|
+
@rule = rule
|
14
|
+
@attribute = attribute
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(value)
|
18
|
+
transformation_methods.reduce(value) do |transformed_value, method|
|
19
|
+
method.call(transformed_value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ImportTransformer < Transformer
|
25
|
+
# Precedene of transformations:
|
26
|
+
# 1. Rule transform
|
27
|
+
# 2. Attribute transform
|
28
|
+
def transformation_methods
|
29
|
+
[
|
30
|
+
rule.transform[:import],
|
31
|
+
attribute&.transform&.[](:import),
|
32
|
+
].compact
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ExportTransformer < Transformer
|
37
|
+
# Precedene of transformations (reverse order):
|
38
|
+
# 1. Attribute transform
|
39
|
+
# 2. Rule transform
|
40
|
+
def transformation_methods
|
41
|
+
[
|
42
|
+
attribute&.transform&.[](:export),
|
43
|
+
rule.transform[:export],
|
44
|
+
].compact
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "../mapping/key_value_mapping"
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Toml
|
6
|
+
class Mapping < Lutaml::Model::KeyValueMapping
|
7
|
+
def initialize
|
8
|
+
super(:toml)
|
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
|
+
|
17
|
+
def validate!(key, to, with, render_nil, render_empty)
|
18
|
+
super
|
19
|
+
|
20
|
+
if [true, :as_nil].include?(render_nil) || render_empty == :as_nil
|
21
|
+
raise IncorrectMappingArgumentsError, "nil values are not supported in toml format"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "toml-rb"
|
2
|
-
require_relative "
|
2
|
+
require_relative "document"
|
3
3
|
|
4
4
|
module Lutaml
|
5
5
|
module Model
|
6
|
-
module
|
7
|
-
class TomlRbAdapter <
|
6
|
+
module Toml
|
7
|
+
class TomlRbAdapter < Document
|
8
8
|
def self.parse(toml, _options = {})
|
9
9
|
TomlRB.parse(toml)
|
10
10
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "tomlib"
|
2
|
+
require_relative "document"
|
3
|
+
|
4
|
+
module Lutaml
|
5
|
+
module Model
|
6
|
+
module Toml
|
7
|
+
class TomlibAdapter < Document
|
8
|
+
def self.parse(toml, _options = {})
|
9
|
+
Tomlib.load(toml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_toml(*)
|
13
|
+
Tomlib.dump(to_h)
|
14
|
+
# Tomlib::Generator.new(to_h).toml_str
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Toml
|
6
|
+
def self.detect_toml_adapter
|
7
|
+
return :tomlib if Object.const_defined?(:Tomlib)
|
8
|
+
return :toml_rb if Object.const_defined?(:TomlRb)
|
9
|
+
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require_relative "toml/document"
|
17
|
+
require_relative "toml/mapping"
|
18
|
+
require_relative "toml/mapping_rule"
|
19
|
+
require_relative "toml/transform"
|
20
|
+
|
21
|
+
Lutaml::Model::FormatRegistry.register(
|
22
|
+
:toml,
|
23
|
+
mapping_class: Lutaml::Model::Toml::Mapping,
|
24
|
+
adapter_class: nil,
|
25
|
+
transformer: Lutaml::Model::Toml::Transform,
|
26
|
+
)
|
27
|
+
|
28
|
+
if (adapter = Lutaml::Model::Toml.detect_toml_adapter)
|
29
|
+
Lutaml::Model::Config.toml_adapter_type = adapter
|
30
|
+
end
|
@@ -0,0 +1,291 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
class KeyValueTransform < Lutaml::Model::Transform
|
4
|
+
def data_to_model(data, format, options = {})
|
5
|
+
instance = model_class.new
|
6
|
+
mappings = extract_mappings(options, format)
|
7
|
+
|
8
|
+
mappings.each do |rule|
|
9
|
+
process_mapping_rule(data, instance, format, rule, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def model_to_data(instance, format, options = {})
|
16
|
+
mappings = mappings_for(format).mappings
|
17
|
+
|
18
|
+
mappings.each_with_object({}) do |rule, hash|
|
19
|
+
next unless valid_mapping?(rule, options)
|
20
|
+
next handle_delegate(instance, rule, hash, format) if rule.delegate
|
21
|
+
|
22
|
+
process_mapping_for_instance(instance, hash, format, rule, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def process_mapping_for_instance(instance, hash, format, rule, options)
|
29
|
+
if rule.custom_methods[:to]
|
30
|
+
return instance.send(rule.custom_methods[:to], instance, hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
attribute = attributes[rule.to]
|
34
|
+
value = rule.serialize(instance)
|
35
|
+
|
36
|
+
return handle_raw_mapping(hash, value, format, options) if rule.raw_mapping?
|
37
|
+
return handle_root_mappings(hash, value, format, rule, attribute) if rule.root_mapping?
|
38
|
+
|
39
|
+
value = ExportTransformer.call(value, rule, attribute)
|
40
|
+
|
41
|
+
value = serialize_value(value, rule, attribute, format, options)
|
42
|
+
|
43
|
+
return unless rule.render?(value, instance)
|
44
|
+
|
45
|
+
value = apply_value_map(value, rule.value_map(:to, options), attribute)
|
46
|
+
|
47
|
+
hash[rule_from_name(rule)] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
def valid_mapping?(rule, options)
|
51
|
+
only = options[:only]
|
52
|
+
except = options[:except]
|
53
|
+
name = rule.to
|
54
|
+
|
55
|
+
(except.nil? || !except.include?(name)) &&
|
56
|
+
(only.nil? || only.include?(name))
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_raw_mapping(hash, value, format, options)
|
60
|
+
result = Lutaml::Model::Config.adapter_for(format).parse(value, options)
|
61
|
+
|
62
|
+
hash.merge!(result)
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_root_mappings(hash, value, format, rule, attr)
|
66
|
+
hash.merge!(
|
67
|
+
generate_hash_from_child_mappings(
|
68
|
+
attr,
|
69
|
+
value,
|
70
|
+
format,
|
71
|
+
rule.root_mappings,
|
72
|
+
),
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def serialize_value(value, rule, attr, format, options)
|
77
|
+
return attr.serialize(value, format, options) unless rule.child_mappings
|
78
|
+
|
79
|
+
generate_hash_from_child_mappings(attr, value, format, rule.child_mappings)
|
80
|
+
end
|
81
|
+
|
82
|
+
def rule_from_name(rule)
|
83
|
+
rule.multiple_mappings? ? rule.from.first.to_s : rule.from.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def generate_hash_from_child_mappings(attr, value, format, child_mappings)
|
87
|
+
return value unless child_mappings
|
88
|
+
|
89
|
+
hash = {}
|
90
|
+
|
91
|
+
generate_remaining_mappings_for_value(child_mappings, value, format)
|
92
|
+
|
93
|
+
value.each do |child_obj|
|
94
|
+
rules = attr.type.mappings_for(format)
|
95
|
+
|
96
|
+
hash.merge!(
|
97
|
+
extract_hash_for_child_mapping(child_mappings, child_obj, rules),
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
hash
|
102
|
+
end
|
103
|
+
|
104
|
+
# Generates remaining child mappings for all attributes when only
|
105
|
+
# the :key mapping (e.g., { name: :key }) is provided.
|
106
|
+
# If any additional mappings (e.g., { name: :key, id: :identifier })
|
107
|
+
# are specified, no additional child mappings will be generated.
|
108
|
+
def generate_remaining_mappings_for_value(child_mappings, value, format)
|
109
|
+
return if child_mappings.values != [:key]
|
110
|
+
|
111
|
+
klass = value.first.class
|
112
|
+
mappings = klass.mappings_for(format)
|
113
|
+
|
114
|
+
klass.attributes.each_key do |name|
|
115
|
+
next if Utils.string_or_symbol_key?(child_mappings, name)
|
116
|
+
|
117
|
+
child_mappings[name.to_sym] = child_mapping_for(name, mappings)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def child_mapping_for(name, mappings)
|
122
|
+
mappings.find_by_to(name)&.name.to_s || name.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
def extract_hash_for_child_mapping(child_mappings, child_obj, rules)
|
126
|
+
key = nil
|
127
|
+
value = {}
|
128
|
+
|
129
|
+
child_mappings.each do |attr_name, path|
|
130
|
+
rule = rules.find_by_to(attr_name)
|
131
|
+
|
132
|
+
attr_value = normalize_attribute_value(child_obj.send(attr_name))
|
133
|
+
|
134
|
+
next unless rule&.render?(attr_value, nil)
|
135
|
+
next key = attr_value if path == :key
|
136
|
+
|
137
|
+
value = extract_hash_value_for_child_mapping(path, attr_value, value)
|
138
|
+
end
|
139
|
+
|
140
|
+
value = nil if value.empty?
|
141
|
+
{ key => value }
|
142
|
+
end
|
143
|
+
|
144
|
+
def normalize_attribute_value(value)
|
145
|
+
if value.is_a?(Lutaml::Model::Serialize)
|
146
|
+
value.to_hash
|
147
|
+
elsif value.is_a?(Array) && value.first.is_a?(Lutaml::Model::Serialize)
|
148
|
+
value.map(&:to_hash)
|
149
|
+
else
|
150
|
+
value
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def extract_hash_value_for_child_mapping(path, value, map_value)
|
155
|
+
return value if path == :value
|
156
|
+
|
157
|
+
path = [path] unless path.is_a?(Array)
|
158
|
+
path[0...-1].inject(map_value) do |acc, k|
|
159
|
+
acc[k.to_s] ||= {}
|
160
|
+
end.public_send(:[]=, path.last.to_s, value)
|
161
|
+
|
162
|
+
map_value
|
163
|
+
end
|
164
|
+
|
165
|
+
def handle_delegate(instance, rule, hash, format)
|
166
|
+
value = extract_value_for_delegate(instance, rule)
|
167
|
+
return if value.nil? && !rule.render_nil
|
168
|
+
|
169
|
+
attribute = instance.send(rule.delegate).class.attributes[rule.to]
|
170
|
+
hash[rule_from_name(rule)] = attribute.serialize(value, format)
|
171
|
+
end
|
172
|
+
|
173
|
+
def extract_value_for_delegate(instance, rule)
|
174
|
+
instance.send(rule.delegate).send(rule.to)
|
175
|
+
end
|
176
|
+
|
177
|
+
def extract_mappings(options, format)
|
178
|
+
options[:mappings] || mappings_for(format).mappings
|
179
|
+
end
|
180
|
+
|
181
|
+
def process_mapping_rule(doc, instance, format, rule, options = {})
|
182
|
+
raise "Attribute '#{rule.to}' not found in #{self}" unless valid_rule?(rule)
|
183
|
+
|
184
|
+
attr = attribute_for_rule(rule)
|
185
|
+
return if attr&.derived?
|
186
|
+
|
187
|
+
value = extract_rule_value(doc, rule, format, attr)
|
188
|
+
value = apply_value_map(value, rule.value_map(:from, options), attr)
|
189
|
+
|
190
|
+
return process_custom_method(rule, instance, value) if rule.has_custom_method_for_deserialization?
|
191
|
+
|
192
|
+
value = translate_mappings(value, rule.hash_mappings, attr, format)
|
193
|
+
value = cast_value(value, attr, format, rule) unless rule.hash_mappings
|
194
|
+
|
195
|
+
attr.valid_collection!(value, context)
|
196
|
+
rule.deserialize(instance, value, attributes, self)
|
197
|
+
end
|
198
|
+
|
199
|
+
def extract_rule_value(doc, rule, format, attr)
|
200
|
+
rule_names = rule.multiple_mappings? ? rule.name : [rule.name]
|
201
|
+
|
202
|
+
rule_names.each do |rule_name|
|
203
|
+
value = rule_value_for(rule_name, doc, rule, format, attr)
|
204
|
+
|
205
|
+
return value if Utils.initialized?(value)
|
206
|
+
end
|
207
|
+
|
208
|
+
Lutaml::Model::UninitializedClass.instance
|
209
|
+
end
|
210
|
+
|
211
|
+
def rule_value_for(name, doc, rule, format, attr)
|
212
|
+
if rule.root_mapping?
|
213
|
+
doc
|
214
|
+
elsif rule.raw_mapping?
|
215
|
+
convert_to_format(doc, format)
|
216
|
+
elsif Utils.string_or_symbol_key?(doc, name)
|
217
|
+
Utils.fetch_with_string_or_symbol_key(doc, name)
|
218
|
+
elsif attr&.default_set?
|
219
|
+
attr.default
|
220
|
+
else
|
221
|
+
Lutaml::Model::UninitializedClass.instance
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def convert_to_format(doc, format)
|
226
|
+
adapter = Lutaml::Model::Config.adapter_for(format)
|
227
|
+
adapter.new(doc).public_send(:"to_#{format}")
|
228
|
+
end
|
229
|
+
|
230
|
+
def process_custom_method(rule, instance, value)
|
231
|
+
return unless Utils.present?(value)
|
232
|
+
|
233
|
+
model_class.new.send(rule.custom_methods[:from], instance, value)
|
234
|
+
end
|
235
|
+
|
236
|
+
def cast_value(value, attr, format, rule)
|
237
|
+
cast_options = rule.polymorphic ? { polymorphic: rule.polymorphic } : {}
|
238
|
+
attr.cast(value, format, cast_options)
|
239
|
+
end
|
240
|
+
|
241
|
+
def translate_mappings(hash, child_mappings, attr, format)
|
242
|
+
return hash unless child_mappings
|
243
|
+
|
244
|
+
hash.map do |key, value|
|
245
|
+
process_child_mapping(key, value, child_mappings, attr, format, hash)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def process_child_mapping(key, value, child_mappings, attr, format, hash)
|
250
|
+
child_hash = build_child_hash(key, value, child_mappings, attr, format)
|
251
|
+
|
252
|
+
if only_keys_mapped?(child_mappings, hash)
|
253
|
+
child_hash.merge!(value)
|
254
|
+
end
|
255
|
+
|
256
|
+
map_child_data(child_hash, attr, format)
|
257
|
+
end
|
258
|
+
|
259
|
+
def build_child_hash(key, value, child_mappings, attr, format)
|
260
|
+
child_mappings.to_h do |attr_name, path|
|
261
|
+
attr_value = extract_attr_value(path, key, value)
|
262
|
+
attr_rule = attr.type.mappings_for(format).find_by_to(attr_name)
|
263
|
+
[attr_rule.from.to_s, attr_value]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def extract_attr_value(path, key, value)
|
268
|
+
case path
|
269
|
+
when :key then key
|
270
|
+
when :value then value
|
271
|
+
else
|
272
|
+
path = Array(path)
|
273
|
+
value.dig(*path.map(&:to_s))
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def only_keys_mapped?(child_mappings, hash)
|
278
|
+
child_mappings.values == [:key] && hash.values.all?(Hash)
|
279
|
+
end
|
280
|
+
|
281
|
+
def map_child_data(child_hash, attr, format)
|
282
|
+
self.class.data_to_model(
|
283
|
+
attr.type,
|
284
|
+
child_hash,
|
285
|
+
format,
|
286
|
+
{ mappings: attr.type.mappings_for(format).mappings },
|
287
|
+
)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|