lutaml-model 0.3.10 → 0.3.12

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.

Potentially problematic release.


This version of lutaml-model might be problematic. Click here for more details.

@@ -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