lutaml-model 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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