lutaml-model 0.3.9 → 0.3.10
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +39 -21
- data/README.adoc +263 -6
- data/lib/lutaml/model/attribute.rb +114 -3
- data/lib/lutaml/model/error/collection_count_out_of_range_error.rb +29 -0
- data/lib/lutaml/model/error/validation_error.rb +21 -0
- data/lib/lutaml/model/error.rb +2 -0
- data/lib/lutaml/model/schema_location.rb +59 -0
- data/lib/lutaml/model/serialize.rb +49 -33
- data/lib/lutaml/model/validation.rb +24 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/xml_document.rb +17 -7
- data/lutaml-model.gemspec +1 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5140f93f22f4b05222edc408aeca50552082e447b71fddd724b34ba9e6b82d55
|
|
4
|
+
data.tar.gz: 0aa44a3c72b65cca0ed2b7411614d8cdb0c44b4e8293e183935cb45ba7818d7c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69e4d0d0a3a5bd19e11a43fd33e03566ca035d18cf948a0a2fc5abe5f880489e4a6ad347d8118a04c35c8c95be5b7eb29ca93d426643c7790ab045db2b34721c
|
|
7
|
+
data.tar.gz: df1699ba6647f53f97735d0986b92bf8f76d6bf44430117406100b257f5934ac4a7baa6a4243bb8384db277ecb975bf64efe2f1a16b293739b245150e800cb15
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2024-09-
|
|
3
|
+
# on 2024-09-10 23:53:08 UTC using RuboCop version 1.66.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count:
|
|
10
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
-
# Configuration parameters: Severity, Include.
|
|
12
|
-
# Include: **/*.gemspec
|
|
13
|
-
Gemspec/RequireMFA:
|
|
14
|
-
Exclude:
|
|
15
|
-
- 'lutaml-model.gemspec'
|
|
16
|
-
|
|
17
|
-
# Offense count: 62
|
|
9
|
+
# Offense count: 88
|
|
18
10
|
# This cop supports safe autocorrection (--autocorrect).
|
|
19
11
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
|
|
20
12
|
# URISchemes: http, https
|
|
21
13
|
Layout/LineLength:
|
|
22
14
|
Enabled: false
|
|
23
15
|
|
|
24
|
-
# Offense count:
|
|
16
|
+
# Offense count: 1
|
|
17
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
18
|
+
# Configuration parameters: AllowInHeredoc.
|
|
19
|
+
Layout/TrailingWhitespace:
|
|
20
|
+
Exclude:
|
|
21
|
+
- 'lib/lutaml/model/schema_location.rb'
|
|
22
|
+
|
|
23
|
+
# Offense count: 11
|
|
25
24
|
# Configuration parameters: AllowedMethods.
|
|
26
25
|
# AllowedMethods: enums
|
|
27
26
|
Lint/ConstantDefinitionInBlock:
|
|
@@ -30,12 +29,19 @@ Lint/ConstantDefinitionInBlock:
|
|
|
30
29
|
- 'spec/lutaml/model/schema/relaxng_schema_spec.rb'
|
|
31
30
|
- 'spec/lutaml/model/schema/xsd_schema_spec.rb'
|
|
32
31
|
- 'spec/lutaml/model/schema/yaml_schema_spec.rb'
|
|
32
|
+
- 'spec/lutaml/model/validation_spec.rb'
|
|
33
33
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
|
34
34
|
|
|
35
|
-
# Offense count:
|
|
35
|
+
# Offense count: 1
|
|
36
|
+
Lint/DuplicateMethods:
|
|
37
|
+
Exclude:
|
|
38
|
+
- 'lib/lutaml/model/attribute.rb'
|
|
39
|
+
|
|
40
|
+
# Offense count: 31
|
|
36
41
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
37
42
|
Metrics/AbcSize:
|
|
38
43
|
Exclude:
|
|
44
|
+
- 'lib/lutaml/model/attribute.rb'
|
|
39
45
|
- 'lib/lutaml/model/comparable_model.rb'
|
|
40
46
|
- 'lib/lutaml/model/schema/relaxng_schema.rb'
|
|
41
47
|
- 'lib/lutaml/model/schema/xsd_schema.rb'
|
|
@@ -51,7 +57,7 @@ Metrics/AbcSize:
|
|
|
51
57
|
Metrics/BlockLength:
|
|
52
58
|
Max: 42
|
|
53
59
|
|
|
54
|
-
# Offense count:
|
|
60
|
+
# Offense count: 25
|
|
55
61
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
56
62
|
Metrics/CyclomaticComplexity:
|
|
57
63
|
Exclude:
|
|
@@ -63,17 +69,17 @@ Metrics/CyclomaticComplexity:
|
|
|
63
69
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
|
64
70
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
|
65
71
|
|
|
66
|
-
# Offense count:
|
|
72
|
+
# Offense count: 39
|
|
67
73
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
68
74
|
Metrics/MethodLength:
|
|
69
|
-
Max:
|
|
75
|
+
Max: 49
|
|
70
76
|
|
|
71
77
|
# Offense count: 4
|
|
72
78
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
|
73
79
|
Metrics/ParameterLists:
|
|
74
80
|
Max: 9
|
|
75
81
|
|
|
76
|
-
# Offense count:
|
|
82
|
+
# Offense count: 21
|
|
77
83
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
78
84
|
Metrics/PerceivedComplexity:
|
|
79
85
|
Exclude:
|
|
@@ -94,7 +100,7 @@ RSpec/ContextWording:
|
|
|
94
100
|
- 'spec/lutaml/model/xml_adapter/ox_adapter_spec.rb'
|
|
95
101
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
|
96
102
|
|
|
97
|
-
# Offense count:
|
|
103
|
+
# Offense count: 101
|
|
98
104
|
# Configuration parameters: CountAsOne.
|
|
99
105
|
RSpec/ExampleLength:
|
|
100
106
|
Max: 57
|
|
@@ -105,13 +111,14 @@ RSpec/IndexedLet:
|
|
|
105
111
|
Exclude:
|
|
106
112
|
- 'spec/address_spec.rb'
|
|
107
113
|
|
|
108
|
-
# Offense count:
|
|
114
|
+
# Offense count: 19
|
|
109
115
|
RSpec/LeakyConstantDeclaration:
|
|
110
116
|
Exclude:
|
|
111
117
|
- 'spec/lutaml/model/schema/json_schema_spec.rb'
|
|
112
118
|
- 'spec/lutaml/model/schema/relaxng_schema_spec.rb'
|
|
113
119
|
- 'spec/lutaml/model/schema/xsd_schema_spec.rb'
|
|
114
120
|
- 'spec/lutaml/model/schema/yaml_schema_spec.rb'
|
|
121
|
+
- 'spec/lutaml/model/validation_spec.rb'
|
|
115
122
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
|
116
123
|
|
|
117
124
|
# Offense count: 4
|
|
@@ -122,23 +129,29 @@ RSpec/MultipleDescribes:
|
|
|
122
129
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
|
123
130
|
- 'spec/lutaml/model/xml_adapter_spec.rb'
|
|
124
131
|
|
|
125
|
-
# Offense count:
|
|
132
|
+
# Offense count: 88
|
|
126
133
|
RSpec/MultipleExpectations:
|
|
127
134
|
Max: 11
|
|
128
135
|
|
|
129
|
-
# Offense count:
|
|
136
|
+
# Offense count: 17
|
|
130
137
|
# Configuration parameters: AllowSubject.
|
|
131
138
|
RSpec/MultipleMemoizedHelpers:
|
|
132
139
|
Max: 9
|
|
133
140
|
|
|
134
|
-
# Offense count:
|
|
141
|
+
# Offense count: 7
|
|
135
142
|
RSpec/PendingWithoutReason:
|
|
136
143
|
Exclude:
|
|
137
144
|
- 'spec/lutaml/model/mixed_content_spec.rb'
|
|
145
|
+
- 'spec/lutaml/model/validation_spec.rb'
|
|
138
146
|
- 'spec/lutaml/model/xml_adapter/oga_adapter_spec.rb'
|
|
139
147
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
|
140
148
|
- 'spec/lutaml/model/xml_adapter_spec.rb'
|
|
141
149
|
|
|
150
|
+
# Offense count: 2
|
|
151
|
+
RSpec/RepeatedExampleGroupDescription:
|
|
152
|
+
Exclude:
|
|
153
|
+
- 'spec/lutaml/model/collection_spec.rb'
|
|
154
|
+
|
|
142
155
|
# Offense count: 1
|
|
143
156
|
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
|
|
144
157
|
# Include: **/*_spec.rb
|
|
@@ -152,6 +165,11 @@ Security/CompoundHash:
|
|
|
152
165
|
Exclude:
|
|
153
166
|
- 'lib/lutaml/model/comparable_model.rb'
|
|
154
167
|
|
|
168
|
+
# Offense count: 1
|
|
169
|
+
Style/MissingRespondToMissing:
|
|
170
|
+
Exclude:
|
|
171
|
+
- 'lib/lutaml/model/serialize.rb'
|
|
172
|
+
|
|
155
173
|
# Offense count: 1
|
|
156
174
|
# Configuration parameters: AllowedMethods.
|
|
157
175
|
# AllowedMethods: respond_to_missing?
|
data/README.adoc
CHANGED
|
@@ -204,11 +204,45 @@ end
|
|
|
204
204
|
Define attributes as collections (arrays or hashes) to store multiple values
|
|
205
205
|
using the `collection` option.
|
|
206
206
|
|
|
207
|
+
`collection` can be set to:
|
|
208
|
+
|
|
209
|
+
`true`:::
|
|
210
|
+
The attribute contains an unbounded collection of objects of the declared class.
|
|
211
|
+
|
|
212
|
+
`{min}..{max}`:::
|
|
213
|
+
The attribute contains a collection of objects of the declared class with a
|
|
214
|
+
count within the specified range.
|
|
215
|
+
If the number of objects is out of this numbered range,
|
|
216
|
+
`CollectionCountOutOfRangeError` will be raised.
|
|
217
|
+
+
|
|
218
|
+
[example]
|
|
219
|
+
====
|
|
220
|
+
When set to `0..1`, it means that the attribute is optional, it could be empty
|
|
221
|
+
or contain one object of the declared class.
|
|
222
|
+
====
|
|
223
|
+
+
|
|
224
|
+
[example]
|
|
225
|
+
====
|
|
226
|
+
When set to `1..` (equivalent to `1..Infinity`), it means that the
|
|
227
|
+
attribute must contain at least one object of the declared class and can contain
|
|
228
|
+
any number of objects.
|
|
229
|
+
====
|
|
230
|
+
+
|
|
231
|
+
[example]
|
|
232
|
+
====
|
|
233
|
+
When set to 5..10` means that there is a minimum of 5 and a maximum of 10
|
|
234
|
+
objects of the declared class. If the count of values for the attribute is less
|
|
235
|
+
then 5 or greater then 10, the `CollectionCountOutOfRangeError` will be raised.
|
|
236
|
+
====
|
|
237
|
+
|
|
238
|
+
|
|
207
239
|
Syntax:
|
|
208
240
|
|
|
209
241
|
[source,ruby]
|
|
210
242
|
----
|
|
211
243
|
attribute :name_of_attribute, Type, collection: true
|
|
244
|
+
attribute :name_of_attribute, Type, collection: {min}..{max}
|
|
245
|
+
attribute :name_of_attribute, Type, collection: {min}..
|
|
212
246
|
----
|
|
213
247
|
|
|
214
248
|
.Using the `collection` option to define a collection attribute
|
|
@@ -219,18 +253,27 @@ attribute :name_of_attribute, Type, collection: true
|
|
|
219
253
|
class Studio < Lutaml::Model::Serializable
|
|
220
254
|
attribute :location, :string
|
|
221
255
|
attribute :potters, :string, collection: true
|
|
256
|
+
attribute :address, :string, collection: 1..2
|
|
257
|
+
attribute :hobbies, :string, collection: 0..
|
|
222
258
|
end
|
|
223
259
|
----
|
|
224
260
|
|
|
225
261
|
[source,ruby]
|
|
226
262
|
----
|
|
227
|
-
> Studio.new
|
|
263
|
+
> Studio.new
|
|
264
|
+
> # address count is `0`, must be between 1 and 2 (Lutaml::Model::CollectionCountOutOfRangeError)
|
|
265
|
+
> Studio.new({ address: ["address 1", "address 2", "address 3"] })
|
|
266
|
+
> # address count is `3`, must be between 1 and 2 (Lutaml::Model::CollectionCountOutOfRangeError)
|
|
267
|
+
> Studio.new({ address: ["address 1"] }).potters
|
|
228
268
|
> # []
|
|
229
|
-
> Studio.new(
|
|
269
|
+
> Studio.new({ address: ["address 1"] }).address
|
|
270
|
+
> # ["address 1"]
|
|
271
|
+
> Studio.new(address: ["address 1"], potters: ['John Doe', 'Jane Doe']).potters
|
|
230
272
|
> # ['John Doe', 'Jane Doe']
|
|
231
273
|
----
|
|
232
274
|
====
|
|
233
275
|
|
|
276
|
+
|
|
234
277
|
[[attribute-enumeration]]
|
|
235
278
|
=== Attribute as an enumeration
|
|
236
279
|
|
|
@@ -947,6 +990,125 @@ end
|
|
|
947
990
|
TODO: How to create mixed content from `#new`?
|
|
948
991
|
|
|
949
992
|
|
|
993
|
+
==== Automatic support of `xsi:schemaLocation`
|
|
994
|
+
|
|
995
|
+
The
|
|
996
|
+
https://www.w3.org/TR/xmlschema-1/#xsi_schemaLocation[W3C "XMLSchema-instance"]
|
|
997
|
+
namespace describes a number of attributes that can be used to control the
|
|
998
|
+
behavior of XML processors. One of these attributes is `xsi:schemaLocation`.
|
|
999
|
+
|
|
1000
|
+
The `xsi:schemaLocation` attribute locates schemas for elements and attributes
|
|
1001
|
+
that are in a specified namespace. Its value consists of pairs of a namespace
|
|
1002
|
+
URI followed by a relative or absolute URL where the schema for that namespace
|
|
1003
|
+
can be found.
|
|
1004
|
+
|
|
1005
|
+
Usage of `xsi:schemaLocation` in an XML element depends on the declaration of
|
|
1006
|
+
the XML namespace of `xsi`, i.e.
|
|
1007
|
+
`xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`. Without this namespace
|
|
1008
|
+
LutaML will not be able to serialize the `xsi:schemaLocation` attribute.
|
|
1009
|
+
|
|
1010
|
+
NOTE: It is most commonly attached to the root element but can appear further
|
|
1011
|
+
down the tree.
|
|
1012
|
+
|
|
1013
|
+
The following snippet shows how `xsi:schemaLocation` is used in an XML document:
|
|
1014
|
+
|
|
1015
|
+
[source,xml]
|
|
1016
|
+
----
|
|
1017
|
+
<cera:Ceramic
|
|
1018
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
1019
|
+
xmlns:cera="http://example.com/ceramic"
|
|
1020
|
+
xmlns:clr='http://example.com/color'
|
|
1021
|
+
xsi:schemaLocation=
|
|
1022
|
+
"http://example.com/ceramic http://example.com/ceramic.xsd
|
|
1023
|
+
http://example.com/color http://example.com/color.xsd"
|
|
1024
|
+
clr:color="navy-blue">
|
|
1025
|
+
<cera:Type>Porcelain</cera:Type>
|
|
1026
|
+
<Glaze>Clear</Glaze>
|
|
1027
|
+
</cera:Ceramic>
|
|
1028
|
+
----
|
|
1029
|
+
|
|
1030
|
+
LutaML::Model supports the `xsi:schemaLocation` attribute in all XML
|
|
1031
|
+
serializations by default, through the `schema_location` attribute on the model
|
|
1032
|
+
instance object.
|
|
1033
|
+
|
|
1034
|
+
.Retrieving and setting the `xsi:schemaLocation` attribute in XML serialization
|
|
1035
|
+
[example]
|
|
1036
|
+
====
|
|
1037
|
+
In this example, the `xsi:schemaLocation` attribute will be automatically
|
|
1038
|
+
supplied without the explicit need to define in the model, and allows for
|
|
1039
|
+
round-trip serialization.
|
|
1040
|
+
|
|
1041
|
+
[source,ruby]
|
|
1042
|
+
----
|
|
1043
|
+
class Ceramic < Lutaml::Model::Serializable
|
|
1044
|
+
attribute :type, :string
|
|
1045
|
+
attribute :glaze, :string
|
|
1046
|
+
attribute :color, :string
|
|
1047
|
+
|
|
1048
|
+
xml do
|
|
1049
|
+
root 'Ceramic'
|
|
1050
|
+
namespace 'http://example.com/ceramic', 'cera'
|
|
1051
|
+
map_element 'Type', to: :type, namespace: :inherit
|
|
1052
|
+
map_element 'Glaze', to: :glaze
|
|
1053
|
+
map_attribute 'color', to: :color, namespace: 'http://example.com/color', prefix: 'clr'
|
|
1054
|
+
end
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
xml_content = <<~HERE
|
|
1058
|
+
<cera:Ceramic
|
|
1059
|
+
xmlns:cera="http://example.com/ceramic"
|
|
1060
|
+
xmlns:clr="http://example.com/color"
|
|
1061
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
1062
|
+
clr:color="navy-blue"
|
|
1063
|
+
xsi:schemaLocation="
|
|
1064
|
+
http://example.com/ceramic http://example.com/ceramic.xsd
|
|
1065
|
+
http://example.com/color http://example.com/color.xsd
|
|
1066
|
+
">
|
|
1067
|
+
<cera:Type>Porcelain</cera:Type>
|
|
1068
|
+
<Glaze>Clear</Glaze>
|
|
1069
|
+
</cera:Ceramic>
|
|
1070
|
+
HERE
|
|
1071
|
+
----
|
|
1072
|
+
|
|
1073
|
+
[source,ruby]
|
|
1074
|
+
----
|
|
1075
|
+
> c = Ceramic.from_xml(xml_content)
|
|
1076
|
+
=>
|
|
1077
|
+
#<Ceramic:0x00000001222bdd60
|
|
1078
|
+
...
|
|
1079
|
+
> schema_loc = c.schema_location
|
|
1080
|
+
#<Lutaml::Model::SchemaLocation:0x0000000122773760
|
|
1081
|
+
...
|
|
1082
|
+
> schema_loc
|
|
1083
|
+
=>
|
|
1084
|
+
#<Lutaml::Model::SchemaLocation:0x0000000122773760
|
|
1085
|
+
@namespace="http://www.w3.org/2001/XMLSchema-instance",
|
|
1086
|
+
@original_schema_location="http://example.com/ceramic http://example.com/ceramic.xsd http://example.com/color http://example.com/color.xsd",
|
|
1087
|
+
@prefix="xsi",
|
|
1088
|
+
@schema_location=
|
|
1089
|
+
[#<Lutaml::Model::Location:0x00000001222bd018 @location="http://example.com/ceramic.xsd", @namespace="http://example.com/ceramic">,
|
|
1090
|
+
#<Lutaml::Model::Location:0x00000001222bcfc8 @location="http://example.com/color.xsd", @namespace="http://example.com/color">]>
|
|
1091
|
+
> new_c = Ceramic.new(type: "Porcelain", glaze: "Clear", color: "navy-blue", schema_location: schema_loc).to_xml
|
|
1092
|
+
> puts new_c
|
|
1093
|
+
# <cera:Ceramic
|
|
1094
|
+
# xmlns:cera="http://example.com/ceramic"
|
|
1095
|
+
# xmlns:clr="http://example.com/color"
|
|
1096
|
+
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
1097
|
+
# clr:color="navy-blue"
|
|
1098
|
+
# xsi:schemaLocation="
|
|
1099
|
+
# http://example.com/ceramic http://example.com/ceramic.xsd
|
|
1100
|
+
# http://example.com/color http://example.com/color.xsd
|
|
1101
|
+
# ">
|
|
1102
|
+
# <cera:Type>Porcelain</cera:Type>
|
|
1103
|
+
# <cera:Glaze>Clear</cera:Glaze>
|
|
1104
|
+
# </cera:Ceramic>
|
|
1105
|
+
----
|
|
1106
|
+
====
|
|
1107
|
+
|
|
1108
|
+
NOTE: For details on `xsi:schemaLocation`, please refer to the
|
|
1109
|
+
https://www.w3.org/TR/xmlschema-1/#xsi_schemaLocation[W3C XML standard].
|
|
1110
|
+
|
|
1111
|
+
|
|
950
1112
|
|
|
951
1113
|
=== Key value data models
|
|
952
1114
|
|
|
@@ -1333,12 +1495,12 @@ class CustomCeramic < Lutaml::Model::Serializable
|
|
|
1333
1495
|
map 'size', to: :size
|
|
1334
1496
|
end
|
|
1335
1497
|
|
|
1336
|
-
def name_to_json(model,
|
|
1337
|
-
doc["name"] = "Masterpiece: #{
|
|
1498
|
+
def name_to_json(model, doc)
|
|
1499
|
+
doc["name"] = "Masterpiece: #{model.name}"
|
|
1338
1500
|
end
|
|
1339
1501
|
|
|
1340
|
-
def name_from_json(model,
|
|
1341
|
-
model.name = value.sub(/^
|
|
1502
|
+
def name_from_json(model, value)
|
|
1503
|
+
model.name = value.sub(/^Masterpiece: /, '')
|
|
1342
1504
|
end
|
|
1343
1505
|
end
|
|
1344
1506
|
----
|
|
@@ -1547,6 +1709,101 @@ In this example:
|
|
|
1547
1709
|
====
|
|
1548
1710
|
|
|
1549
1711
|
|
|
1712
|
+
== Validation
|
|
1713
|
+
|
|
1714
|
+
=== General
|
|
1715
|
+
|
|
1716
|
+
Lutaml::Model provides a way to validate data models using the `validate` and
|
|
1717
|
+
`validate!` methods.
|
|
1718
|
+
|
|
1719
|
+
* The `validate` method sets an `errors` array in the model instance that
|
|
1720
|
+
contains all the validation errors. This method is used for checking the
|
|
1721
|
+
validity of the model silently.
|
|
1722
|
+
|
|
1723
|
+
* The `validate!` method raises a `Lutaml::Model::ValidationError` that contains
|
|
1724
|
+
all the validation errors. This method is used for forceful validation of the
|
|
1725
|
+
model through raising an error.
|
|
1726
|
+
|
|
1727
|
+
Lutaml::Model supports the following validation methods:
|
|
1728
|
+
|
|
1729
|
+
* `collection`:: Validates collection size range.
|
|
1730
|
+
* `values`:: Validates the value of an attribute from a set of fixed values.
|
|
1731
|
+
|
|
1732
|
+
[example]
|
|
1733
|
+
====
|
|
1734
|
+
The following class will validate the `degree_settings` attribute to ensure that
|
|
1735
|
+
it has at least one element and that the `description` attribute is one of the
|
|
1736
|
+
values in the set `[one, two, three]`.
|
|
1737
|
+
|
|
1738
|
+
[source,ruby]
|
|
1739
|
+
----
|
|
1740
|
+
class Klin < Lutaml::Model::Serializable
|
|
1741
|
+
attribute :name, :string
|
|
1742
|
+
attribute :degree_settings, :integer, collection: (1..)
|
|
1743
|
+
attribute :description, :string, values: %w[one two three]
|
|
1744
|
+
|
|
1745
|
+
xml do
|
|
1746
|
+
map_element 'name', to: :name
|
|
1747
|
+
map_attribute 'degree_settings', to: :degree_settings
|
|
1748
|
+
end
|
|
1749
|
+
end
|
|
1750
|
+
|
|
1751
|
+
klin = Klin.new(name: "Klin", degree_settings: [100, 200, 300], description: "one")
|
|
1752
|
+
klin.validate
|
|
1753
|
+
# => []
|
|
1754
|
+
|
|
1755
|
+
klin = Klin.new(name: "Klin", degree_settings: [], description: "four")
|
|
1756
|
+
klin.validate
|
|
1757
|
+
# => [
|
|
1758
|
+
# #<Lutaml::Model::CollectionSizeError: degree_settings must have at least 1 element>,
|
|
1759
|
+
# #<Lutaml::Model::ValueError: description must be one of [one, two, three]>
|
|
1760
|
+
# ]
|
|
1761
|
+
|
|
1762
|
+
e = klin.validate!
|
|
1763
|
+
# => Lutaml::Model::ValidationError: [
|
|
1764
|
+
# degree_settings must have at least 1 element,
|
|
1765
|
+
# description must be one of [one, two, three]
|
|
1766
|
+
# ]
|
|
1767
|
+
e.errors
|
|
1768
|
+
# => [
|
|
1769
|
+
# #<Lutaml::Model::CollectionSizeError: degree_settings must have at least 1 element>,
|
|
1770
|
+
# #<Lutaml::Model::ValueError: description must be one of [one, two, three]>
|
|
1771
|
+
# ]
|
|
1772
|
+
----
|
|
1773
|
+
====
|
|
1774
|
+
|
|
1775
|
+
=== Custom validation
|
|
1776
|
+
|
|
1777
|
+
To add custom validation, override the `validate` method in the model class.
|
|
1778
|
+
Additional errors should be added to the `errors` array.
|
|
1779
|
+
|
|
1780
|
+
[example]
|
|
1781
|
+
====
|
|
1782
|
+
The following class validates the `degree_settings` attribute when the `type` is
|
|
1783
|
+
`glass` to ensure that the value is less than 1300.
|
|
1784
|
+
|
|
1785
|
+
[source,ruby]
|
|
1786
|
+
----
|
|
1787
|
+
class Klin < Lutaml::Model::Serializable
|
|
1788
|
+
attribute :name, :string
|
|
1789
|
+
attribute :type, :string, values: %w[glass ceramic]
|
|
1790
|
+
attribute :degree_settings, :integer, collection: (1..)
|
|
1791
|
+
|
|
1792
|
+
def validate
|
|
1793
|
+
errors = super
|
|
1794
|
+
if type == "glass" && degree_settings.any? { |d| d > 1300 }
|
|
1795
|
+
errors << Lutaml::Model::Error.new("Degree settings for glass must be less than 1300")
|
|
1796
|
+
end
|
|
1797
|
+
end
|
|
1798
|
+
end
|
|
1799
|
+
|
|
1800
|
+
klin = Klin.new(name: "Klin", type: "glass", degree_settings: [100, 200, 1400])
|
|
1801
|
+
klin.validate
|
|
1802
|
+
# => [#<Lutaml::Model::Error: Degree settings for glass must be less than 1300>]
|
|
1803
|
+
----
|
|
1804
|
+
====
|
|
1805
|
+
|
|
1806
|
+
|
|
1550
1807
|
== Adapters
|
|
1551
1808
|
|
|
1552
1809
|
=== General
|
|
@@ -6,11 +6,11 @@ module Lutaml
|
|
|
6
6
|
def initialize(name, type, options = {})
|
|
7
7
|
@name = name
|
|
8
8
|
@type = cast_type(type)
|
|
9
|
-
|
|
10
9
|
@options = options
|
|
11
10
|
|
|
12
|
-
if collection?
|
|
13
|
-
|
|
11
|
+
if collection?
|
|
12
|
+
validate_collection_range
|
|
13
|
+
@options[:default] = -> { [] } unless options[:default]
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -31,6 +31,10 @@ module Lutaml
|
|
|
31
31
|
options[:collection] || false
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
def singular?
|
|
35
|
+
!collection?
|
|
36
|
+
end
|
|
37
|
+
|
|
34
38
|
def default
|
|
35
39
|
return options[:default].call if options[:default].is_a?(Proc)
|
|
36
40
|
|
|
@@ -41,6 +45,113 @@ module Lutaml
|
|
|
41
45
|
options.fetch(:render_nil, false)
|
|
42
46
|
end
|
|
43
47
|
|
|
48
|
+
def enum_values
|
|
49
|
+
@options.key?(:values) ? @options[:values] : []
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Check if the value to be assigned is valid for the attribute
|
|
53
|
+
#
|
|
54
|
+
# Currently there are 2 validations
|
|
55
|
+
# 1. Value should be from the values list if they are defined
|
|
56
|
+
# e.g values: ["foo", "bar"] is set then any other value for this
|
|
57
|
+
# attribute will raise `Lutaml::Model::InvalidValueError`
|
|
58
|
+
#
|
|
59
|
+
# 2. Value count should be between the collection range if defined
|
|
60
|
+
# e.g if collection: 0..5 is set then the value greater then 5
|
|
61
|
+
# will raise `Lutaml::Model::CollectionCountOutOfRangeError`
|
|
62
|
+
def validate_value!(value)
|
|
63
|
+
valid_value!(value)
|
|
64
|
+
valid_collection!(value)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def valid_value!(value)
|
|
68
|
+
return true if value.nil? && !collection?
|
|
69
|
+
return true if enum_values.empty?
|
|
70
|
+
|
|
71
|
+
unless valid_value?(value)
|
|
72
|
+
raise Lutaml::Model::InvalidValueError.new(name, value, enum_values)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def valid_value?(value)
|
|
79
|
+
return true unless options[:values]
|
|
80
|
+
|
|
81
|
+
options[:values].include?(value)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def validate_value!(value)
|
|
85
|
+
# return true if none of the validations are present
|
|
86
|
+
return true if enum_values.empty? && singular?
|
|
87
|
+
|
|
88
|
+
# Use the default value if the value is nil
|
|
89
|
+
value = default if value.nil?
|
|
90
|
+
|
|
91
|
+
valid_value!(value) && valid_collection!(value)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def validate_collection_range
|
|
95
|
+
range = @options[:collection]
|
|
96
|
+
return if range == true
|
|
97
|
+
|
|
98
|
+
unless range.is_a?(Range)
|
|
99
|
+
raise ArgumentError, "Invalid collection range: #{range}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if range.begin.nil?
|
|
103
|
+
raise ArgumentError,
|
|
104
|
+
"Invalid collection range: #{range}. Begin must be specified."
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
if range.begin.negative?
|
|
108
|
+
raise ArgumentError,
|
|
109
|
+
"Invalid collection range: #{range}. Begin must be non-negative."
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if range.end && range.end < range.begin
|
|
113
|
+
raise ArgumentError,
|
|
114
|
+
"Invalid collection range: #{range}. End must be greater than or equal to begin."
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def valid_collection!(value)
|
|
119
|
+
return true unless collection?
|
|
120
|
+
|
|
121
|
+
# Allow nil values for collections during initialization
|
|
122
|
+
return true if value.nil?
|
|
123
|
+
|
|
124
|
+
# Allow any value for unbounded collections
|
|
125
|
+
return true if options[:collection] == true
|
|
126
|
+
|
|
127
|
+
unless value.is_a?(Array)
|
|
128
|
+
raise Lutaml::Model::CollectionCountOutOfRangeError.new(
|
|
129
|
+
name,
|
|
130
|
+
value,
|
|
131
|
+
options[:collection],
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
range = options[:collection]
|
|
136
|
+
return true unless range.is_a?(Range)
|
|
137
|
+
|
|
138
|
+
if range.end.nil?
|
|
139
|
+
if value.size < range.begin
|
|
140
|
+
raise Lutaml::Model::CollectionCountOutOfRangeError.new(
|
|
141
|
+
name,
|
|
142
|
+
value,
|
|
143
|
+
range,
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
elsif !range.cover?(value.size)
|
|
147
|
+
raise Lutaml::Model::CollectionCountOutOfRangeError.new(
|
|
148
|
+
name,
|
|
149
|
+
value,
|
|
150
|
+
range,
|
|
151
|
+
)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
44
155
|
def serialize(value, format, options = {})
|
|
45
156
|
if value.is_a?(Array)
|
|
46
157
|
value.map do |v|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Lutaml
|
|
2
|
+
module Model
|
|
3
|
+
class CollectionCountOutOfRangeError < Error
|
|
4
|
+
def initialize(attr_name, value, range)
|
|
5
|
+
@attr_name = attr_name
|
|
6
|
+
@value = value
|
|
7
|
+
@range = range
|
|
8
|
+
|
|
9
|
+
super()
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
"#{@attr_name} count is #{@value.size}, must be #{range_to_string}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def range_to_string
|
|
19
|
+
if @range.end.nil?
|
|
20
|
+
"at least #{@range.begin}"
|
|
21
|
+
elsif @range.begin == @range.end
|
|
22
|
+
"exactly #{@range.begin}"
|
|
23
|
+
else
|
|
24
|
+
"between #{@range.begin} and #{@range.end}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# lib/lutaml/model/error/validation_error.rb
|
|
2
|
+
module Lutaml
|
|
3
|
+
module Model
|
|
4
|
+
class ValidationError < Error
|
|
5
|
+
attr_reader :errors
|
|
6
|
+
|
|
7
|
+
def initialize(errors)
|
|
8
|
+
@errors = errors
|
|
9
|
+
super(errors.join(", "))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def include?(error_class)
|
|
13
|
+
errors.any?(error_class)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def error_messages
|
|
17
|
+
errors.map(&:message)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/lutaml/model/error.rb
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Lutaml
|
|
2
|
+
module Model
|
|
3
|
+
class Location
|
|
4
|
+
attr_reader :namespace, :location
|
|
5
|
+
|
|
6
|
+
def initialize(namespace:, location:)
|
|
7
|
+
@namespace = namespace
|
|
8
|
+
@location = location
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_xml_attribute
|
|
12
|
+
"#{@namespace} #{@location}".strip
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class SchemaLocation
|
|
17
|
+
DEFAULT_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance".freeze
|
|
18
|
+
|
|
19
|
+
attr_reader :namespace, :prefix, :schema_location
|
|
20
|
+
|
|
21
|
+
def initialize(schema_location:, prefix: "xsi",
|
|
22
|
+
namespace: DEFAULT_NAMESPACE)
|
|
23
|
+
@original_schema_location = schema_location
|
|
24
|
+
@schema_location = parsed_schema_locations(schema_location)
|
|
25
|
+
@prefix = prefix
|
|
26
|
+
@namespace = namespace
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_xml_attributes
|
|
30
|
+
{
|
|
31
|
+
"xmlns:#{prefix}" => namespace,
|
|
32
|
+
"#{prefix}:schemaLocation" => schema_location.map(&:to_xml_attribute).join(" "),
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def [](index)
|
|
37
|
+
@schema_location[index]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def size
|
|
41
|
+
@schema_location.size
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def parsed_schema_locations(schema_location)
|
|
47
|
+
locations = if schema_location.is_a?(Hash)
|
|
48
|
+
schema_location
|
|
49
|
+
else
|
|
50
|
+
schema_location.split.each_slice(2)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
locations.map do |n, l|
|
|
54
|
+
Location.new(namespace: n, location: l)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -9,11 +9,14 @@ require_relative "xml_mapping"
|
|
|
9
9
|
require_relative "key_value_mapping"
|
|
10
10
|
require_relative "json_adapter"
|
|
11
11
|
require_relative "comparable_model"
|
|
12
|
+
require_relative "schema_location"
|
|
13
|
+
require_relative "validation"
|
|
12
14
|
|
|
13
15
|
module Lutaml
|
|
14
16
|
module Model
|
|
15
17
|
module Serialize
|
|
16
18
|
include ComparableModel
|
|
19
|
+
include Validation
|
|
17
20
|
|
|
18
21
|
def self.included(base)
|
|
19
22
|
base.extend(ClassMethods)
|
|
@@ -52,25 +55,10 @@ module Lutaml
|
|
|
52
55
|
|
|
53
56
|
define_method(:"#{name}=") do |value|
|
|
54
57
|
instance_variable_set(:"@#{name}", value)
|
|
55
|
-
validate
|
|
58
|
+
# validate!(name)
|
|
56
59
|
end
|
|
57
60
|
end
|
|
58
61
|
|
|
59
|
-
# Check if the value to be assigned is valid for the attribute
|
|
60
|
-
def attr_value_valid?(name, value)
|
|
61
|
-
attr = attributes[name]
|
|
62
|
-
|
|
63
|
-
return true unless attr.options[:values]
|
|
64
|
-
|
|
65
|
-
# Allow nil values if there's no default
|
|
66
|
-
return true if value.nil? && !attr.default
|
|
67
|
-
|
|
68
|
-
# Use the default value if the value is nil
|
|
69
|
-
value = attr.default if value.nil?
|
|
70
|
-
|
|
71
|
-
attr.options[:values].include?(value)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
62
|
Lutaml::Model::Config::AVAILABLE_FORMATS.each do |format|
|
|
75
63
|
define_method(format) do |&block|
|
|
76
64
|
klass = format == :xml ? XmlMapping : KeyValueMapping
|
|
@@ -92,8 +80,8 @@ module Lutaml
|
|
|
92
80
|
define_method(:"of_#{format}") do |hash|
|
|
93
81
|
if hash.is_a?(Array)
|
|
94
82
|
return hash.map do |item|
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
apply_mappings(item, format)
|
|
84
|
+
end
|
|
97
85
|
end
|
|
98
86
|
|
|
99
87
|
apply_mappings(hash, format)
|
|
@@ -316,6 +304,14 @@ module Lutaml
|
|
|
316
304
|
instance.ordered = mappings_for(:xml).mixed_content? || options[:mixed_content]
|
|
317
305
|
end
|
|
318
306
|
|
|
307
|
+
if doc["__schema_location"]
|
|
308
|
+
instance.schema_location = Lutaml::Model::SchemaLocation.new(
|
|
309
|
+
schema_location: doc["__schema_location"][:schema_location],
|
|
310
|
+
prefix: doc["__schema_location"][:prefix],
|
|
311
|
+
namespace: doc["__schema_location"][:namespace],
|
|
312
|
+
)
|
|
313
|
+
end
|
|
314
|
+
|
|
319
315
|
mappings.each do |rule|
|
|
320
316
|
attr = attributes[rule.to]
|
|
321
317
|
raise "Attribute '#{rule.to}' not found in #{self}" unless attr
|
|
@@ -376,9 +372,11 @@ module Lutaml
|
|
|
376
372
|
end
|
|
377
373
|
end
|
|
378
374
|
|
|
379
|
-
attr_accessor :element_order
|
|
375
|
+
attr_accessor :element_order, :schema_location
|
|
380
376
|
|
|
381
377
|
def initialize(attrs = {})
|
|
378
|
+
@validate_on_set = attrs.delete(:validate_on_set) || false
|
|
379
|
+
|
|
382
380
|
return unless self.class.attributes
|
|
383
381
|
|
|
384
382
|
if attrs.is_a?(Lutaml::Model::MappingHash)
|
|
@@ -386,13 +384,41 @@ module Lutaml
|
|
|
386
384
|
@element_order = attrs.item_order
|
|
387
385
|
end
|
|
388
386
|
|
|
387
|
+
if attrs.key?(:schema_location)
|
|
388
|
+
self.schema_location = attrs[:schema_location]
|
|
389
|
+
end
|
|
390
|
+
|
|
389
391
|
self.class.attributes.each do |name, attr|
|
|
390
|
-
value =
|
|
392
|
+
value = if attrs.key?(name) || attrs.key?(name.to_s)
|
|
393
|
+
self.class.attr_value(attrs, name, attr)
|
|
394
|
+
else
|
|
395
|
+
attr.default
|
|
396
|
+
end
|
|
391
397
|
|
|
392
|
-
|
|
398
|
+
# Initialize collections with an empty array if no value is provided
|
|
399
|
+
if attr.collection? && value.nil?
|
|
400
|
+
value = []
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
instance_variable_set(:"@#{name}", self.class.ensure_utf8(value))
|
|
393
404
|
end
|
|
405
|
+
end
|
|
394
406
|
|
|
395
|
-
|
|
407
|
+
def method_missing(method_name, *args)
|
|
408
|
+
if method_name.to_s.end_with?("=") && self.class.attributes.key?(method_name.to_s.chomp("=").to_sym)
|
|
409
|
+
define_singleton_method(method_name) do |value|
|
|
410
|
+
instance_variable_set(:"@#{method_name.to_s.chomp('=')}", value)
|
|
411
|
+
end
|
|
412
|
+
send(method_name, *args)
|
|
413
|
+
else
|
|
414
|
+
super
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def validate_attribute!(attr_name)
|
|
419
|
+
attr = self.class.attributes[attr_name]
|
|
420
|
+
value = instance_variable_get(:"@#{attr_name}")
|
|
421
|
+
attr.validate_value!(value)
|
|
396
422
|
end
|
|
397
423
|
|
|
398
424
|
def ordered?
|
|
@@ -413,7 +439,7 @@ module Lutaml
|
|
|
413
439
|
|
|
414
440
|
Lutaml::Model::Config::AVAILABLE_FORMATS.each do |format|
|
|
415
441
|
define_method(:"to_#{format}") do |options = {}|
|
|
416
|
-
validate
|
|
442
|
+
validate!
|
|
417
443
|
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
|
418
444
|
representation = if format == :xml
|
|
419
445
|
self
|
|
@@ -425,16 +451,6 @@ module Lutaml
|
|
|
425
451
|
adapter.new(representation).public_send(:"to_#{format}", options)
|
|
426
452
|
end
|
|
427
453
|
end
|
|
428
|
-
|
|
429
|
-
def validate
|
|
430
|
-
self.class.attributes.each do |name, attr|
|
|
431
|
-
value = send(name)
|
|
432
|
-
unless self.class.attr_value_valid?(name, value)
|
|
433
|
-
raise Lutaml::Model::InvalidValueError.new(name, value,
|
|
434
|
-
attr.options[:values])
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
454
|
end
|
|
439
455
|
end
|
|
440
456
|
end
|
|
@@ -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
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
|
@@ -150,6 +157,9 @@ module Lutaml
|
|
|
150
157
|
attributes = options[:xml_attributes] ||= {}
|
|
151
158
|
attributes = build_attributes(element,
|
|
152
159
|
xml_mapping, options).merge(attributes)&.compact
|
|
160
|
+
if element.respond_to?(:schema_location) && element.schema_location
|
|
161
|
+
attributes.merge!(element.schema_location.to_xml_attributes)
|
|
162
|
+
end
|
|
153
163
|
|
|
154
164
|
prefix = if options.key?(:namespace_prefix)
|
|
155
165
|
options[:namespace_prefix]
|
data/lutaml-model.gemspec
CHANGED
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.
|
|
4
|
+
version: 0.3.10
|
|
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
|
+
date: 2024-09-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|
|
@@ -69,8 +69,10 @@ files:
|
|
|
69
69
|
- lib/lutaml/model/comparison.rb
|
|
70
70
|
- lib/lutaml/model/config.rb
|
|
71
71
|
- lib/lutaml/model/error.rb
|
|
72
|
+
- lib/lutaml/model/error/collection_count_out_of_range_error.rb
|
|
72
73
|
- lib/lutaml/model/error/invalid_value_error.rb
|
|
73
74
|
- lib/lutaml/model/error/unknown_adapter_type_error.rb
|
|
75
|
+
- lib/lutaml/model/error/validation_error.rb
|
|
74
76
|
- lib/lutaml/model/json_adapter.rb
|
|
75
77
|
- lib/lutaml/model/json_adapter/json_document.rb
|
|
76
78
|
- lib/lutaml/model/json_adapter/json_object.rb
|
|
@@ -86,6 +88,7 @@ files:
|
|
|
86
88
|
- lib/lutaml/model/schema/relaxng_schema.rb
|
|
87
89
|
- lib/lutaml/model/schema/xsd_schema.rb
|
|
88
90
|
- lib/lutaml/model/schema/yaml_schema.rb
|
|
91
|
+
- lib/lutaml/model/schema_location.rb
|
|
89
92
|
- lib/lutaml/model/serializable.rb
|
|
90
93
|
- lib/lutaml/model/serialize.rb
|
|
91
94
|
- lib/lutaml/model/toml_adapter.rb
|
|
@@ -97,6 +100,7 @@ files:
|
|
|
97
100
|
- lib/lutaml/model/type/date_time.rb
|
|
98
101
|
- lib/lutaml/model/type/time_without_date.rb
|
|
99
102
|
- lib/lutaml/model/utils.rb
|
|
103
|
+
- lib/lutaml/model/validation.rb
|
|
100
104
|
- lib/lutaml/model/version.rb
|
|
101
105
|
- lib/lutaml/model/xml_adapter.rb
|
|
102
106
|
- lib/lutaml/model/xml_adapter/builder/nokogiri.rb
|
|
@@ -119,7 +123,8 @@ files:
|
|
|
119
123
|
homepage: https://github.com/lutaml/lutaml-model
|
|
120
124
|
licenses:
|
|
121
125
|
- BSD-2-Clause
|
|
122
|
-
metadata:
|
|
126
|
+
metadata:
|
|
127
|
+
rubygems_mfa_required: 'true'
|
|
123
128
|
post_install_message:
|
|
124
129
|
rdoc_options: []
|
|
125
130
|
require_paths:
|