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.
@@ -1,10 +1,13 @@
1
1
  # lib/lutaml/model/xml_adapter.rb
2
2
 
3
3
  require_relative "xml_namespace"
4
+ require_relative "mapping_hash"
4
5
 
5
6
  module Lutaml
6
7
  module Model
7
8
  module XmlAdapter
9
+ XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace".freeze
10
+
8
11
  class Document
9
12
  attr_reader :root
10
13
 
@@ -33,8 +36,113 @@ module Lutaml
33
36
  declaration
34
37
  end
35
38
 
36
- # rubocop:disable Metrics/AbcSize
37
- # rubocop:disable Metrics/MethodLength
39
+ def to_h
40
+ parse_element(@root)
41
+ end
42
+
43
+ def order
44
+ @root.order
45
+ end
46
+
47
+ def handle_nested_elements(builder, value, rule: nil, attribute: nil)
48
+ options = build_options_for_nested_elements(attribute, rule)
49
+
50
+ case value
51
+ when Array
52
+ value.each { |val| build_element(builder, val, options) }
53
+ else
54
+ build_element(builder, value, options)
55
+ end
56
+ end
57
+
58
+ def build_options_for_nested_elements(attribute, rule)
59
+ return {} unless rule
60
+
61
+ options = {}
62
+
63
+ options[:namespace_prefix] = rule.prefix if rule&.namespace_set?
64
+ options[:mixed_content] = rule.mixed_content
65
+
66
+ options[:mapper_class] = attribute&.type if attribute
67
+
68
+ options
69
+ end
70
+
71
+ def parse_element(element)
72
+ result = Lutaml::Model::MappingHash.new
73
+ result.item_order = element.order
74
+
75
+ element.children.each_with_object(result) do |child, hash|
76
+ value = child.text? ? child.text : parse_element(child)
77
+
78
+ if hash[child.unprefixed_name]
79
+ hash[child.unprefixed_name] =
80
+ [hash[child.unprefixed_name], value].flatten
81
+ else
82
+ hash[child.unprefixed_name] = value
83
+ end
84
+ end
85
+
86
+ element.attributes.each_value do |attr|
87
+ result[attr.unprefixed_name] = attr.value
88
+ end
89
+
90
+ result
91
+ end
92
+
93
+ def build_element(xml, element, options = {})
94
+ if ordered?(element, options)
95
+ build_ordered_element(xml, element, options)
96
+ else
97
+ build_unordered_element(xml, element, options)
98
+ end
99
+ end
100
+
101
+ def ordered?(element, options = {})
102
+ return false unless element.respond_to?(:element_order)
103
+ return element.ordered? if element.respond_to?(:ordered?)
104
+ return options[:mixed_content] if options.key?(:mixed_content)
105
+
106
+ mapper_class = options[:mapper_class]
107
+ mapper_class ? mapper_class.mappings_for(:xml).mixed_content? : false
108
+ end
109
+
110
+ def build_namespace_attributes(klass, processed = {})
111
+ xml_mappings = klass.mappings_for(:xml)
112
+ attributes = klass.attributes
113
+
114
+ attrs = {}
115
+
116
+ if xml_mappings.namespace_prefix
117
+ attrs["xmlns:#{xml_mappings.namespace_prefix}"] =
118
+ xml_mappings.namespace_uri
119
+ end
120
+
121
+ xml_mappings.mappings.each do |mapping_rule|
122
+ processed[klass] ||= {}
123
+
124
+ next if processed[klass][mapping_rule.name]
125
+
126
+ processed[klass][mapping_rule.name] = true
127
+
128
+ type = if mapping_rule.delegate
129
+ attributes[mapping_rule.delegate].type.attributes[mapping_rule.to].type
130
+ else
131
+ attributes[mapping_rule.to].type
132
+ end
133
+
134
+ if type <= Lutaml::Model::Serialize
135
+ attrs = attrs.merge(build_namespace_attributes(type, processed))
136
+ end
137
+
138
+ if mapping_rule.namespace
139
+ attrs["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
140
+ end
141
+ end
142
+
143
+ attrs
144
+ end
145
+
38
146
  def build_attributes(element, xml_mapping)
39
147
  attrs = namespace_attributes(xml_mapping)
40
148
 
@@ -52,8 +160,19 @@ module Lutaml
52
160
  end
53
161
  end
54
162
  end
55
- # rubocop:enable Metrics/AbcSize
56
- # rubocop:enable Metrics/MethodLength
163
+
164
+ def attribute_definition_for(element, rule, mapper_class: nil)
165
+ klass = mapper_class || element.class
166
+ return klass.attributes[rule.to] unless rule.delegate
167
+
168
+ element.send(rule.delegate).class.attributes[rule.to]
169
+ end
170
+
171
+ def attribute_value_for(element, rule)
172
+ return element.send(rule.to) unless rule.delegate
173
+
174
+ element.send(rule.delegate).send(rule.to)
175
+ end
57
176
 
58
177
  def namespace_attributes(xml_mapping)
59
178
  return {} unless xml_mapping.namespace_uri
@@ -70,7 +189,6 @@ module Lutaml
70
189
  :namespace_prefix,
71
190
  :parent_document
72
191
 
73
- # rubocop:disable Metrics/ParameterLists
74
192
  def initialize(
75
193
  name,
76
194
  attributes = {},
@@ -86,10 +204,9 @@ module Lutaml
86
204
  @text = text
87
205
  @parent_document = parent_document
88
206
  end
89
- # rubocop:enable Metrics/ParameterLists
90
207
 
91
208
  def name
92
- if namespace_prefix && namespaces[namespace_prefix]
209
+ if namespace_prefix
93
210
  "#{namespace_prefix}:#{@name}"
94
211
  else
95
212
  @name
@@ -144,6 +261,12 @@ module Lutaml
144
261
 
145
262
  n.first
146
263
  end
264
+
265
+ def order
266
+ children.each_with_object([]) do |child, arr|
267
+ arr << child.unprefixed_name
268
+ end
269
+ end
147
270
  end
148
271
 
149
272
  class Attribute
@@ -155,6 +278,14 @@ module Lutaml
155
278
  @namespace = namespace
156
279
  @namespace_prefix = namespace_prefix
157
280
  end
281
+
282
+ def unprefixed_name
283
+ if namespace_prefix
284
+ name.split(":").last
285
+ else
286
+ name
287
+ end
288
+ end
158
289
  end
159
290
  end
160
291
  end
@@ -4,16 +4,23 @@ require_relative "xml_mapping_rule"
4
4
  module Lutaml
5
5
  module Model
6
6
  class XmlMapping
7
- attr_reader :root_element, :namespace_uri, :namespace_prefix
7
+ attr_reader :root_element,
8
+ :namespace_uri,
9
+ :namespace_prefix,
10
+ :mixed_content
8
11
 
9
12
  def initialize
10
13
  @elements = []
11
14
  @attributes = []
12
15
  @content_mapping = nil
16
+ @mixed_content = false
13
17
  end
14
18
 
15
- def root(name)
19
+ alias mixed_content? mixed_content
20
+
21
+ def root(name, mixed: false)
16
22
  @root_element = name
23
+ @mixed_content = mixed
17
24
  end
18
25
 
19
26
  def prefixed_root
@@ -36,8 +43,10 @@ module Lutaml
36
43
  render_nil: false,
37
44
  with: {},
38
45
  delegate: nil,
39
- namespace: nil,
40
- prefix: nil
46
+ namespace: (namespace_set = false
47
+ nil),
48
+ prefix: nil,
49
+ mixed: false
41
50
  )
42
51
  @elements << XmlMappingRule.new(
43
52
  name,
@@ -47,6 +56,8 @@ module Lutaml
47
56
  delegate: delegate,
48
57
  namespace: namespace,
49
58
  prefix: prefix,
59
+ mixed_content: mixed,
60
+ namespace_set: namespace_set != false,
50
61
  )
51
62
  end
52
63
 
@@ -56,7 +67,8 @@ module Lutaml
56
67
  render_nil: false,
57
68
  with: {},
58
69
  delegate: nil,
59
- namespace: nil,
70
+ namespace: (namespace_set = false
71
+ nil),
60
72
  prefix: nil
61
73
  )
62
74
  @attributes << XmlMappingRule.new(
@@ -67,17 +79,25 @@ module Lutaml
67
79
  delegate: delegate,
68
80
  namespace: namespace,
69
81
  prefix: prefix,
82
+ namespace_set: namespace_set != false,
70
83
  )
71
84
  end
72
85
  # rubocop:enable Metrics/ParameterLists
73
86
 
74
- def map_content(to:, render_nil: false, with: {}, delegate: nil)
87
+ def map_content(
88
+ to:,
89
+ render_nil: false,
90
+ with: {},
91
+ delegate: nil,
92
+ mixed: false
93
+ )
75
94
  @content_mapping = XmlMappingRule.new(
76
95
  nil,
77
96
  to: to,
78
97
  render_nil: render_nil,
79
98
  with: with,
80
99
  delegate: delegate,
100
+ mixed_content: mixed,
81
101
  )
82
102
  end
83
103
 
@@ -108,6 +128,16 @@ module Lutaml
108
128
  name == rule.to
109
129
  end
110
130
  end
131
+
132
+ def find_by_name(name)
133
+ if name.to_s == "text"
134
+ content_mapping
135
+ else
136
+ mappings.detect do |rule|
137
+ rule.name == name.to_s || rule.name == name.to_sym
138
+ end
139
+ end
140
+ end
111
141
  end
112
142
  end
113
143
  end
@@ -6,8 +6,6 @@ module Lutaml
6
6
  class XmlMappingRule < MappingRule
7
7
  attr_reader :namespace, :prefix
8
8
 
9
- # rubocop:disable Metrics/MethodLength
10
- # rubocop:disable Metrics/ParameterLists
11
9
  def initialize(
12
10
  name,
13
11
  to:,
@@ -15,14 +13,18 @@ module Lutaml
15
13
  with: {},
16
14
  delegate: nil,
17
15
  namespace: nil,
18
- prefix: nil
16
+ prefix: nil,
17
+ mixed_content: false,
18
+ namespace_set: false
19
19
  )
20
20
  super(
21
21
  name,
22
22
  to: to,
23
23
  render_nil: render_nil,
24
24
  with: with,
25
- delegate: delegate
25
+ delegate: delegate,
26
+ mixed_content: mixed_content,
27
+ namespace_set: namespace_set
26
28
  )
27
29
 
28
30
  @namespace = if namespace.to_s == "inherit"
@@ -33,8 +35,6 @@ module Lutaml
33
35
  end
34
36
  @prefix = prefix
35
37
  end
36
- # rubocop:enable Metrics/MethodLength
37
- # rubocop:enable Metrics/ParameterLists
38
38
  end
39
39
  end
40
40
  end
@@ -4,9 +4,17 @@ require "yaml"
4
4
  module Lutaml
5
5
  module Model
6
6
  module YamlAdapter
7
- module Standard
8
- def self.to_yaml(model, *args)
9
- YAML.dump(model.hash_representation(:yaml), *args)
7
+ class Standard
8
+ def initialize(attributes)
9
+ @attributes = attributes
10
+ end
11
+
12
+ def to_yaml(options = {})
13
+ YAML.dump(@attributes, options)
14
+ end
15
+
16
+ def self.to_yaml(attributes, *args)
17
+ new(attributes).to_yaml(*args)
10
18
  end
11
19
 
12
20
  def self.from_yaml(yaml, klass)
data/lib/lutaml/model.rb CHANGED
@@ -12,9 +12,16 @@ require_relative "model/json_adapter"
12
12
  require_relative "model/yaml_adapter"
13
13
  require_relative "model/xml_adapter"
14
14
  require_relative "model/toml_adapter"
15
+ require_relative "model/error"
15
16
 
16
17
  module Lutaml
17
18
  module Model
19
+ # Error for passing incorrect model type
20
+ #
21
+ # @api private
22
+ class IncorrectModelError < StandardError
23
+ end
24
+
18
25
  class BaseModel < Serializable
19
26
  end
20
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-10 00:00:00.000000000 Z
11
+ date: 2024-08-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'LutaML creating data models in Ruby
14
14
 
@@ -24,6 +24,7 @@ files:
24
24
  - ".gitignore"
25
25
  - ".rspec"
26
26
  - ".rubocop.yml"
27
+ - ".rubocop_todo.yml"
27
28
  - CODE_OF_CONDUCT.md
28
29
  - Gemfile
29
30
  - README.adoc
@@ -33,11 +34,14 @@ files:
33
34
  - lib/lutaml/model.rb
34
35
  - lib/lutaml/model/attribute.rb
35
36
  - lib/lutaml/model/config.rb
37
+ - lib/lutaml/model/error.rb
38
+ - lib/lutaml/model/error/invalid_value_error.rb
36
39
  - lib/lutaml/model/json_adapter.rb
37
40
  - lib/lutaml/model/json_adapter/multi_json.rb
38
41
  - lib/lutaml/model/json_adapter/standard.rb
39
42
  - lib/lutaml/model/key_value_mapping.rb
40
43
  - lib/lutaml/model/key_value_mapping_rule.rb
44
+ - lib/lutaml/model/mapping_hash.rb
41
45
  - lib/lutaml/model/mapping_rule.rb
42
46
  - lib/lutaml/model/schema.rb
43
47
  - lib/lutaml/model/schema/json_schema.rb