lutaml-model 0.2.1 → 0.3.1
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/.gitignore +2 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +207 -0
- data/Gemfile +6 -2
- data/README.adoc +1054 -126
- data/lib/lutaml/model/attribute.rb +4 -0
- data/lib/lutaml/model/error/invalid_value_error.rb +18 -0
- data/lib/lutaml/model/error.rb +8 -0
- data/lib/lutaml/model/key_value_mapping.rb +9 -1
- data/lib/lutaml/model/mapping_hash.rb +42 -0
- data/lib/lutaml/model/mapping_rule.rb +24 -2
- data/lib/lutaml/model/serialize.rb +270 -189
- data/lib/lutaml/model/toml_adapter/toml_rb_adapter.rb +2 -2
- data/lib/lutaml/model/type.rb +19 -13
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +104 -101
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +125 -85
- data/lib/lutaml/model/xml_adapter.rb +138 -7
- data/lib/lutaml/model/xml_mapping.rb +36 -6
- data/lib/lutaml/model/xml_mapping_rule.rb +6 -6
- data/lib/lutaml/model/yaml_adapter.rb +11 -3
- data/lib/lutaml/model.rb +7 -0
- metadata +6 -2
@@ -1,14 +1,11 @@
|
|
1
1
|
# lib/lutaml/model/serialize.rb
|
2
|
-
require_relative "json_adapter/standard"
|
3
|
-
require_relative "json_adapter/multi_json"
|
4
2
|
require_relative "yaml_adapter"
|
5
3
|
require_relative "xml_adapter"
|
6
|
-
require_relative "toml_adapter/toml_rb_adapter"
|
7
|
-
require_relative "toml_adapter/tomlib_adapter"
|
8
4
|
require_relative "config"
|
9
5
|
require_relative "type"
|
10
6
|
require_relative "attribute"
|
11
7
|
require_relative "mapping_rule"
|
8
|
+
require_relative "mapping_hash"
|
12
9
|
require_relative "xml_mapping"
|
13
10
|
require_relative "key_value_mapping"
|
14
11
|
require_relative "json_adapter"
|
@@ -22,16 +19,29 @@ module Lutaml
|
|
22
19
|
base.extend(ClassMethods)
|
23
20
|
end
|
24
21
|
|
25
|
-
# rubocop:disable Metrics/MethodLength
|
26
|
-
# rubocop:disable Metrics/BlockLength
|
27
|
-
# rubocop:disable Metrics/AbcSize
|
28
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
29
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
30
22
|
module ClassMethods
|
31
23
|
attr_accessor :attributes, :mappings
|
32
24
|
|
25
|
+
def inherited(subclass)
|
26
|
+
super
|
27
|
+
|
28
|
+
@mappings ||= {}
|
29
|
+
@attributes ||= {}
|
30
|
+
|
31
|
+
subclass.instance_variable_set(:@attributes, @attributes.dup)
|
32
|
+
subclass.instance_variable_set(:@mappings, @mappings.dup)
|
33
|
+
subclass.instance_variable_set(:@model, subclass)
|
34
|
+
end
|
35
|
+
|
36
|
+
def model(klass = nil)
|
37
|
+
if klass
|
38
|
+
@model = klass
|
39
|
+
else
|
40
|
+
@model
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
33
44
|
def attribute(name, type, options = {})
|
34
|
-
self.attributes ||= {}
|
35
45
|
attr = Attribute.new(name, type, options)
|
36
46
|
attributes[name] = attr
|
37
47
|
|
@@ -40,29 +50,159 @@ module Lutaml
|
|
40
50
|
end
|
41
51
|
|
42
52
|
define_method(:"#{name}=") do |value|
|
53
|
+
if options[:values] && !options[:values].include?(value)
|
54
|
+
raise Lutaml::Model::InvalidValueError.new(name, value, options[:values])
|
55
|
+
end
|
56
|
+
|
43
57
|
instance_variable_set(:"@#{name}", value)
|
44
58
|
end
|
45
59
|
end
|
46
60
|
|
47
61
|
FORMATS.each do |format|
|
48
62
|
define_method(format) do |&block|
|
49
|
-
self.mappings ||= {}
|
50
63
|
klass = format == :xml ? XmlMapping : KeyValueMapping
|
51
|
-
|
52
|
-
|
64
|
+
mappings[format] = klass.new
|
65
|
+
mappings[format].instance_eval(&block)
|
66
|
+
|
67
|
+
if format == :xml && !mappings[format].root_element
|
68
|
+
mappings[format].root(model.to_s)
|
69
|
+
end
|
53
70
|
end
|
54
71
|
|
55
72
|
define_method(:"from_#{format}") do |data|
|
56
73
|
adapter = Lutaml::Model::Config.send(:"#{format}_adapter")
|
57
74
|
doc = adapter.parse(data)
|
58
75
|
mapped_attrs = apply_mappings(doc.to_h, format)
|
59
|
-
apply_content_mapping(doc, mapped_attrs) if format == :xml
|
60
|
-
|
76
|
+
# apply_content_mapping(doc, mapped_attrs) if format == :xml
|
77
|
+
generate_model_object(self, mapped_attrs)
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method(:"to_#{format}") do |instance|
|
81
|
+
unless instance.is_a?(model)
|
82
|
+
msg = "argument is a '#{instance.class}' but should be a '#{model}'"
|
83
|
+
raise Lutaml::Model::IncorrectModelError, msg
|
84
|
+
end
|
85
|
+
|
86
|
+
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
87
|
+
|
88
|
+
if format == :xml
|
89
|
+
xml_options = { mapper_class: self }
|
90
|
+
|
91
|
+
adapter.new(instance).public_send(:"to_#{format}", xml_options)
|
92
|
+
else
|
93
|
+
hash = hash_representation(instance, format)
|
94
|
+
adapter.new(hash).public_send(:"to_#{format}")
|
95
|
+
end
|
61
96
|
end
|
62
97
|
end
|
63
98
|
|
99
|
+
def hash_representation(instance, format, options = {})
|
100
|
+
only = options[:only]
|
101
|
+
except = options[:except]
|
102
|
+
mappings = mappings_for(format).mappings
|
103
|
+
|
104
|
+
mappings.each_with_object({}) do |rule, hash|
|
105
|
+
name = rule.to
|
106
|
+
next if except&.include?(name) || (only && !only.include?(name))
|
107
|
+
|
108
|
+
next handle_delegate(instance, rule, hash) if rule.delegate
|
109
|
+
|
110
|
+
value = if rule.custom_methods[:to]
|
111
|
+
instance.send(rule.custom_methods[:to], instance, instance.send(name))
|
112
|
+
else
|
113
|
+
instance.send(name)
|
114
|
+
end
|
115
|
+
|
116
|
+
next if value.nil? && !rule.render_nil
|
117
|
+
|
118
|
+
attribute = attributes[name]
|
119
|
+
|
120
|
+
hash[rule.from] = if rule.child_mappings
|
121
|
+
generate_hash_from_child_mappings(value, rule.child_mappings)
|
122
|
+
elsif value.is_a?(Array)
|
123
|
+
value.map do |v|
|
124
|
+
if attribute.type <= Serialize
|
125
|
+
attribute.type.hash_representation(v, format, options)
|
126
|
+
else
|
127
|
+
attribute.type.serialize(v)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
elsif attribute.type <= Serialize
|
131
|
+
attribute.type.hash_representation(value, format, options)
|
132
|
+
else
|
133
|
+
attribute.type.serialize(value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def handle_delegate(instance, rule, hash)
|
139
|
+
name = rule.to
|
140
|
+
value = instance.send(rule.delegate).send(name)
|
141
|
+
return if value.nil? && !rule.render_nil
|
142
|
+
|
143
|
+
attribute = instance.send(rule.delegate).class.attributes[name]
|
144
|
+
hash[rule.from] = case value
|
145
|
+
when Array
|
146
|
+
value.map do |v|
|
147
|
+
if v.is_a?(Serialize)
|
148
|
+
hash_representation(v, format, options)
|
149
|
+
else
|
150
|
+
attribute.type.serialize(v)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
if value.is_a?(Serialize)
|
155
|
+
hash_representation(value, format, options)
|
156
|
+
else
|
157
|
+
attribute.type.serialize(value)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
64
162
|
def mappings_for(format)
|
65
|
-
|
163
|
+
mappings[format] || default_mappings(format)
|
164
|
+
end
|
165
|
+
|
166
|
+
def generate_model_object(type, mapped_attrs)
|
167
|
+
return type.model.new(mapped_attrs) if self == model
|
168
|
+
|
169
|
+
instance = type.model.new
|
170
|
+
|
171
|
+
type.attributes.each do |name, attr|
|
172
|
+
value = attr_value(mapped_attrs, name, attr)
|
173
|
+
|
174
|
+
instance.send(:"#{name}=", ensure_utf8(value))
|
175
|
+
end
|
176
|
+
|
177
|
+
instance
|
178
|
+
end
|
179
|
+
|
180
|
+
def attr_value(attrs, name, attr_rule)
|
181
|
+
value = if attrs.key?(name)
|
182
|
+
attrs[name]
|
183
|
+
elsif attrs.key?(name.to_sym)
|
184
|
+
attrs[name.to_sym]
|
185
|
+
elsif attrs.key?(name.to_s)
|
186
|
+
attrs[name.to_s]
|
187
|
+
else
|
188
|
+
attr_rule.default
|
189
|
+
end
|
190
|
+
|
191
|
+
if attr_rule.collection? || value.is_a?(Array)
|
192
|
+
(value || []).map do |v|
|
193
|
+
if v.is_a?(Hash)
|
194
|
+
attr_rule.type.new(v)
|
195
|
+
else
|
196
|
+
Lutaml::Model::Type.cast(
|
197
|
+
v, attr_rule.type
|
198
|
+
)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
elsif value.is_a?(Hash) && attr_rule.type != Lutaml::Model::Type::Hash
|
202
|
+
generate_model_object(attr_rule.type, value)
|
203
|
+
else
|
204
|
+
Lutaml::Model::Type.cast(value, attr_rule.type)
|
205
|
+
end
|
66
206
|
end
|
67
207
|
|
68
208
|
def default_mappings(format)
|
@@ -75,11 +215,57 @@ module Lutaml
|
|
75
215
|
end
|
76
216
|
end
|
77
217
|
|
218
|
+
def apply_child_mappings(hash, child_mappings)
|
219
|
+
return hash unless child_mappings
|
220
|
+
|
221
|
+
hash.map do |key, value|
|
222
|
+
child_mappings.to_h do |attr_name, path|
|
223
|
+
attr_value = if path == :key
|
224
|
+
key
|
225
|
+
elsif path == :value
|
226
|
+
value
|
227
|
+
else
|
228
|
+
path = [path] unless path.is_a?(Array)
|
229
|
+
value.dig(*path.map(&:to_s))
|
230
|
+
end
|
231
|
+
|
232
|
+
[attr_name, attr_value]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def generate_hash_from_child_mappings(value, child_mappings)
|
238
|
+
return value unless child_mappings
|
239
|
+
|
240
|
+
hash = {}
|
241
|
+
|
242
|
+
value.each do |child_obj|
|
243
|
+
map_key = nil
|
244
|
+
map_value = {}
|
245
|
+
child_mappings.each do |attr_name, path|
|
246
|
+
if path == :key
|
247
|
+
map_key = child_obj.send(attr_name)
|
248
|
+
elsif path == :value
|
249
|
+
map_value = child_obj.send(attr_name)
|
250
|
+
else
|
251
|
+
path = [path] unless path.is_a?(Array)
|
252
|
+
path[0...-1].inject(map_value) do |acc, k|
|
253
|
+
acc[k.to_s] ||= {}
|
254
|
+
end.public_send(:[]=, path.last.to_s, child_obj.send(attr_name))
|
255
|
+
end
|
256
|
+
end
|
257
|
+
# hash[mapping.name] ||= {}
|
258
|
+
hash[map_key] = map_value
|
259
|
+
end
|
260
|
+
|
261
|
+
hash
|
262
|
+
end
|
263
|
+
|
78
264
|
def apply_mappings(doc, format)
|
79
265
|
return apply_xml_mapping(doc) if format == :xml
|
80
266
|
|
81
267
|
mappings = mappings_for(format).mappings
|
82
|
-
mappings.each_with_object(
|
268
|
+
mappings.each_with_object(Lutaml::Model::MappingHash.new) do |rule, hash|
|
83
269
|
attr = if rule.delegate
|
84
270
|
attributes[rule.delegate].type.attributes[rule.to]
|
85
271
|
else
|
@@ -95,15 +281,8 @@ module Lutaml
|
|
95
281
|
else
|
96
282
|
attr.default
|
97
283
|
end
|
98
|
-
|
99
|
-
|
100
|
-
# attr.type <= Serialize ? attr.type.new(v) : v
|
101
|
-
# end
|
102
|
-
# elsif value.is_a?(Hash) && attr.type <= Serialize
|
103
|
-
# value = attr.type.new(value)
|
104
|
-
# else
|
105
|
-
# value = attr.type.cast(value)
|
106
|
-
# end
|
284
|
+
|
285
|
+
value = apply_child_mappings(value, rule.child_mappings)
|
107
286
|
|
108
287
|
if attr.collection?
|
109
288
|
value = (value || []).map do |v|
|
@@ -122,214 +301,116 @@ module Lutaml
|
|
122
301
|
end
|
123
302
|
end
|
124
303
|
|
125
|
-
def apply_xml_mapping(doc)
|
304
|
+
def apply_xml_mapping(doc, caller_class: nil, mixed_content: false)
|
305
|
+
return unless doc
|
306
|
+
|
126
307
|
mappings = mappings_for(:xml).mappings
|
127
308
|
|
128
|
-
|
309
|
+
if doc.is_a?(Array)
|
310
|
+
raise "May be `collection: true` is" \
|
311
|
+
"missing for #{self} in #{caller_class}"
|
312
|
+
end
|
313
|
+
|
314
|
+
mapping_hash = Lutaml::Model::MappingHash.new
|
315
|
+
mapping_hash.item_order = doc.item_order
|
316
|
+
mapping_hash.ordered = mappings_for(:xml).mixed_content? || mixed_content
|
317
|
+
|
318
|
+
mappings.each_with_object(mapping_hash) do |rule, hash|
|
129
319
|
attr = attributes[rule.to]
|
130
320
|
raise "Attribute '#{rule.to}' not found in #{self}" unless attr
|
131
321
|
|
132
|
-
|
133
|
-
|
134
|
-
else
|
322
|
+
is_content_mapping = rule.name.nil?
|
323
|
+
value = if is_content_mapping
|
135
324
|
doc["text"]
|
325
|
+
else
|
326
|
+
doc[rule.name.to_s] || doc[rule.name.to_sym]
|
136
327
|
end
|
137
328
|
|
138
|
-
# if attr.collection?
|
139
|
-
# value = (value || []).map do |v|
|
140
|
-
# attr.type <= Serialize ? attr.type.from_hash(v) : v
|
141
|
-
# end
|
142
|
-
# elsif value.is_a?(Hash) && attr.type <= Serialize
|
143
|
-
# value = attr.type.cast(value)
|
144
|
-
# elsif value.is_a?(Array)
|
145
|
-
# value = attr.type.cast(value.first["text"]&.first)
|
146
|
-
# end
|
147
|
-
|
148
329
|
if attr.collection?
|
330
|
+
if value && !value.is_a?(Array)
|
331
|
+
value = [value]
|
332
|
+
end
|
333
|
+
|
149
334
|
value = (value || []).map do |v|
|
150
335
|
if attr.type <= Serialize
|
151
|
-
attr.type.apply_xml_mapping(v)
|
152
|
-
|
336
|
+
attr.type.apply_xml_mapping(v, caller_class: self, mixed_content: rule.mixed_content)
|
337
|
+
elsif v.is_a?(Hash)
|
153
338
|
v["text"]
|
339
|
+
else
|
340
|
+
v
|
154
341
|
end
|
155
342
|
end
|
156
343
|
elsif attr.type <= Serialize
|
157
|
-
value = attr.type.apply_xml_mapping(value
|
344
|
+
value = attr.type.apply_xml_mapping(value, caller_class: self, mixed_content: rule.mixed_content)
|
158
345
|
else
|
159
346
|
if value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
|
160
347
|
value = value["text"]
|
161
348
|
end
|
162
349
|
|
163
|
-
value = attr.type.cast(value)
|
350
|
+
value = attr.type.cast(value) unless is_content_mapping
|
164
351
|
end
|
352
|
+
|
165
353
|
hash[rule.to] = value
|
166
354
|
end
|
167
355
|
end
|
168
356
|
|
169
|
-
def
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
357
|
+
def ensure_utf8(value)
|
358
|
+
case value
|
359
|
+
when String
|
360
|
+
value.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
361
|
+
when Array
|
362
|
+
value.map { |v| ensure_utf8(v) }
|
363
|
+
when Hash
|
364
|
+
value.transform_keys do |k|
|
365
|
+
ensure_utf8(k)
|
366
|
+
end.transform_values { |v| ensure_utf8(v) }
|
367
|
+
else
|
368
|
+
value
|
369
|
+
end
|
175
370
|
end
|
176
371
|
end
|
177
372
|
|
178
|
-
|
373
|
+
attr_reader :element_order
|
374
|
+
|
179
375
|
def initialize(attrs = {})
|
180
376
|
return unless self.class.attributes
|
181
377
|
|
378
|
+
if attrs.is_a?(Lutaml::Model::MappingHash)
|
379
|
+
@ordered = attrs.ordered?
|
380
|
+
@element_order = attrs.item_order
|
381
|
+
end
|
382
|
+
|
182
383
|
self.class.attributes.each do |name, attr|
|
183
|
-
value =
|
184
|
-
attrs[name]
|
185
|
-
elsif attrs.key?(name.to_sym)
|
186
|
-
attrs[name.to_sym]
|
187
|
-
elsif attrs.key?(name.to_s)
|
188
|
-
attrs[name.to_s]
|
189
|
-
else
|
190
|
-
attr.default
|
191
|
-
end
|
384
|
+
value = self.class.attr_value(attrs, name, attr)
|
192
385
|
|
193
|
-
|
194
|
-
(value || []).map do |v|
|
195
|
-
if v.is_a?(Hash)
|
196
|
-
attr.type.new(v)
|
197
|
-
else
|
198
|
-
Lutaml::Model::Type.cast(
|
199
|
-
v, attr.type
|
200
|
-
)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
elsif value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
|
204
|
-
attr.type.new(value)
|
205
|
-
else
|
206
|
-
Lutaml::Model::Type.cast(value, attr.type)
|
207
|
-
end
|
208
|
-
send(:"#{name}=", ensure_utf8(value))
|
386
|
+
send(:"#{name}=", self.class.ensure_utf8(value))
|
209
387
|
end
|
210
388
|
end
|
211
|
-
# rubocop:enable Layout/LineLength
|
212
|
-
|
213
|
-
# TODO: Make this work
|
214
|
-
# FORMATS.each do |format|
|
215
|
-
# define_method("to_#{format}") do |options = {}|
|
216
|
-
# adapter = Lutaml::Model::Config.send("#{format}_adapter")
|
217
|
-
# representation = if format == :yaml
|
218
|
-
# self
|
219
|
-
# else
|
220
|
-
# hash_representation(format, options)
|
221
|
-
# end
|
222
|
-
# adapter.new(representation).send("to_#{format}", options)
|
223
|
-
# end
|
224
|
-
# end
|
225
|
-
|
226
|
-
def to_xml(options = {})
|
227
|
-
adapter = Lutaml::Model::Config.xml_adapter
|
228
|
-
adapter.new(self).to_xml(options)
|
229
|
-
end
|
230
|
-
|
231
|
-
def to_json(options = {})
|
232
|
-
adapter = Lutaml::Model::Config.json_adapter
|
233
|
-
adapter.new(hash_representation(:json, options)).to_json(options)
|
234
|
-
end
|
235
389
|
|
236
|
-
def
|
237
|
-
|
238
|
-
adapter.to_yaml(self, options)
|
390
|
+
def ordered?
|
391
|
+
@ordered
|
239
392
|
end
|
240
393
|
|
241
|
-
def
|
242
|
-
|
243
|
-
adapter.new(hash_representation(:toml, options)).to_toml
|
394
|
+
def key_exist?(hash, key)
|
395
|
+
hash.key?(key) || hash.key?(key.to_sym) || hash.key?(key.to_s)
|
244
396
|
end
|
245
397
|
|
246
|
-
|
247
|
-
|
248
|
-
def hash_representation(format, options = {})
|
249
|
-
only = options[:only]
|
250
|
-
except = options[:except]
|
251
|
-
mappings = self.class.mappings_for(format).mappings
|
252
|
-
|
253
|
-
mappings.each_with_object({}) do |rule, hash|
|
254
|
-
name = rule.to
|
255
|
-
next if except&.include?(name) || (only && !only.include?(name))
|
256
|
-
|
257
|
-
next handle_delegate(self, rule, hash) if rule.delegate
|
258
|
-
|
259
|
-
value = if rule.custom_methods[:to]
|
260
|
-
send(rule.custom_methods[:to], self, send(name))
|
261
|
-
else
|
262
|
-
send(name)
|
263
|
-
end
|
264
|
-
|
265
|
-
next if value.nil? && !rule.render_nil
|
266
|
-
|
267
|
-
attribute = self.class.attributes[name]
|
268
|
-
|
269
|
-
hash[rule.from] = case value
|
270
|
-
when Array
|
271
|
-
value.map do |v|
|
272
|
-
if v.is_a?(Serialize)
|
273
|
-
v.hash_representation(format, options)
|
274
|
-
else
|
275
|
-
attribute.type.serialize(v)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
else
|
279
|
-
if value.is_a?(Serialize)
|
280
|
-
value.hash_representation(format, options)
|
281
|
-
else
|
282
|
-
attribute.type.serialize(value)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
398
|
+
def key_value(hash, key)
|
399
|
+
hash[key] || hash[key.to_sym] || hash[key.to_s]
|
286
400
|
end
|
287
401
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
hash[rule.from] = case value
|
297
|
-
when Array
|
298
|
-
value.map do |v|
|
299
|
-
if v.is_a?(Serialize)
|
300
|
-
v.hash_representation(format, options)
|
301
|
-
else
|
302
|
-
attribute.type.serialize(v)
|
303
|
-
end
|
304
|
-
end
|
305
|
-
else
|
306
|
-
if value.is_a?(Serialize)
|
307
|
-
value.hash_representation(format, options)
|
308
|
-
else
|
309
|
-
attribute.type.serialize(value)
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
402
|
+
FORMATS.each do |format|
|
403
|
+
define_method(:"to_#{format}") do |options = {}|
|
404
|
+
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
405
|
+
representation = if format == :xml
|
406
|
+
self
|
407
|
+
else
|
408
|
+
self.class.hash_representation(self, format, options)
|
409
|
+
end
|
313
410
|
|
314
|
-
|
315
|
-
case value
|
316
|
-
when String
|
317
|
-
value.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
318
|
-
when Array
|
319
|
-
value.map { |v| ensure_utf8(v) }
|
320
|
-
when Hash
|
321
|
-
value.transform_keys do |k|
|
322
|
-
ensure_utf8(k)
|
323
|
-
end.transform_values { |v| ensure_utf8(v) }
|
324
|
-
else
|
325
|
-
value
|
411
|
+
adapter.new(representation).public_send(:"to_#{format}", options)
|
326
412
|
end
|
327
413
|
end
|
328
|
-
# rubocop:enable Metrics/MethodLength
|
329
|
-
# rubocop:enable Metrics/BlockLength
|
330
|
-
# rubocop:enable Metrics/AbcSize
|
331
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
332
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
333
414
|
end
|
334
415
|
end
|
335
416
|
end
|
data/lib/lutaml/model/type.rb
CHANGED
@@ -74,6 +74,24 @@ module Lutaml
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
class TextWithTags
|
78
|
+
attr_reader :content
|
79
|
+
|
80
|
+
def initialize(ordered_text_with_tags)
|
81
|
+
@content = ordered_text_with_tags
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.cast(value)
|
85
|
+
return value if value.is_a?(self)
|
86
|
+
|
87
|
+
new(value)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.serialize(value)
|
91
|
+
value.content.join
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
77
95
|
class JSON
|
78
96
|
attr_reader :value
|
79
97
|
|
@@ -94,7 +112,7 @@ module Lutaml
|
|
94
112
|
end
|
95
113
|
|
96
114
|
def self.cast(value)
|
97
|
-
return value if value.is_a?(self)
|
115
|
+
return value if value.is_a?(self) || value.nil?
|
98
116
|
|
99
117
|
new(::JSON.parse(value))
|
100
118
|
end
|
@@ -104,15 +122,8 @@ module Lutaml
|
|
104
122
|
end
|
105
123
|
end
|
106
124
|
|
107
|
-
# rubocop:disable Layout/LineLength
|
108
125
|
UUID_REGEX = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/
|
109
|
-
# rubocop:enable Layout/LineLength
|
110
126
|
|
111
|
-
# rubocop:disable Metrics/MethodLength
|
112
|
-
# rubocop:disable Layout/LineLength
|
113
|
-
# rubocop:disable Metrics/AbcSize
|
114
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
115
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
116
127
|
def self.cast(value, type)
|
117
128
|
return if value.nil?
|
118
129
|
|
@@ -203,11 +214,6 @@ module Lutaml
|
|
203
214
|
end
|
204
215
|
end.to_h
|
205
216
|
end
|
206
|
-
# rubocop:enable Metrics/MethodLength
|
207
|
-
# rubocop:enable Layout/LineLength
|
208
|
-
# rubocop:enable Metrics/AbcSize
|
209
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
210
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
211
217
|
end
|
212
218
|
end
|
213
219
|
end
|