lutaml-model 0.3.9 → 0.3.11

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.
@@ -0,0 +1,24 @@
1
+ module Lutaml
2
+ module Model
3
+ module Validation
4
+ def validate
5
+ errors = []
6
+ self.class.attributes.each do |name, attr|
7
+ value = instance_variable_get(:"@#{name}")
8
+ begin
9
+ attr.validate_value!(value)
10
+ rescue Lutaml::Model::InvalidValueError,
11
+ Lutaml::Model::CollectionCountOutOfRangeError => e
12
+ errors << e
13
+ end
14
+ end
15
+ errors
16
+ end
17
+
18
+ def validate!
19
+ errors = validate
20
+ raise Lutaml::Model::ValidationError.new(errors) if errors.any?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.3.9"
5
+ VERSION = "0.3.11"
6
6
  end
7
7
  end
@@ -27,11 +27,21 @@ module Lutaml
27
27
  element.add_child(child)
28
28
  end
29
29
 
30
- def create_and_add_element(element_name, prefix: nil, attributes: {})
31
- add_namespace_prefix(prefix) if prefix
30
+ def add_attribute(element, name, value)
31
+ element[name] = value
32
+ end
33
+
34
+ def create_and_add_element(
35
+ element_name,
36
+ prefix: (prefix_unset = true
37
+ nil),
38
+ attributes: {}
39
+ )
40
+ add_namespace_prefix(prefix)
32
41
 
33
42
  if block_given?
34
43
  public_send(element_name, attributes) do
44
+ xml.parent.namespace = nil if prefix.nil? && !prefix_unset
35
45
  yield(self)
36
46
  end
37
47
  else
@@ -38,6 +38,10 @@ module Lutaml
38
38
  element << child
39
39
  end
40
40
 
41
+ def add_attribute(element, name, value)
42
+ element[name] = value
43
+ end
44
+
41
45
  def create_and_add_element(element_name, prefix: nil, attributes: {})
42
46
  prefixed_name = if prefix
43
47
  "#{prefix}:#{element_name}"
@@ -68,7 +68,7 @@ module Lutaml
68
68
  value = attribute_value_for(element, element_rule)
69
69
 
70
70
  if element_rule == xml_mapping.content_mapping
71
- text = element.send(xml_mapping.content_mapping.to)
71
+ text = xml_mapping.content_mapping.serialize(element)
72
72
  text = text[curr_index] if text.is_a?(Array)
73
73
 
74
74
  prefixed_xml.text text
@@ -77,6 +77,7 @@ module Lutaml
77
77
 
78
78
  add_to_xml(
79
79
  xml,
80
+ element,
80
81
  element_rule.prefix,
81
82
  value,
82
83
  options.merge(
@@ -64,6 +64,7 @@ module Lutaml
64
64
 
65
65
  add_to_xml(
66
66
  el,
67
+ element,
67
68
  nil,
68
69
  value,
69
70
  options.merge(
@@ -77,16 +77,23 @@ module Lutaml
77
77
  element.children.each_with_object(result) do |child, hash|
78
78
  value = child.text? ? child.text : parse_element(child)
79
79
 
80
- if hash[child.unprefixed_name]
81
- hash[child.unprefixed_name] =
82
- [hash[child.unprefixed_name], value].flatten
83
- else
84
- hash[child.unprefixed_name] = value
85
- end
80
+ hash[child.unprefixed_name] = if hash[child.unprefixed_name]
81
+ [hash[child.unprefixed_name], value].flatten
82
+ else
83
+ value
84
+ end
86
85
  end
87
86
 
88
87
  element.attributes.each_value do |attr|
89
- result[attr.unprefixed_name] = attr.value
88
+ if attr.unprefixed_name == "schemaLocation"
89
+ result["__schema_location"] = {
90
+ namespace: attr.namespace,
91
+ prefix: attr.namespace_prefix,
92
+ schema_location: attr.value,
93
+ }
94
+ else
95
+ result[attr.unprefixed_name] = attr.value
96
+ end
90
97
  end
91
98
 
92
99
  result
@@ -100,10 +107,10 @@ module Lutaml
100
107
  end
101
108
  end
102
109
 
103
- def add_to_xml(xml, prefix, value, options = {})
110
+ def add_to_xml(xml, element, prefix, value, options = {})
104
111
  if value.is_a?(Array)
105
112
  value.each do |item|
106
- add_to_xml(xml, prefix, item, options)
113
+ add_to_xml(xml, element, prefix, item, options)
107
114
  end
108
115
 
109
116
  return
@@ -113,7 +120,7 @@ module Lutaml
113
120
  rule = options[:rule]
114
121
 
115
122
  if rule.custom_methods[:to]
116
- @root.send(rule.custom_methods[:to], @root, xml.parent, xml)
123
+ options[:mapper_class].new.send(rule.custom_methods[:to], element, xml.parent, xml)
117
124
  return
118
125
  end
119
126
 
@@ -123,21 +130,29 @@ module Lutaml
123
130
  value,
124
131
  options.merge({ rule: rule, attribute: attribute }),
125
132
  )
126
- else
133
+ elsif rule.prefix_set?
127
134
  xml.create_and_add_element(rule.name, prefix: prefix) do
128
- if !value.nil?
129
- serialized_value = attribute.type.serialize(value)
130
-
131
- if attribute.type == Lutaml::Model::Type::Hash
132
- serialized_value.each do |key, val|
133
- xml.create_and_add_element(key) do |element|
134
- element.text(val)
135
- end
136
- end
137
- else
138
- xml.add_text(xml, serialized_value)
135
+ add_value(xml, value, attribute)
136
+ end
137
+ else
138
+ xml.create_and_add_element(rule.name) do
139
+ add_value(xml, value, attribute)
140
+ end
141
+ end
142
+ end
143
+
144
+ def add_value(xml, value, attribute)
145
+ if !value.nil?
146
+ serialized_value = attribute.type.serialize(value)
147
+
148
+ if attribute.type == Lutaml::Model::Type::Hash
149
+ serialized_value.each do |key, val|
150
+ xml.create_and_add_element(key) do |element|
151
+ element.text(val)
139
152
  end
140
153
  end
154
+ else
155
+ xml.add_text(xml, serialized_value)
141
156
  end
142
157
  end
143
158
  end
@@ -150,6 +165,9 @@ module Lutaml
150
165
  attributes = options[:xml_attributes] ||= {}
151
166
  attributes = build_attributes(element,
152
167
  xml_mapping, options).merge(attributes)&.compact
168
+ if element.respond_to?(:schema_location) && element.schema_location
169
+ attributes.merge!(element.schema_location.to_xml_attributes)
170
+ end
153
171
 
154
172
  prefix = if options.key?(:namespace_prefix)
155
173
  options[:namespace_prefix]
@@ -166,21 +184,28 @@ module Lutaml
166
184
  prefixed_xml.add_namespace_prefix(nil)
167
185
  end
168
186
 
187
+ xml_mapping.attributes.each do |attribute_rule|
188
+ attribute_rule.serialize_attribute(element, prefixed_xml.parent, xml)
189
+ end
190
+
169
191
  xml_mapping.elements.each do |element_rule|
170
192
  attribute_def = attribute_definition_for(element, element_rule,
171
193
  mapper_class: mapper_class)
172
194
 
173
- value = attribute_value_for(element, element_rule)
195
+ if attribute_def
196
+ value = attribute_value_for(element, element_rule)
174
197
 
175
- next if value.nil? && !element_rule.render_nil?
198
+ next if value.nil? && !element_rule.render_nil?
176
199
 
177
- value = [value] if attribute_def.collection? && !value.is_a?(Array)
200
+ value = [value] if attribute_def.collection? && !value.is_a?(Array)
201
+ end
178
202
 
179
203
  add_to_xml(
180
204
  prefixed_xml,
205
+ element,
181
206
  element_rule.prefix,
182
207
  value,
183
- options.merge({ attribute: attribute_def, rule: element_rule }),
208
+ options.merge({ attribute: attribute_def, rule: element_rule, mapper_class: mapper_class }),
184
209
  )
185
210
  end
186
211
 
@@ -189,7 +214,7 @@ module Lutaml
189
214
  @root.send(content_rule.custom_methods[:to], element,
190
215
  prefixed_xml.parent, prefixed_xml)
191
216
  else
192
- text = element.send(content_rule.to)
217
+ text = content_rule.serialize(element)
193
218
  text = text.join if text.is_a?(Array)
194
219
  prefixed_xml.add_text(xml, text)
195
220
  end
@@ -213,8 +238,10 @@ module Lutaml
213
238
  attrs = {}
214
239
 
215
240
  if xml_mappings.namespace_uri
216
- prefixed_name = ["xmlns",
217
- xml_mappings.namespace_prefix].compact.join(":")
241
+ prefixed_name = [
242
+ "xmlns",
243
+ xml_mappings.namespace_prefix,
244
+ ].compact.join(":")
218
245
 
219
246
  attrs[prefixed_name] = xml_mappings.namespace_uri
220
247
  end
@@ -229,9 +256,11 @@ module Lutaml
229
256
  type = if mapping_rule.delegate
230
257
  attributes[mapping_rule.delegate].type.attributes[mapping_rule.to].type
231
258
  else
232
- attributes[mapping_rule.to].type
259
+ attributes[mapping_rule.to]&.type
233
260
  end
234
261
 
262
+ next unless type
263
+
235
264
  if type <= Lutaml::Model::Serialize
236
265
  attrs = attrs.merge(build_namespace_attributes(type, processed))
237
266
  end
@@ -249,6 +278,7 @@ module Lutaml
249
278
 
250
279
  xml_mapping.attributes.each_with_object(attrs) do |mapping_rule, hash|
251
280
  next if options[:except]&.include?(mapping_rule.to)
281
+ next if mapping_rule.custom_methods[:to]
252
282
 
253
283
  if mapping_rule.namespace
254
284
  hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
@@ -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"
@@ -38,14 +38,17 @@ module Lutaml
38
38
  # rubocop:disable Metrics/ParameterLists
39
39
  def map_element(
40
40
  name,
41
- to:,
41
+ to: nil,
42
42
  render_nil: false,
43
43
  with: {},
44
44
  delegate: nil,
45
45
  namespace: (namespace_set = false
46
46
  nil),
47
- prefix: nil
47
+ prefix: (prefix_set = false
48
+ nil)
48
49
  )
50
+ validate!(name, to, with)
51
+
49
52
  @elements[name] = XmlMappingRule.new(
50
53
  name,
51
54
  to: to,
@@ -55,19 +58,23 @@ module Lutaml
55
58
  namespace: namespace,
56
59
  prefix: prefix,
57
60
  namespace_set: namespace_set != false,
61
+ prefix_set: prefix_set != false,
58
62
  )
59
63
  end
60
64
 
61
65
  def map_attribute(
62
66
  name,
63
- to:,
67
+ to: nil,
64
68
  render_nil: false,
65
69
  with: {},
66
70
  delegate: nil,
67
71
  namespace: (namespace_set = false
68
72
  nil),
69
- prefix: nil
73
+ prefix: (prefix_set = false
74
+ nil)
70
75
  )
76
+ validate!(name, to, with)
77
+
71
78
  @attributes[name] = XmlMappingRule.new(
72
79
  name,
73
80
  to: to,
@@ -77,18 +84,21 @@ module Lutaml
77
84
  namespace: namespace,
78
85
  prefix: prefix,
79
86
  namespace_set: namespace_set != false,
87
+ prefix_set: prefix_set != false,
80
88
  )
81
89
  end
82
90
 
83
91
  # rubocop:enable Metrics/ParameterLists
84
92
 
85
93
  def map_content(
86
- to:,
94
+ to: nil,
87
95
  render_nil: false,
88
96
  with: {},
89
97
  delegate: nil,
90
98
  mixed: false
91
99
  )
100
+ validate!("content", to, with)
101
+
92
102
  @content_mapping = XmlMappingRule.new(
93
103
  nil,
94
104
  to: to,
@@ -99,6 +109,18 @@ module Lutaml
99
109
  )
100
110
  end
101
111
 
112
+ def validate!(key, to, with)
113
+ if to.nil? && with.empty?
114
+ msg = ":to or :with argument is required for mapping '#{key}'"
115
+ raise IncorrectMappingArgumentsError.new(msg)
116
+ end
117
+
118
+ if !with.empty? && (with[:from].nil? || with[:to].nil?)
119
+ msg = ":with argument for mapping '#{key}' requires :to and :from keys"
120
+ raise IncorrectMappingArgumentsError.new(msg)
121
+ end
122
+ end
123
+
102
124
  def elements
103
125
  @elements.values
104
126
  end
@@ -14,7 +14,8 @@ 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
18
19
  )
19
20
  super(
20
21
  name,
@@ -24,6 +25,7 @@ module Lutaml
24
25
  delegate: delegate,
25
26
  mixed_content: mixed_content,
26
27
  namespace_set: namespace_set,
28
+ prefix_set: prefix_set,
27
29
  )
28
30
 
29
31
  @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,6 +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"
34
+ spec.metadata["rubygems_mfa_required"] = "true"
35
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.9
4
+ version: 0.3.11
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-04 00:00:00.000000000 Z
11
+ date: 2024-10-04 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
@@ -69,8 +56,12 @@ files:
69
56
  - lib/lutaml/model/comparison.rb
70
57
  - lib/lutaml/model/config.rb
71
58
  - lib/lutaml/model/error.rb
59
+ - lib/lutaml/model/error/collection_count_out_of_range_error.rb
60
+ - lib/lutaml/model/error/incorrect_mapping_argument_error.rb
72
61
  - lib/lutaml/model/error/invalid_value_error.rb
62
+ - lib/lutaml/model/error/type_not_enabled_error.rb
73
63
  - lib/lutaml/model/error/unknown_adapter_type_error.rb
64
+ - lib/lutaml/model/error/validation_error.rb
74
65
  - lib/lutaml/model/json_adapter.rb
75
66
  - lib/lutaml/model/json_adapter/json_document.rb
76
67
  - lib/lutaml/model/json_adapter/json_object.rb
@@ -86,6 +77,7 @@ files:
86
77
  - lib/lutaml/model/schema/relaxng_schema.rb
87
78
  - lib/lutaml/model/schema/xsd_schema.rb
88
79
  - lib/lutaml/model/schema/yaml_schema.rb
80
+ - lib/lutaml/model/schema_location.rb
89
81
  - lib/lutaml/model/serializable.rb
90
82
  - lib/lutaml/model/serialize.rb
91
83
  - lib/lutaml/model/toml_adapter.rb
@@ -97,6 +89,7 @@ files:
97
89
  - lib/lutaml/model/type/date_time.rb
98
90
  - lib/lutaml/model/type/time_without_date.rb
99
91
  - lib/lutaml/model/utils.rb
92
+ - lib/lutaml/model/validation.rb
100
93
  - lib/lutaml/model/version.rb
101
94
  - lib/lutaml/model/xml_adapter.rb
102
95
  - lib/lutaml/model/xml_adapter/builder/nokogiri.rb
@@ -119,7 +112,8 @@ files:
119
112
  homepage: https://github.com/lutaml/lutaml-model
120
113
  licenses:
121
114
  - BSD-2-Clause
122
- metadata: {}
115
+ metadata:
116
+ rubygems_mfa_required: 'true'
123
117
  post_install_message:
124
118
  rdoc_options: []
125
119
  require_paths: