lutaml-model 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -5
  3. data/.rubocop_todo.yml +21 -101
  4. data/Gemfile +3 -18
  5. data/README.adoc +145 -6
  6. data/lib/lutaml/model/attribute.rb +15 -2
  7. data/lib/lutaml/model/config.rb +0 -1
  8. data/lib/lutaml/model/json_adapter/json_document.rb +20 -0
  9. data/lib/lutaml/model/json_adapter/json_object.rb +28 -0
  10. data/lib/lutaml/model/json_adapter/{multi_json.rb → multi_json_adapter.rb} +2 -3
  11. data/lib/lutaml/model/json_adapter/{standard.rb → standard_json_adapter.rb} +2 -3
  12. data/lib/lutaml/model/json_adapter.rb +1 -31
  13. data/lib/lutaml/model/key_value_mapping.rb +0 -1
  14. data/lib/lutaml/model/key_value_mapping_rule.rb +0 -1
  15. data/lib/lutaml/model/mapping_hash.rb +0 -2
  16. data/lib/lutaml/model/mapping_rule.rb +0 -1
  17. data/lib/lutaml/model/schema/json_schema.rb +0 -1
  18. data/lib/lutaml/model/schema/relaxng_schema.rb +0 -1
  19. data/lib/lutaml/model/schema/xsd_schema.rb +0 -1
  20. data/lib/lutaml/model/schema/yaml_schema.rb +0 -1
  21. data/lib/lutaml/model/schema.rb +0 -1
  22. data/lib/lutaml/model/serializable.rb +0 -1
  23. data/lib/lutaml/model/serialize.rb +22 -4
  24. data/lib/lutaml/model/toml_adapter/toml_document.rb +20 -0
  25. data/lib/lutaml/model/toml_adapter/toml_object.rb +28 -0
  26. data/lib/lutaml/model/toml_adapter/toml_rb_adapter.rb +2 -3
  27. data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +2 -3
  28. data/lib/lutaml/model/toml_adapter.rb +0 -31
  29. data/lib/lutaml/model/type/date_time.rb +20 -0
  30. data/lib/lutaml/model/type/json.rb +34 -0
  31. data/lib/lutaml/model/type/time_without_date.rb +4 -3
  32. data/lib/lutaml/model/type.rb +61 -124
  33. data/lib/lutaml/model/version.rb +1 -1
  34. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +9 -8
  35. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +4 -5
  36. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +14 -13
  37. data/lib/lutaml/model/xml_adapter/xml_attribute.rb +27 -0
  38. data/lib/lutaml/model/xml_adapter/xml_document.rb +185 -0
  39. data/lib/lutaml/model/xml_adapter/xml_element.rb +94 -0
  40. data/lib/lutaml/model/xml_adapter/xml_namespace.rb +49 -0
  41. data/lib/lutaml/model/xml_adapter.rb +0 -285
  42. data/lib/lutaml/model/xml_mapping.rb +7 -7
  43. data/lib/lutaml/model/xml_mapping_rule.rb +3 -4
  44. data/lib/lutaml/model/yaml_adapter/standard_yaml_adapter.rb +34 -0
  45. data/lib/lutaml/model/yaml_adapter/yaml_document.rb +20 -0
  46. data/lib/lutaml/model/yaml_adapter/yaml_object.rb +28 -0
  47. data/lib/lutaml/model/yaml_adapter.rb +1 -27
  48. data/lib/lutaml/model.rb +0 -5
  49. metadata +17 -5
  50. data/lib/lutaml/model/xml_namespace.rb +0 -47
@@ -1,292 +1,7 @@
1
- # lib/lutaml/model/xml_adapter.rb
2
-
3
- require_relative "xml_namespace"
4
- require_relative "mapping_hash"
5
-
6
1
  module Lutaml
7
2
  module Model
8
3
  module XmlAdapter
9
4
  XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace".freeze
10
-
11
- class Document
12
- attr_reader :root
13
-
14
- def initialize(root)
15
- @root = root
16
- end
17
-
18
- def self.parse(xml)
19
- raise NotImplementedError, "Subclasses must implement `parse`."
20
- end
21
-
22
- def children
23
- @root.children
24
- end
25
-
26
- def declaration(options)
27
- version = "1.0"
28
- version = options[:declaration] if options[:declaration].is_a?(String)
29
-
30
- encoding = options[:encoding] ? "UTF-8" : nil
31
- encoding = options[:encoding] if options[:encoding].is_a?(String)
32
-
33
- declaration = "<?xml version=\"#{version}\""
34
- declaration += " encoding=\"#{encoding}\"" if encoding
35
- declaration += "?>\n"
36
- declaration
37
- end
38
-
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
-
146
- def build_attributes(element, xml_mapping)
147
- attrs = namespace_attributes(xml_mapping)
148
-
149
- xml_mapping.attributes.each_with_object(attrs) do |mapping_rule, hash|
150
- if mapping_rule.namespace
151
- hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
152
- end
153
-
154
- hash[mapping_rule.prefixed_name] = element.send(mapping_rule.to)
155
- end
156
-
157
- xml_mapping.elements.each_with_object(attrs) do |mapping_rule, hash|
158
- if mapping_rule.namespace
159
- hash["xmlns:#{mapping_rule.prefix}"] = mapping_rule.namespace
160
- end
161
- end
162
- end
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
176
-
177
- def namespace_attributes(xml_mapping)
178
- return {} unless xml_mapping.namespace_uri
179
-
180
- key = ["xmlns", xml_mapping.namespace_prefix].compact.join(":")
181
- { key => xml_mapping.namespace_uri }
182
- end
183
- end
184
-
185
- class Element
186
- attr_reader :attributes,
187
- :children,
188
- :text,
189
- :namespace_prefix,
190
- :parent_document
191
-
192
- def initialize(
193
- name,
194
- attributes = {},
195
- children = [],
196
- text = nil,
197
- parent_document: nil,
198
- namespace_prefix: nil
199
- )
200
- @name = extract_name(name)
201
- @namespace_prefix = namespace_prefix || extract_namespace_prefix(name)
202
- @attributes = attributes # .map { |k, v| Attribute.new(k, v) }
203
- @children = children
204
- @text = text
205
- @parent_document = parent_document
206
- end
207
-
208
- def name
209
- if namespace_prefix
210
- "#{namespace_prefix}:#{@name}"
211
- else
212
- @name
213
- end
214
- end
215
-
216
- def unprefixed_name
217
- @name
218
- end
219
-
220
- def document
221
- Document.new(self)
222
- end
223
-
224
- def namespaces
225
- @namespaces || @parent_document&.namespaces || {}
226
- end
227
-
228
- def own_namespaces
229
- @namespaces || {}
230
- end
231
-
232
- def namespace
233
- return default_namespace unless namespace_prefix
234
-
235
- namespaces[namespace_prefix]
236
- end
237
-
238
- def attribute_is_namespace?(name)
239
- name.to_s.start_with?("xmlns")
240
- end
241
-
242
- def add_namespace(namespace)
243
- @namespaces ||= {}
244
- @namespaces[namespace.prefix] = namespace
245
- end
246
-
247
- def default_namespace
248
- namespaces[nil] || @parent_document&.namespaces&.dig(nil)
249
- end
250
-
251
- def extract_name(name)
252
- n = name.to_s.split(":")
253
- return name if n.length <= 1
254
-
255
- n[1..].join(":")
256
- end
257
-
258
- def extract_namespace_prefix(name)
259
- n = name.to_s.split(":")
260
- return if n.length <= 1
261
-
262
- n.first
263
- end
264
-
265
- def order
266
- children.each_with_object([]) do |child, arr|
267
- arr << child.unprefixed_name
268
- end
269
- end
270
- end
271
-
272
- class Attribute
273
- attr_reader :name, :value, :namespace, :namespace_prefix
274
-
275
- def initialize(name, value, namespace: nil, namespace_prefix: nil)
276
- @name = name
277
- @value = value
278
- @namespace = namespace
279
- @namespace_prefix = namespace_prefix
280
- end
281
-
282
- def unprefixed_name
283
- if namespace_prefix
284
- name.split(":").last
285
- else
286
- name
287
- end
288
- end
289
- end
290
5
  end
291
6
  end
292
7
  end
@@ -1,4 +1,3 @@
1
- # lib/lutaml/model/xml_mapping.rb
2
1
  require_relative "xml_mapping_rule"
3
2
 
4
3
  module Lutaml
@@ -10,8 +9,8 @@ module Lutaml
10
9
  :mixed_content
11
10
 
12
11
  def initialize
13
- @elements = []
14
- @attributes = []
12
+ @elements = {}
13
+ @attributes = {}
15
14
  @content_mapping = nil
16
15
  @mixed_content = false
17
16
  end
@@ -48,7 +47,7 @@ module Lutaml
48
47
  prefix: nil,
49
48
  mixed: false
50
49
  )
51
- @elements << XmlMappingRule.new(
50
+ @elements[name] = XmlMappingRule.new(
52
51
  name,
53
52
  to: to,
54
53
  render_nil: render_nil,
@@ -71,7 +70,7 @@ module Lutaml
71
70
  nil),
72
71
  prefix: nil
73
72
  )
74
- @attributes << XmlMappingRule.new(
73
+ @attributes[name] = XmlMappingRule.new(
75
74
  name,
76
75
  to: to,
77
76
  render_nil: render_nil,
@@ -82,6 +81,7 @@ module Lutaml
82
81
  namespace_set: namespace_set != false,
83
82
  )
84
83
  end
84
+
85
85
  # rubocop:enable Metrics/ParameterLists
86
86
 
87
87
  def map_content(
@@ -102,11 +102,11 @@ module Lutaml
102
102
  end
103
103
 
104
104
  def elements
105
- @elements
105
+ @elements.values
106
106
  end
107
107
 
108
108
  def attributes
109
- @attributes
109
+ @attributes.values
110
110
  end
111
111
 
112
112
  def content_mapping
@@ -1,4 +1,3 @@
1
- # lib/lutaml/model/xml_mapping_rule.rb
2
1
  require_relative "mapping_rule"
3
2
 
4
3
  module Lutaml
@@ -24,12 +23,12 @@ module Lutaml
24
23
  with: with,
25
24
  delegate: delegate,
26
25
  mixed_content: mixed_content,
27
- namespace_set: namespace_set
26
+ namespace_set: namespace_set,
28
27
  )
29
28
 
30
29
  @namespace = if namespace.to_s == "inherit"
31
- # we are using inherit_namespace in xml builder by
32
- # default so no need to do anything here.
30
+ # we are using inherit_namespace in xml builder by
31
+ # default so no need to do anything here.
33
32
  else
34
33
  namespace
35
34
  end
@@ -0,0 +1,34 @@
1
+ require "yaml"
2
+ require_relative "yaml_document"
3
+
4
+ module Lutaml
5
+ module Model
6
+ module YamlAdapter
7
+ class StandardYamlAdapter < YamlDocument
8
+ def self.parse(yaml)
9
+ YAML.safe_load(
10
+ yaml,
11
+ permitted_classes: [Date, Time, DateTime, Symbol,
12
+ BigDecimal, Hash, Array],
13
+ )
14
+ end
15
+
16
+ def to_yaml(options = {})
17
+ YAML.dump(@attributes, options)
18
+ end
19
+
20
+ # TODO: Is this really needed?
21
+ def self.to_yaml(attributes, *args)
22
+ new(attributes).to_yaml(*args)
23
+ end
24
+
25
+ # TODO: Is this really needed?
26
+ def self.from_yaml(yaml, klass)
27
+ data = parse(yaml)
28
+ mapped_attrs = klass.send(:apply_mappings, data, :yaml)
29
+ klass.new(mapped_attrs)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "yaml_object"
4
+
5
+ module Lutaml
6
+ module Model
7
+ module YamlAdapter
8
+ # Base class for YAML documents
9
+ class YamlDocument < YamlObject
10
+ def self.parse(yaml)
11
+ raise NotImplementedError, "Subclasses must implement `parse`."
12
+ end
13
+
14
+ def to_yaml(*args)
15
+ raise NotImplementedError, "Subclasses must implement `to_yaml`."
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module YamlAdapter
6
+ # Base class for YAML objects
7
+ class YamlObject
8
+ attr_reader :attributes
9
+
10
+ def initialize(attributes = {})
11
+ @attributes = attributes
12
+ end
13
+
14
+ def [](key)
15
+ @attributes[key]
16
+ end
17
+
18
+ def []=(key, value)
19
+ @attributes[key] = value
20
+ end
21
+
22
+ def to_h
23
+ @attributes
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,34 +1,8 @@
1
- # lib/lutaml/model/yaml_adapter.rb
2
- require "yaml"
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Lutaml
5
4
  module Model
6
5
  module YamlAdapter
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)
18
- end
19
-
20
- def self.from_yaml(yaml, klass)
21
- data = parse(yaml)
22
- mapped_attrs = klass.send(:apply_mappings, data, :yaml)
23
- klass.new(mapped_attrs)
24
- end
25
-
26
- def self.parse(yaml)
27
- YAML.safe_load(yaml,
28
- permitted_classes: [Date, Time, DateTime, Symbol,
29
- BigDecimal, Hash, Array])
30
- end
31
- end
32
6
  end
33
7
  end
34
8
  end
data/lib/lutaml/model.rb CHANGED
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "model/version"
4
-
5
- # lib/lutaml/model.rb
6
- require "nokogiri"
7
- require "json"
8
- require "yaml"
9
4
  require_relative "model/type"
10
5
  require_relative "model/serializable"
11
6
  require_relative "model/json_adapter"
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.3.1
4
+ version: 0.3.3
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-08-13 00:00:00.000000000 Z
11
+ date: 2024-08-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'LutaML creating data models in Ruby
14
14
 
@@ -37,8 +37,10 @@ files:
37
37
  - lib/lutaml/model/error.rb
38
38
  - lib/lutaml/model/error/invalid_value_error.rb
39
39
  - lib/lutaml/model/json_adapter.rb
40
- - lib/lutaml/model/json_adapter/multi_json.rb
41
- - lib/lutaml/model/json_adapter/standard.rb
40
+ - lib/lutaml/model/json_adapter/json_document.rb
41
+ - lib/lutaml/model/json_adapter/json_object.rb
42
+ - lib/lutaml/model/json_adapter/multi_json_adapter.rb
43
+ - lib/lutaml/model/json_adapter/standard_json_adapter.rb
42
44
  - lib/lutaml/model/key_value_mapping.rb
43
45
  - lib/lutaml/model/key_value_mapping_rule.rb
44
46
  - lib/lutaml/model/mapping_hash.rb
@@ -51,19 +53,29 @@ files:
51
53
  - lib/lutaml/model/serializable.rb
52
54
  - lib/lutaml/model/serialize.rb
53
55
  - lib/lutaml/model/toml_adapter.rb
56
+ - lib/lutaml/model/toml_adapter/toml_document.rb
57
+ - lib/lutaml/model/toml_adapter/toml_object.rb
54
58
  - lib/lutaml/model/toml_adapter/toml_rb_adapter.rb
55
59
  - lib/lutaml/model/toml_adapter/tomlib_adapter.rb
56
60
  - lib/lutaml/model/type.rb
61
+ - lib/lutaml/model/type/date_time.rb
62
+ - lib/lutaml/model/type/json.rb
57
63
  - lib/lutaml/model/type/time_without_date.rb
58
64
  - lib/lutaml/model/version.rb
59
65
  - lib/lutaml/model/xml_adapter.rb
60
66
  - lib/lutaml/model/xml_adapter/nokogiri_adapter.rb
61
67
  - lib/lutaml/model/xml_adapter/oga_adapter.rb
62
68
  - lib/lutaml/model/xml_adapter/ox_adapter.rb
69
+ - lib/lutaml/model/xml_adapter/xml_attribute.rb
70
+ - lib/lutaml/model/xml_adapter/xml_document.rb
71
+ - lib/lutaml/model/xml_adapter/xml_element.rb
72
+ - lib/lutaml/model/xml_adapter/xml_namespace.rb
63
73
  - lib/lutaml/model/xml_mapping.rb
64
74
  - lib/lutaml/model/xml_mapping_rule.rb
65
- - lib/lutaml/model/xml_namespace.rb
66
75
  - lib/lutaml/model/yaml_adapter.rb
76
+ - lib/lutaml/model/yaml_adapter/standard_yaml_adapter.rb
77
+ - lib/lutaml/model/yaml_adapter/yaml_document.rb
78
+ - lib/lutaml/model/yaml_adapter/yaml_object.rb
67
79
  - lutaml-model.gemspec
68
80
  - sig/lutaml/model.rbs
69
81
  homepage: https://github.com/lutaml/lutaml-model
@@ -1,47 +0,0 @@
1
- # frozen_striing_literal: true
2
-
3
- module Lutaml
4
- module Model
5
- class XmlNamespace
6
- # Return name
7
- #
8
- # @return [String]
9
- #
10
- # @api private
11
- attr_accessor :uri
12
-
13
- # Return prefix
14
- #
15
- # @return [String]
16
- #
17
- # @api private
18
- attr_accessor :prefix
19
-
20
- # Initialize instance
21
- #
22
- # @param [String, nil] name
23
- # @param [String, nil] prefix
24
- #
25
- # @api private
26
- def initialize(uri = nil, prefix = nil)
27
- @uri = uri
28
- @prefix = normalize_prefix(prefix)
29
- end
30
-
31
- def normalize_prefix(prefix)
32
- normalized_prefix = prefix.to_s.gsub(/xmlns:?/, "")
33
- return if normalized_prefix.empty?
34
-
35
- normalized_prefix
36
- end
37
-
38
- def attr_name
39
- if prefix && !prefix.empty?
40
- "xmlns:#{prefix}"
41
- else
42
- "xmlns"
43
- end
44
- end
45
- end
46
- end
47
- end