lutaml-model 0.3.6 → 0.3.8
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_todo.yml +14 -12
- data/README.adoc +30 -26
- data/lib/lutaml/model/attribute.rb +27 -0
- data/lib/lutaml/model/serialize.rb +100 -127
- data/lib/lutaml/model/type.rb +2 -0
- data/lib/lutaml/model/utils.rb +45 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/nokogiri.rb +73 -0
- data/lib/lutaml/model/xml_adapter/builder/ox.rb +89 -0
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +19 -92
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +22 -94
- data/lib/lutaml/model/xml_adapter/xml_document.rb +111 -7
- data/lib/lutaml/model/yaml_adapter/standard_yaml_adapter.rb +0 -12
- data/lib/lutaml/model.rb +1 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30487a24277470ff7b3d12193e46262b0fc1cac85461224ed98749c8b6de5104
|
4
|
+
data.tar.gz: a161a8e5f83a10ec5db5b77a0d5a0abe72b629d0900a4ab040414c2a02c22725
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a805f81f93bc0dcb983d83e7f7fc870989f84fb25434de7edee18269c1b96b8572516132e17e3db2e188075e985cb8219ec84257fd380c7abfe4b65b32116af
|
7
|
+
data.tar.gz: 0243f89d6fb6c5466e29500e810a077096e260b51d53a8a23db7918c7b2d57dc30a9757dd00814a2c497dd552e39bd17e92729c509670dde555a0b508a77013b
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2024-08-
|
3
|
+
# on 2024-08-27 06:48:03 UTC using RuboCop version 1.65.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -14,7 +14,7 @@ Gemspec/RequireMFA:
|
|
14
14
|
Exclude:
|
15
15
|
- 'lutaml-model.gemspec'
|
16
16
|
|
17
|
-
# Offense count:
|
17
|
+
# Offense count: 57
|
18
18
|
# This cop supports safe autocorrection (--autocorrect).
|
19
19
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
|
20
20
|
# URISchemes: http, https
|
@@ -24,6 +24,7 @@ Layout/LineLength:
|
|
24
24
|
- 'lib/lutaml/model/comparable_model.rb'
|
25
25
|
- 'lib/lutaml/model/serialize.rb'
|
26
26
|
- 'lib/lutaml/model/type.rb'
|
27
|
+
- 'lib/lutaml/model/utils.rb'
|
27
28
|
- 'lib/lutaml/model/xml_adapter/nokogiri_adapter.rb'
|
28
29
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
29
30
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
@@ -43,7 +44,7 @@ Lint/ConstantDefinitionInBlock:
|
|
43
44
|
- 'spec/lutaml/model/schema/xsd_schema_spec.rb'
|
44
45
|
- 'spec/lutaml/model/schema/yaml_schema_spec.rb'
|
45
46
|
|
46
|
-
# Offense count:
|
47
|
+
# Offense count: 28
|
47
48
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
48
49
|
Metrics/AbcSize:
|
49
50
|
Exclude:
|
@@ -56,16 +57,17 @@ Metrics/AbcSize:
|
|
56
57
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
57
58
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
58
59
|
|
59
|
-
# Offense count:
|
60
|
+
# Offense count: 5
|
60
61
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
61
62
|
# AllowedMethods: refine
|
62
63
|
Metrics/BlockLength:
|
63
|
-
Max:
|
64
|
+
Max: 43
|
64
65
|
|
65
|
-
# Offense count:
|
66
|
+
# Offense count: 22
|
66
67
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
67
68
|
Metrics/CyclomaticComplexity:
|
68
69
|
Exclude:
|
70
|
+
- 'lib/lutaml/model/attribute.rb'
|
69
71
|
- 'lib/lutaml/model/comparable_model.rb'
|
70
72
|
- 'lib/lutaml/model/serialize.rb'
|
71
73
|
- 'lib/lutaml/model/type.rb'
|
@@ -73,23 +75,23 @@ Metrics/CyclomaticComplexity:
|
|
73
75
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
74
76
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
75
77
|
|
76
|
-
# Offense count:
|
78
|
+
# Offense count: 36
|
77
79
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
78
80
|
Metrics/MethodLength:
|
79
|
-
Max:
|
81
|
+
Max: 43
|
80
82
|
|
81
83
|
# Offense count: 4
|
82
84
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
83
85
|
Metrics/ParameterLists:
|
84
86
|
Max: 9
|
85
87
|
|
86
|
-
# Offense count:
|
88
|
+
# Offense count: 18
|
87
89
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
88
90
|
Metrics/PerceivedComplexity:
|
89
91
|
Exclude:
|
92
|
+
- 'lib/lutaml/model/attribute.rb'
|
90
93
|
- 'lib/lutaml/model/comparable_model.rb'
|
91
94
|
- 'lib/lutaml/model/serialize.rb'
|
92
|
-
- 'lib/lutaml/model/type.rb'
|
93
95
|
- 'lib/lutaml/model/xml_adapter/nokogiri_adapter.rb'
|
94
96
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
95
97
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
@@ -103,7 +105,7 @@ RSpec/ContextWording:
|
|
103
105
|
- 'spec/lutaml/model/xml_adapter/oga_adapter_spec.rb'
|
104
106
|
- 'spec/lutaml/model/xml_adapter/ox_adapter_spec.rb'
|
105
107
|
|
106
|
-
# Offense count:
|
108
|
+
# Offense count: 76
|
107
109
|
# Configuration parameters: CountAsOne.
|
108
110
|
RSpec/ExampleLength:
|
109
111
|
Max: 57
|
@@ -132,7 +134,7 @@ RSpec/MultipleDescribes:
|
|
132
134
|
|
133
135
|
# Offense count: 70
|
134
136
|
RSpec/MultipleExpectations:
|
135
|
-
Max:
|
137
|
+
Max: 10
|
136
138
|
|
137
139
|
# Offense count: 11
|
138
140
|
# Configuration parameters: AllowSubject.
|
data/README.adoc
CHANGED
@@ -1338,11 +1338,11 @@ class CustomCeramic < Lutaml::Model::Serializable
|
|
1338
1338
|
end
|
1339
1339
|
|
1340
1340
|
def name_to_json(model, value)
|
1341
|
-
"Masterpiece: #{value}"
|
1341
|
+
doc["name"] = "Masterpiece: #{value}"
|
1342
1342
|
end
|
1343
1343
|
|
1344
1344
|
def name_from_json(model, doc)
|
1345
|
-
|
1345
|
+
model.name = value.sub(/^JSON Masterpiece: /, '')
|
1346
1346
|
end
|
1347
1347
|
end
|
1348
1348
|
----
|
@@ -1971,52 +1971,56 @@ class Example < Lutaml::Model::Serializable
|
|
1971
1971
|
from: :description_from_xml }
|
1972
1972
|
end
|
1973
1973
|
|
1974
|
-
def name_to_json(
|
1975
|
-
"JSON Masterpiece: #{
|
1974
|
+
def name_to_json(model, doc)
|
1975
|
+
doc["name"] = "JSON Masterpiece: #{model.name}"
|
1976
1976
|
end
|
1977
1977
|
|
1978
|
-
def name_from_json(
|
1979
|
-
|
1978
|
+
def name_from_json(model, value)
|
1979
|
+
model.name = value.sub(/^JSON Masterpiece: /, "")
|
1980
1980
|
end
|
1981
1981
|
|
1982
|
-
def color_to_json(
|
1983
|
-
|
1982
|
+
def color_to_json(model, doc)
|
1983
|
+
doc["color"] = model.color.upcase
|
1984
1984
|
end
|
1985
1985
|
|
1986
|
-
def color_from_json(
|
1987
|
-
|
1986
|
+
def color_from_json(model, value)
|
1987
|
+
model.color = value.downcase
|
1988
1988
|
end
|
1989
1989
|
|
1990
|
-
def description_to_json(
|
1991
|
-
"JSON Description: #{
|
1990
|
+
def description_to_json(model, doc)
|
1991
|
+
doc["description"] = "JSON Description: #{model.description}"
|
1992
1992
|
end
|
1993
1993
|
|
1994
|
-
def description_from_json(
|
1995
|
-
|
1994
|
+
def description_from_json(model, value)
|
1995
|
+
model.description = value.sub(/^JSON Description: /, "")
|
1996
1996
|
end
|
1997
1997
|
|
1998
|
-
def name_to_xml(
|
1999
|
-
|
1998
|
+
def name_to_xml(model, parent, doc)
|
1999
|
+
el = doc.create_element("Name")
|
2000
|
+
doc.add_text(el, "XML Masterpiece: #{model.name}")
|
2001
|
+
doc.add_element(parent, el)
|
2000
2002
|
end
|
2001
2003
|
|
2002
|
-
def name_from_xml(
|
2003
|
-
value.sub(/^XML Masterpiece: /, "")
|
2004
|
+
def name_from_xml(model, value)
|
2005
|
+
model.name = value.sub(/^XML Masterpiece: /, "")
|
2004
2006
|
end
|
2005
2007
|
|
2006
|
-
def color_to_xml(
|
2007
|
-
|
2008
|
+
def color_to_xml(model, parent, doc)
|
2009
|
+
color_element = doc.create_element("Color")
|
2010
|
+
doc.add_text(color_element, model.color.upcase)
|
2011
|
+
doc.add_element(parent, color_element)
|
2008
2012
|
end
|
2009
2013
|
|
2010
|
-
def color_from_xml(
|
2011
|
-
value.downcase
|
2014
|
+
def color_from_xml(model, value)
|
2015
|
+
model.color = value.downcase
|
2012
2016
|
end
|
2013
2017
|
|
2014
|
-
def description_to_xml(
|
2015
|
-
"XML Description: #{
|
2018
|
+
def description_to_xml(model, parent, doc)
|
2019
|
+
doc.add_text(parent, "XML Description: #{model.description}")
|
2016
2020
|
end
|
2017
2021
|
|
2018
|
-
def description_from_xml(
|
2019
|
-
value.sub(/^XML Description: /, "")
|
2022
|
+
def description_from_xml(model, value)
|
2023
|
+
model.description = value.join.strip.sub(/^XML Description: /, "")
|
2020
2024
|
end
|
2021
2025
|
end
|
2022
2026
|
----
|
@@ -40,6 +40,33 @@ module Lutaml
|
|
40
40
|
def render_nil?
|
41
41
|
options.fetch(:render_nil, false)
|
42
42
|
end
|
43
|
+
|
44
|
+
def serialize(value, format, options = {})
|
45
|
+
if value.is_a?(Array)
|
46
|
+
value.map do |v|
|
47
|
+
serialize(v, format, options)
|
48
|
+
end
|
49
|
+
elsif type <= Serialize
|
50
|
+
type.hash_representation(value, format, options)
|
51
|
+
else
|
52
|
+
type.serialize(value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cast(value, format, options = {})
|
57
|
+
value ||= [] if collection?
|
58
|
+
instance = options[:instance]
|
59
|
+
|
60
|
+
if value.is_a?(Array)
|
61
|
+
value.map do |v|
|
62
|
+
cast(v, format, instance: instance)
|
63
|
+
end
|
64
|
+
elsif type <= Serialize && value.is_a?(Hash)
|
65
|
+
type.apply_mappings(value, format, options)
|
66
|
+
else
|
67
|
+
Lutaml::Model::Type.cast(value, type)
|
68
|
+
end
|
69
|
+
end
|
43
70
|
end
|
44
71
|
end
|
45
72
|
end
|
@@ -84,29 +84,47 @@ module Lutaml
|
|
84
84
|
|
85
85
|
define_method(:"from_#{format}") do |data|
|
86
86
|
adapter = Lutaml::Model::Config.send(:"#{format}_adapter")
|
87
|
+
|
87
88
|
doc = adapter.parse(data)
|
88
|
-
|
89
|
-
# apply_content_mapping(doc, mapped_attrs) if format == :xml
|
90
|
-
generate_model_object(self, mapped_attrs)
|
89
|
+
public_send(:"of_#{format}", doc.to_h)
|
91
90
|
end
|
92
91
|
|
93
|
-
define_method(:"
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
define_method(:"of_#{format}") do |hash|
|
93
|
+
if hash.is_a?(Array)
|
94
|
+
return hash.map do |item|
|
95
|
+
apply_mappings(item, format)
|
96
|
+
end
|
97
97
|
end
|
98
98
|
|
99
|
+
apply_mappings(hash, format)
|
100
|
+
end
|
101
|
+
|
102
|
+
define_method(:"to_#{format}") do |instance|
|
103
|
+
value = public_send(:"as_#{format}", instance)
|
99
104
|
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
100
105
|
|
101
106
|
if format == :xml
|
102
107
|
xml_options = { mapper_class: self }
|
103
|
-
|
104
|
-
adapter.new(instance).public_send(:"to_#{format}", xml_options)
|
108
|
+
adapter.new(value).public_send(:"to_#{format}", xml_options)
|
105
109
|
else
|
106
|
-
|
107
|
-
adapter.new(hash).public_send(:"to_#{format}")
|
110
|
+
adapter.new(value).public_send(:"to_#{format}")
|
108
111
|
end
|
109
112
|
end
|
113
|
+
|
114
|
+
define_method(:"as_#{format}") do |instance|
|
115
|
+
if instance.is_a?(Array)
|
116
|
+
return instance.map { |item| public_send(:"as_#{format}", item) }
|
117
|
+
end
|
118
|
+
|
119
|
+
unless instance.is_a?(model)
|
120
|
+
msg = "argument is a '#{instance.class}' but should be a '#{model}'"
|
121
|
+
raise Lutaml::Model::IncorrectModelError, msg
|
122
|
+
end
|
123
|
+
|
124
|
+
return instance if format == :xml
|
125
|
+
|
126
|
+
hash_representation(instance, format)
|
127
|
+
end
|
110
128
|
end
|
111
129
|
|
112
130
|
def hash_representation(instance, format, options = {})
|
@@ -118,13 +136,13 @@ module Lutaml
|
|
118
136
|
name = rule.to
|
119
137
|
next if except&.include?(name) || (only && !only.include?(name))
|
120
138
|
|
121
|
-
next handle_delegate(instance, rule, hash) if rule.delegate
|
139
|
+
next handle_delegate(instance, rule, hash, format) if rule.delegate
|
122
140
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
141
|
+
if rule.custom_methods[:to]
|
142
|
+
next instance.send(rule.custom_methods[:to], instance, hash)
|
143
|
+
end
|
144
|
+
|
145
|
+
value = instance.send(name)
|
128
146
|
|
129
147
|
next if value.nil? && !rule.render_nil
|
130
148
|
|
@@ -132,68 +150,27 @@ module Lutaml
|
|
132
150
|
|
133
151
|
hash[rule.from] = if rule.child_mappings
|
134
152
|
generate_hash_from_child_mappings(value, rule.child_mappings)
|
135
|
-
elsif value.is_a?(Array)
|
136
|
-
value.map do |v|
|
137
|
-
if attribute.type <= Serialize
|
138
|
-
attribute.type.hash_representation(v, format, options)
|
139
|
-
else
|
140
|
-
attribute.type.serialize(v)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
elsif attribute.type <= Serialize
|
144
|
-
attribute.type.hash_representation(value, format, options)
|
145
153
|
else
|
146
|
-
attribute.
|
154
|
+
attribute.serialize(value, format, options)
|
147
155
|
end
|
148
156
|
end
|
149
157
|
end
|
150
158
|
|
151
|
-
def handle_delegate(instance, rule, hash)
|
159
|
+
def handle_delegate(instance, rule, hash, format)
|
152
160
|
name = rule.to
|
153
161
|
value = instance.send(rule.delegate).send(name)
|
154
162
|
return if value.nil? && !rule.render_nil
|
155
163
|
|
156
164
|
attribute = instance.send(rule.delegate).class.attributes[name]
|
157
|
-
hash[rule.from] =
|
158
|
-
when Array
|
159
|
-
value.map do |v|
|
160
|
-
if v.is_a?(Serialize)
|
161
|
-
hash_representation(v, format, options)
|
162
|
-
else
|
163
|
-
attribute.type.serialize(v)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
else
|
167
|
-
if value.is_a?(Serialize)
|
168
|
-
hash_representation(value, format, options)
|
169
|
-
else
|
170
|
-
attribute.type.serialize(value)
|
171
|
-
end
|
172
|
-
end
|
165
|
+
hash[rule.from] = attribute.serialize(value, format)
|
173
166
|
end
|
174
167
|
|
175
168
|
def mappings_for(format)
|
176
169
|
mappings[format] || default_mappings(format)
|
177
170
|
end
|
178
171
|
|
179
|
-
def generate_model_object(type, mapped_attrs)
|
180
|
-
return type.model.new(mapped_attrs) if self == model
|
181
|
-
|
182
|
-
instance = type.model.new
|
183
|
-
|
184
|
-
type.attributes.each do |name, attr|
|
185
|
-
value = attr_value(mapped_attrs, name, attr)
|
186
|
-
|
187
|
-
instance.send(:"#{name}=", ensure_utf8(value))
|
188
|
-
end
|
189
|
-
|
190
|
-
instance
|
191
|
-
end
|
192
|
-
|
193
172
|
def attr_value(attrs, name, attr_rule)
|
194
|
-
value = if attrs.key?(name)
|
195
|
-
attrs[name]
|
196
|
-
elsif attrs.key?(name.to_sym)
|
173
|
+
value = if attrs.key?(name.to_sym)
|
197
174
|
attrs[name.to_sym]
|
198
175
|
elsif attrs.key?(name.to_s)
|
199
176
|
attrs[name.to_s]
|
@@ -211,8 +188,6 @@ module Lutaml
|
|
211
188
|
Lutaml::Model::Type.cast(v, attr_rule.type)
|
212
189
|
end
|
213
190
|
end
|
214
|
-
elsif value.is_a?(Hash) && attr_rule.type != Lutaml::Model::Type::Hash
|
215
|
-
generate_model_object(attr_rule.type, value)
|
216
191
|
else
|
217
192
|
# TODO: This code is problematic because Type.cast does not know
|
218
193
|
# about all the types.
|
@@ -279,11 +254,13 @@ module Lutaml
|
|
279
254
|
hash
|
280
255
|
end
|
281
256
|
|
282
|
-
def apply_mappings(doc, format)
|
283
|
-
|
257
|
+
def apply_mappings(doc, format, options = {})
|
258
|
+
instance = options[:instance] || model.new
|
259
|
+
return instance if !doc || doc.empty?
|
260
|
+
return apply_xml_mapping(doc, instance, options) if format == :xml
|
284
261
|
|
285
262
|
mappings = mappings_for(format).mappings
|
286
|
-
mappings.
|
263
|
+
mappings.each do |rule|
|
287
264
|
attr = if rule.delegate
|
288
265
|
attributes[rule.delegate].type.attributes[rule.to]
|
289
266
|
else
|
@@ -292,106 +269,96 @@ module Lutaml
|
|
292
269
|
|
293
270
|
raise "Attribute '#{rule.to}' not found in #{self}" unless attr
|
294
271
|
|
295
|
-
value = if rule.
|
296
|
-
new.send(rule.custom_methods[:from], hash, doc)
|
297
|
-
elsif doc.key?(rule.name) || doc.key?(rule.name.to_sym)
|
272
|
+
value = if doc.key?(rule.name) || doc.key?(rule.name.to_sym)
|
298
273
|
doc[rule.name] || doc[rule.name.to_sym]
|
299
274
|
else
|
300
275
|
attr.default
|
301
276
|
end
|
302
277
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
value = (value || []).map do |v|
|
307
|
-
attr.type <= Serialize ? attr.type.apply_mappings(v, format) : v
|
308
|
-
end
|
309
|
-
elsif value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
|
310
|
-
value = attr.type.apply_mappings(value, format)
|
278
|
+
if rule.custom_methods[:from]
|
279
|
+
value = new.send(rule.custom_methods[:from], instance, value) if value && !value.empty?
|
280
|
+
next
|
311
281
|
end
|
312
282
|
|
283
|
+
value = apply_child_mappings(value, rule.child_mappings)
|
284
|
+
value = attr.cast(value, format)
|
285
|
+
|
313
286
|
if rule.delegate
|
314
|
-
|
315
|
-
|
287
|
+
if instance.public_send(rule.delegate).nil?
|
288
|
+
instance.public_send(:"#{rule.delegate}=",
|
289
|
+
attributes[rule.delegate].type.new)
|
290
|
+
end
|
291
|
+
instance.public_send(rule.delegate).public_send(:"#{rule.to}=",
|
292
|
+
value)
|
316
293
|
else
|
317
|
-
|
294
|
+
instance.public_send(:"#{rule.to}=", value)
|
318
295
|
end
|
319
296
|
end
|
297
|
+
|
298
|
+
instance
|
320
299
|
end
|
321
300
|
|
322
|
-
def apply_xml_mapping(doc,
|
323
|
-
return unless doc
|
301
|
+
def apply_xml_mapping(doc, instance, options = {})
|
302
|
+
return instance unless doc
|
324
303
|
|
325
304
|
mappings = mappings_for(:xml).mappings
|
326
305
|
|
327
306
|
if doc.is_a?(Array)
|
328
307
|
raise "May be `collection: true` is" \
|
329
|
-
"missing for #{self} in #{caller_class}"
|
308
|
+
"missing for #{self} in #{options[:caller_class]}"
|
330
309
|
end
|
331
310
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
mapping_from = []
|
311
|
+
if instance.respond_to?(:ordered=) && doc.is_a?(Lutaml::Model::MappingHash)
|
312
|
+
instance.element_order = doc.item_order
|
313
|
+
instance.ordered = mappings_for(:xml).mixed_content? || options[:mixed_content]
|
314
|
+
end
|
337
315
|
|
338
|
-
mappings.
|
316
|
+
mappings.each do |rule|
|
339
317
|
attr = attributes[rule.to]
|
340
318
|
raise "Attribute '#{rule.to}' not found in #{self}" unless attr
|
341
319
|
|
342
320
|
is_content_mapping = rule.name.nil?
|
321
|
+
|
343
322
|
value = if is_content_mapping
|
344
323
|
doc["text"]
|
345
324
|
else
|
346
325
|
doc[rule.name.to_s] || doc[rule.name.to_sym]
|
347
326
|
end
|
348
327
|
|
349
|
-
if attr.collection?
|
350
|
-
if value && !value.is_a?(Array)
|
351
|
-
value = [value]
|
352
|
-
end
|
328
|
+
value = [value].compact if attr.collection? && !value.is_a?(Array)
|
353
329
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
elsif v.is_a?(Hash)
|
358
|
-
v["text"]
|
359
|
-
else
|
360
|
-
v
|
361
|
-
end
|
330
|
+
if value.is_a?(Array)
|
331
|
+
value = value.map do |v|
|
332
|
+
v.is_a?(Hash) && !(attr.type <= Serialize) ? v["text"] : v
|
362
333
|
end
|
363
|
-
elsif attr.type <= Serialize
|
364
|
-
value =
|
365
|
-
else
|
366
|
-
if value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
|
367
|
-
value = value["text"]
|
368
|
-
end
|
369
|
-
|
370
|
-
value = attr.type.cast(value) unless is_content_mapping
|
334
|
+
elsif !(attr.type <= Serialize) && value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
|
335
|
+
value = value["text"]
|
371
336
|
end
|
372
337
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
else
|
382
|
-
mapping_hash[rule.to]
|
383
|
-
end
|
338
|
+
unless is_content_mapping
|
339
|
+
value = attr.cast(
|
340
|
+
value,
|
341
|
+
:xml,
|
342
|
+
caller_class: self,
|
343
|
+
mixed_content: rule.mixed_content,
|
344
|
+
)
|
345
|
+
end
|
384
346
|
|
385
|
-
|
347
|
+
if rule.custom_methods[:from]
|
348
|
+
new.send(rule.custom_methods[:from], instance, value)
|
349
|
+
else
|
350
|
+
instance.public_send(:"#{rule.to}=", value)
|
351
|
+
end
|
386
352
|
end
|
387
353
|
|
388
|
-
|
354
|
+
instance
|
389
355
|
end
|
390
356
|
|
391
357
|
def ensure_utf8(value)
|
392
358
|
case value
|
393
359
|
when String
|
394
|
-
value.encode("UTF-8", invalid: :replace, undef: :replace,
|
360
|
+
value.encode("UTF-8", invalid: :replace, undef: :replace,
|
361
|
+
replace: "")
|
395
362
|
when Array
|
396
363
|
value.map { |v| ensure_utf8(v) }
|
397
364
|
when Hash
|
@@ -406,7 +373,7 @@ module Lutaml
|
|
406
373
|
end
|
407
374
|
end
|
408
375
|
|
409
|
-
|
376
|
+
attr_accessor :element_order
|
410
377
|
|
411
378
|
def initialize(attrs = {})
|
412
379
|
return unless self.class.attributes
|
@@ -429,6 +396,10 @@ module Lutaml
|
|
429
396
|
@ordered
|
430
397
|
end
|
431
398
|
|
399
|
+
def ordered=(ordered)
|
400
|
+
@ordered = ordered
|
401
|
+
end
|
402
|
+
|
432
403
|
def key_exist?(hash, key)
|
433
404
|
hash.key?(key.to_sym) || hash.key?(key.to_s)
|
434
405
|
end
|
@@ -444,7 +415,8 @@ module Lutaml
|
|
444
415
|
representation = if format == :xml
|
445
416
|
self
|
446
417
|
else
|
447
|
-
self.class.hash_representation(self, format,
|
418
|
+
self.class.hash_representation(self, format,
|
419
|
+
options)
|
448
420
|
end
|
449
421
|
|
450
422
|
adapter.new(representation).public_send(:"to_#{format}", options)
|
@@ -455,7 +427,8 @@ module Lutaml
|
|
455
427
|
self.class.attributes.each do |name, attr|
|
456
428
|
value = send(name)
|
457
429
|
unless self.class.attr_value_valid?(name, value)
|
458
|
-
raise Lutaml::Model::InvalidValueError.new(name, value,
|
430
|
+
raise Lutaml::Model::InvalidValueError.new(name, value,
|
431
|
+
attr.options[:values])
|
459
432
|
end
|
460
433
|
end
|
461
434
|
end
|
data/lib/lutaml/model/type.rb
CHANGED
@@ -22,11 +22,13 @@ module Lutaml
|
|
22
22
|
class #{t} # class Integer
|
23
23
|
def self.cast(value) # def self.cast(value)
|
24
24
|
return if value.nil? # return if value.nil?
|
25
|
+
#
|
25
26
|
Type.cast(value, #{t}) # Type.cast(value, Integer)
|
26
27
|
end # end
|
27
28
|
|
28
29
|
def self.serialize(value) # def self.serialize(value)
|
29
30
|
return if value.nil? # return if value.nil?
|
31
|
+
#
|
30
32
|
Type.serialize(value, #{t}) # Type.serialize(value, Integer)
|
31
33
|
end # end
|
32
34
|
end # end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Utils
|
6
|
+
class << self
|
7
|
+
# Convert string to camel case
|
8
|
+
def camel_case(str)
|
9
|
+
return "" if str.nil? || str.empty?
|
10
|
+
|
11
|
+
str.split("/").map { |part| camelize_part(part) }.join("::")
|
12
|
+
end
|
13
|
+
|
14
|
+
# Convert string to class name
|
15
|
+
def classify(str)
|
16
|
+
str = str.to_s.delete(".")
|
17
|
+
str = str.sub(/^[a-z\d]*/) { |match| camel_case(match) || match }
|
18
|
+
|
19
|
+
str.gsub("::", "/").gsub(%r{(?:_|-|(/))([a-z\d]*)}i) do
|
20
|
+
word = Regexp.last_match(2)
|
21
|
+
substituted = camel_case(word) || word
|
22
|
+
Regexp.last_match(1) ? "::#{substituted}" : substituted
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Convert string to snake case
|
27
|
+
def snake_case(str)
|
28
|
+
str = str.to_s.tr(".", "_")
|
29
|
+
return str unless /[A-Z-]|::/.match?(str)
|
30
|
+
|
31
|
+
str.gsub("::", "/")
|
32
|
+
.gsub(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { "#{$1 || $2}_" }
|
33
|
+
.tr("-", "_")
|
34
|
+
.downcase
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def camelize_part(part)
|
40
|
+
part.gsub(/(?:_|-|^)([a-z\d])/i) { $1.upcase }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|