lutaml-model 0.3.10 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -66,24 +66,43 @@ module Lutaml
66
66
  options[:tag_name] = rule.name
67
67
 
68
68
  options[:mapper_class] = attribute&.type if attribute
69
+ options[:namespace_set] = set_namespace?(rule)
69
70
 
70
71
  options
71
72
  end
72
73
 
73
- def parse_element(element)
74
+ def parse_element(element, klass = nil, format = nil)
74
75
  result = Lutaml::Model::MappingHash.new
75
76
  result.item_order = element.order
76
77
 
77
78
  element.children.each_with_object(result) do |child, hash|
78
- value = child.text? ? child.text : parse_element(child)
79
+ attr = klass.attribute_for_child(child.name, format) if klass&.<= Serialize
80
+
81
+ value = if child.text?
82
+ child.text
83
+ elsif attr&.raw?
84
+ child.children.map do |c|
85
+ next c.text if c.text?
86
+
87
+ c.to_xml.doc.root.to_xml({})
88
+ end.join
89
+ else
90
+ parse_element(child, attr&.type || klass, format)
91
+ end
79
92
 
80
- hash[child.unprefixed_name] = if hash[child.unprefixed_name]
81
- [hash[child.unprefixed_name], value].flatten
93
+ hash[child.namespaced_name] = if hash[child.namespaced_name]
94
+ [hash[child.namespaced_name], value].flatten
82
95
  else
83
96
  value
84
97
  end
85
98
  end
86
99
 
100
+ result.merge(attributes_hash(element))
101
+ end
102
+
103
+ def attributes_hash(element)
104
+ result = Lutaml::Model::MappingHash.new
105
+
87
106
  element.attributes.each_value do |attr|
88
107
  if attr.unprefixed_name == "schemaLocation"
89
108
  result["__schema_location"] = {
@@ -92,7 +111,7 @@ module Lutaml
92
111
  schema_location: attr.value,
93
112
  }
94
113
  else
95
- result[attr.unprefixed_name] = attr.value
114
+ result[attr.name] = attr.value
96
115
  end
97
116
  end
98
117
 
@@ -107,10 +126,10 @@ module Lutaml
107
126
  end
108
127
  end
109
128
 
110
- def add_to_xml(xml, prefix, value, options = {})
129
+ def add_to_xml(xml, element, prefix, value, options = {})
111
130
  if value.is_a?(Array)
112
131
  value.each do |item|
113
- add_to_xml(xml, prefix, item, options)
132
+ add_to_xml(xml, element, prefix, item, options)
114
133
  end
115
134
 
116
135
  return
@@ -120,7 +139,7 @@ module Lutaml
120
139
  rule = options[:rule]
121
140
 
122
141
  if rule.custom_methods[:to]
123
- @root.send(rule.custom_methods[:to], @root, xml.parent, xml)
142
+ options[:mapper_class].new.send(rule.custom_methods[:to], element, xml.parent, xml)
124
143
  return
125
144
  end
126
145
 
@@ -130,21 +149,29 @@ module Lutaml
130
149
  value,
131
150
  options.merge({ rule: rule, attribute: attribute }),
132
151
  )
133
- else
152
+ elsif rule.prefix_set?
134
153
  xml.create_and_add_element(rule.name, prefix: prefix) do
135
- if !value.nil?
136
- serialized_value = attribute.type.serialize(value)
154
+ add_value(xml, value, attribute)
155
+ end
156
+ else
157
+ xml.create_and_add_element(rule.name) do
158
+ add_value(xml, value, attribute)
159
+ end
160
+ end
161
+ end
137
162
 
138
- if attribute.type == Lutaml::Model::Type::Hash
139
- serialized_value.each do |key, val|
140
- xml.create_and_add_element(key) do |element|
141
- element.text(val)
142
- end
143
- end
144
- else
145
- xml.add_text(xml, serialized_value)
163
+ def add_value(xml, value, attribute)
164
+ if !value.nil?
165
+ serialized_value = attribute.type.serialize(value)
166
+
167
+ if attribute.type == Lutaml::Model::Type::Hash
168
+ serialized_value.each do |key, val|
169
+ xml.create_and_add_element(key) do |element|
170
+ element.text(val)
146
171
  end
147
172
  end
173
+ else
174
+ xml.add_text(xml, serialized_value)
148
175
  end
149
176
  end
150
177
  end
@@ -176,21 +203,28 @@ module Lutaml
176
203
  prefixed_xml.add_namespace_prefix(nil)
177
204
  end
178
205
 
206
+ xml_mapping.attributes.each do |attribute_rule|
207
+ attribute_rule.serialize_attribute(element, prefixed_xml.parent, xml)
208
+ end
209
+
179
210
  xml_mapping.elements.each do |element_rule|
180
211
  attribute_def = attribute_definition_for(element, element_rule,
181
212
  mapper_class: mapper_class)
182
213
 
183
- value = attribute_value_for(element, element_rule)
214
+ if attribute_def
215
+ value = attribute_value_for(element, element_rule)
184
216
 
185
- next if value.nil? && !element_rule.render_nil?
217
+ next if value.nil? && !element_rule.render_nil?
186
218
 
187
- value = [value] if attribute_def.collection? && !value.is_a?(Array)
219
+ value = [value] if attribute_def.collection? && !value.is_a?(Array)
220
+ end
188
221
 
189
222
  add_to_xml(
190
223
  prefixed_xml,
224
+ element,
191
225
  element_rule.prefix,
192
226
  value,
193
- options.merge({ attribute: attribute_def, rule: element_rule }),
227
+ options.merge({ attribute: attribute_def, rule: element_rule, mapper_class: mapper_class }),
194
228
  )
195
229
  end
196
230
 
@@ -199,7 +233,7 @@ module Lutaml
199
233
  @root.send(content_rule.custom_methods[:to], element,
200
234
  prefixed_xml.parent, prefixed_xml)
201
235
  else
202
- text = element.send(content_rule.to)
236
+ text = content_rule.serialize(element)
203
237
  text = text.join if text.is_a?(Array)
204
238
  prefixed_xml.add_text(xml, text)
205
239
  end
@@ -216,15 +250,21 @@ module Lutaml
216
250
  mapper_class ? mapper_class.mappings_for(:xml).mixed_content? : false
217
251
  end
218
252
 
219
- def build_namespace_attributes(klass, processed = {})
253
+ def set_namespace?(rule)
254
+ rule.nil? || !rule.namespace_set? || !rule.namespace.nil?
255
+ end
256
+
257
+ def build_namespace_attributes(klass, processed = {}, options = {})
220
258
  xml_mappings = klass.mappings_for(:xml)
221
259
  attributes = klass.attributes
222
260
 
223
261
  attrs = {}
224
262
 
225
- if xml_mappings.namespace_uri
226
- prefixed_name = ["xmlns",
227
- xml_mappings.namespace_prefix].compact.join(":")
263
+ if xml_mappings.namespace_uri && set_namespace?(options[:caller_rule])
264
+ prefixed_name = [
265
+ "xmlns",
266
+ xml_mappings.namespace_prefix,
267
+ ].compact.join(":")
228
268
 
229
269
  attrs[prefixed_name] = xml_mappings.namespace_uri
230
270
  end
@@ -239,14 +279,16 @@ module Lutaml
239
279
  type = if mapping_rule.delegate
240
280
  attributes[mapping_rule.delegate].type.attributes[mapping_rule.to].type
241
281
  else
242
- attributes[mapping_rule.to].type
282
+ attributes[mapping_rule.to]&.type
243
283
  end
244
284
 
285
+ next unless type
286
+
245
287
  if type <= Lutaml::Model::Serialize
246
- attrs = attrs.merge(build_namespace_attributes(type, processed))
288
+ attrs = attrs.merge(build_namespace_attributes(type, processed, { caller_rule: mapping_rule }))
247
289
  end
248
290
 
249
- if mapping_rule.namespace
291
+ if mapping_rule.namespace && mapping_rule.prefix && mapping_rule.name != "lang"
250
292
  attrs["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
251
293
  end
252
294
  end
@@ -255,22 +297,27 @@ module Lutaml
255
297
  end
256
298
 
257
299
  def build_attributes(element, xml_mapping, options = {})
258
- attrs = namespace_attributes(xml_mapping)
300
+ attrs = if options.fetch(:namespace_set, true)
301
+ namespace_attributes(xml_mapping)
302
+ else
303
+ {}
304
+ end
259
305
 
260
306
  xml_mapping.attributes.each_with_object(attrs) do |mapping_rule, hash|
261
307
  next if options[:except]&.include?(mapping_rule.to)
308
+ next if mapping_rule.custom_methods[:to]
262
309
 
263
- if mapping_rule.namespace
310
+ if mapping_rule.namespace && mapping_rule.prefix && mapping_rule.name != "lang"
264
311
  hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
265
312
  end
266
313
 
267
- hash[mapping_rule.prefixed_name] = element.send(mapping_rule.to)
314
+ hash[mapping_rule.prefixed_name] = mapping_rule.to_value_for(element)
268
315
  end
269
316
 
270
317
  xml_mapping.elements.each_with_object(attrs) do |mapping_rule, hash|
271
318
  next if options[:except]&.include?(mapping_rule.to)
272
319
 
273
- if mapping_rule.namespace
320
+ if mapping_rule.namespace && mapping_rule.prefix
274
321
  hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
275
322
  end
276
323
  end
@@ -16,7 +16,8 @@ module Lutaml
16
16
  children = [],
17
17
  text = nil,
18
18
  parent_document: nil,
19
- namespace_prefix: nil
19
+ namespace_prefix: nil,
20
+ default_namespace: nil
20
21
  )
21
22
  @name = extract_name(name)
22
23
  @namespace_prefix = namespace_prefix || extract_namespace_prefix(name)
@@ -24,11 +25,20 @@ module Lutaml
24
25
  @children = children
25
26
  @text = text
26
27
  @parent_document = parent_document
28
+ @default_namespace = default_namespace
27
29
  end
28
30
 
29
31
  def name
30
- if namespace_prefix
31
- "#{namespace_prefix}:#{@name}"
32
+ return @name unless namespace_prefix
33
+
34
+ "#{namespace_prefix}:#{@name}"
35
+ end
36
+
37
+ def namespaced_name
38
+ if namespaces[namespace_prefix] && !text?
39
+ "#{namespaces[namespace_prefix].uri}:#{@name}"
40
+ elsif @default_namespace && !text?
41
+ "#{@default_namespace}:#{name}"
32
42
  else
33
43
  @name
34
44
  end
@@ -37,7 +37,7 @@ module Lutaml
37
37
  end
38
38
 
39
39
  def attr_name
40
- if prefix && !prefix.empty?
40
+ if Utils.present?(prefix)
41
41
  "xmlns:#{prefix}"
42
42
  else
43
43
  "xmlns"
@@ -6,7 +6,8 @@ module Lutaml
6
6
  attr_reader :root_element,
7
7
  :namespace_uri,
8
8
  :namespace_prefix,
9
- :mixed_content
9
+ :mixed_content,
10
+ :ordered
10
11
 
11
12
  def initialize
12
13
  @elements = {}
@@ -16,10 +17,12 @@ module Lutaml
16
17
  end
17
18
 
18
19
  alias mixed_content? mixed_content
20
+ alias ordered? ordered
19
21
 
20
- def root(name, mixed: false)
22
+ def root(name, mixed: false, ordered: false)
21
23
  @root_element = name
22
24
  @mixed_content = mixed
25
+ @ordered = ordered || mixed # mixed contenet will always be ordered
23
26
  end
24
27
 
25
28
  def prefixed_root
@@ -38,37 +41,46 @@ module Lutaml
38
41
  # rubocop:disable Metrics/ParameterLists
39
42
  def map_element(
40
43
  name,
41
- to:,
44
+ to: nil,
42
45
  render_nil: false,
43
46
  with: {},
44
47
  delegate: nil,
45
48
  namespace: (namespace_set = false
46
49
  nil),
47
- prefix: nil
50
+ prefix: (prefix_set = false
51
+ nil)
48
52
  )
49
- @elements[name] = XmlMappingRule.new(
53
+ validate!(name, to, with)
54
+
55
+ rule = XmlMappingRule.new(
50
56
  name,
51
57
  to: to,
52
58
  render_nil: render_nil,
53
59
  with: with,
54
60
  delegate: delegate,
55
61
  namespace: namespace,
62
+ default_namespace: namespace_uri,
56
63
  prefix: prefix,
57
64
  namespace_set: namespace_set != false,
65
+ prefix_set: prefix_set != false,
58
66
  )
67
+ @elements[rule.namespaced_name] = rule
59
68
  end
60
69
 
61
70
  def map_attribute(
62
71
  name,
63
- to:,
72
+ to: nil,
64
73
  render_nil: false,
65
74
  with: {},
66
75
  delegate: nil,
67
76
  namespace: (namespace_set = false
68
77
  nil),
69
- prefix: nil
78
+ prefix: (prefix_set = false
79
+ nil)
70
80
  )
71
- @attributes[name] = XmlMappingRule.new(
81
+ validate!(name, to, with)
82
+
83
+ rule = XmlMappingRule.new(
72
84
  name,
73
85
  to: to,
74
86
  render_nil: render_nil,
@@ -76,19 +88,24 @@ module Lutaml
76
88
  delegate: delegate,
77
89
  namespace: namespace,
78
90
  prefix: prefix,
91
+ default_namespace: namespace_uri,
79
92
  namespace_set: namespace_set != false,
93
+ prefix_set: prefix_set != false,
80
94
  )
95
+ @attributes[rule.namespaced_name] = rule
81
96
  end
82
97
 
83
98
  # rubocop:enable Metrics/ParameterLists
84
99
 
85
100
  def map_content(
86
- to:,
101
+ to: nil,
87
102
  render_nil: false,
88
103
  with: {},
89
104
  delegate: nil,
90
105
  mixed: false
91
106
  )
107
+ validate!("content", to, with)
108
+
92
109
  @content_mapping = XmlMappingRule.new(
93
110
  nil,
94
111
  to: to,
@@ -99,6 +116,18 @@ module Lutaml
99
116
  )
100
117
  end
101
118
 
119
+ def validate!(key, to, with)
120
+ if to.nil? && with.empty?
121
+ msg = ":to or :with argument is required for mapping '#{key}'"
122
+ raise IncorrectMappingArgumentsError.new(msg)
123
+ end
124
+
125
+ if !with.empty? && (with[:from].nil? || with[:to].nil?)
126
+ msg = ":with argument for mapping '#{key}' requires :to and :from keys"
127
+ raise IncorrectMappingArgumentsError.new(msg)
128
+ end
129
+ end
130
+
102
131
  def elements
103
132
  @elements.values
104
133
  end
@@ -14,7 +14,9 @@ module Lutaml
14
14
  namespace: nil,
15
15
  prefix: nil,
16
16
  mixed_content: false,
17
- namespace_set: false
17
+ namespace_set: false,
18
+ prefix_set: false,
19
+ default_namespace: nil
18
20
  )
19
21
  super(
20
22
  name,
@@ -24,6 +26,8 @@ module Lutaml
24
26
  delegate: delegate,
25
27
  mixed_content: mixed_content,
26
28
  namespace_set: namespace_set,
29
+ prefix_set: prefix_set,
30
+ default_namespace: default_namespace
27
31
  )
28
32
 
29
33
  @namespace = if namespace.to_s == "inherit"
@@ -5,12 +5,17 @@ module Lutaml
5
5
  module Model
6
6
  module YamlAdapter
7
7
  class StandardYamlAdapter < YamlDocument
8
+ PERMITTED_CLASSES_BASE = [Date, Time, DateTime, Symbol, Hash,
9
+ Array].freeze
10
+
11
+ PERMITTED_CLASSES = if defined?(BigDecimal)
12
+ PERMITTED_CLASSES_BASE + [BigDecimal]
13
+ else
14
+ PERMITTED_CLASSES_BASE
15
+ end.freeze
16
+
8
17
  def self.parse(yaml)
9
- YAML.safe_load(
10
- yaml,
11
- permitted_classes: [Date, Time, DateTime, Symbol,
12
- BigDecimal, Hash, Array],
13
- )
18
+ YAML.safe_load(yaml, permitted_classes: PERMITTED_CLASSES)
14
19
  end
15
20
 
16
21
  def to_yaml(options = {})
data/lutaml-model.gemspec CHANGED
@@ -30,7 +30,6 @@ Gem::Specification.new do |spec|
30
30
  end
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
 
33
- spec.add_dependency "bigdecimal"
34
33
  spec.add_dependency "thor"
35
34
  spec.metadata["rubygems_mfa_required"] = "true"
36
35
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.3.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-11 00:00:00.000000000 Z
11
+ date: 2024-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bigdecimal
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: thor
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -56,6 +42,7 @@ files:
56
42
  - ".rubocop_todo.yml"
57
43
  - CODE_OF_CONDUCT.md
58
44
  - Gemfile
45
+ - LICENSE.md
59
46
  - README.adoc
60
47
  - Rakefile
61
48
  - bin/console
@@ -70,7 +57,9 @@ files:
70
57
  - lib/lutaml/model/config.rb
71
58
  - lib/lutaml/model/error.rb
72
59
  - lib/lutaml/model/error/collection_count_out_of_range_error.rb
60
+ - lib/lutaml/model/error/incorrect_mapping_argument_error.rb
73
61
  - lib/lutaml/model/error/invalid_value_error.rb
62
+ - lib/lutaml/model/error/type_not_enabled_error.rb
74
63
  - lib/lutaml/model/error/unknown_adapter_type_error.rb
75
64
  - lib/lutaml/model/error/validation_error.rb
76
65
  - lib/lutaml/model/json_adapter.rb