lutaml-model 0.3.30 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +34 -18
- data/README.adoc +172 -8
- data/lib/lutaml/model/attribute.rb +6 -2
- data/lib/lutaml/model/key_value_mapping.rb +0 -1
- data/lib/lutaml/model/key_value_mapping_rule.rb +3 -1
- data/lib/lutaml/model/mapping_rule.rb +14 -2
- data/lib/lutaml/model/serialize.rb +174 -61
- data/lib/lutaml/model/type/decimal.rb +5 -0
- data/lib/lutaml/model/type/time.rb +4 -4
- data/lib/lutaml/model/utils.rb +1 -1
- data/lib/lutaml/model/validation.rb +6 -2
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/nokogiri.rb +1 -0
- data/lib/lutaml/model/xml_adapter/builder/oga.rb +180 -0
- data/lib/lutaml/model/xml_adapter/builder/ox.rb +1 -0
- data/lib/lutaml/model/xml_adapter/oga/document.rb +20 -0
- data/lib/lutaml/model/xml_adapter/oga/element.rb +117 -0
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +77 -44
- data/lib/lutaml/model/xml_adapter/xml_document.rb +11 -9
- data/lib/lutaml/model/xml_mapping.rb +0 -1
- data/lib/lutaml/model/xml_mapping_rule.rb +16 -4
- data/spec/address_spec.rb +1 -0
- data/spec/fixtures/sample_model.rb +7 -0
- data/spec/lutaml/model/custom_model_spec.rb +47 -1
- data/spec/lutaml/model/custom_serialization_spec.rb +16 -0
- data/spec/lutaml/model/enum_spec.rb +131 -0
- data/spec/lutaml/model/included_spec.rb +192 -0
- data/spec/lutaml/model/mixed_content_spec.rb +48 -32
- data/spec/lutaml/model/multiple_mapping_spec.rb +329 -0
- data/spec/lutaml/model/ordered_content_spec.rb +1 -1
- data/spec/lutaml/model/render_nil_spec.rb +3 -2
- data/spec/lutaml/model/serializable_spec.rb +3 -3
- data/spec/lutaml/model/type/boolean_spec.rb +62 -0
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -11
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +1 -1
- data/spec/lutaml/model/xml_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_mapping_spec.rb +24 -9
- data/spec/sample_model_spec.rb +114 -0
- metadata +9 -2
@@ -0,0 +1,329 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model"
|
3
|
+
|
4
|
+
module MultipleMapping
|
5
|
+
class Product < Lutaml::Model::Serializable
|
6
|
+
attribute :name, Lutaml::Model::Type::String
|
7
|
+
attribute :localized_name, Lutaml::Model::Type::String
|
8
|
+
attribute :description, Lutaml::Model::Type::String
|
9
|
+
attribute :status, Lutaml::Model::Type::String
|
10
|
+
attribute :content, Lutaml::Model::Type::String
|
11
|
+
|
12
|
+
yaml do
|
13
|
+
map ["name", "product_name"], to: :name
|
14
|
+
map ["desc", "description"], to: :description
|
15
|
+
end
|
16
|
+
|
17
|
+
json do
|
18
|
+
map ["name", "product_name"], to: :name
|
19
|
+
map ["desc", "description"], to: :description
|
20
|
+
end
|
21
|
+
|
22
|
+
toml do
|
23
|
+
map ["name", "product_name"], to: :name
|
24
|
+
map ["desc", "description"], to: :description
|
25
|
+
end
|
26
|
+
|
27
|
+
xml do
|
28
|
+
root "product"
|
29
|
+
map_element ["name", "product-name"], to: :name
|
30
|
+
map_element ["localized-name", "localized_name"], to: :localized_name
|
31
|
+
map_element ["desc", "description"], to: :description
|
32
|
+
map_attribute ["status", "product-status"], to: :status
|
33
|
+
map_content to: :content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class CustomModel < Lutaml::Model::Serializable
|
38
|
+
attribute :id, Lutaml::Model::Type::String
|
39
|
+
attribute :full_name, Lutaml::Model::Type::String
|
40
|
+
attribute :size, Lutaml::Model::Type::Integer
|
41
|
+
attribute :color, Lutaml::Model::Type::String
|
42
|
+
attribute :description, Lutaml::Model::Type::String
|
43
|
+
|
44
|
+
json do
|
45
|
+
map ["name", "custom_name"], with: { to: :name_to_json, from: :name_from_json }
|
46
|
+
map ["color", "shade"], with: { to: :color_to_json, from: :color_from_json }
|
47
|
+
map ["size", "dimension"], with: { to: :size_to_json, from: :size_from_json }
|
48
|
+
map ["desc", "description"], with: { to: :desc_to_json, from: :desc_from_json }
|
49
|
+
end
|
50
|
+
|
51
|
+
xml do
|
52
|
+
root "CustomModel"
|
53
|
+
map_attribute ["id", "identifier"], with: { to: :id_to_xml, from: :id_from_xml }
|
54
|
+
map_element ["name", "custom-name"], with: { to: :name_to_xml, from: :name_from_xml }
|
55
|
+
map_element ["color", "shade"], with: { to: :color_to_xml, from: :color_from_xml }
|
56
|
+
map_element ["size", "dimension"], with: { to: :size_to_xml, from: :size_from_xml }
|
57
|
+
map_element ["desc", "description"], with: { to: :desc_to_xml, from: :desc_from_xml }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Custom methods for JSON
|
61
|
+
def name_to_json(model, doc)
|
62
|
+
doc["name"] = "JSON Model: #{model.full_name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def name_from_json(model, value)
|
66
|
+
model.full_name = value&.sub(/^JSON Model: /, "")
|
67
|
+
end
|
68
|
+
|
69
|
+
def color_to_json(model, doc)
|
70
|
+
doc["color"] = model.color.upcase
|
71
|
+
end
|
72
|
+
|
73
|
+
def color_from_json(model, value)
|
74
|
+
model.color = value&.downcase
|
75
|
+
end
|
76
|
+
|
77
|
+
def size_to_json(model, doc)
|
78
|
+
doc["size"] = model.size + 10
|
79
|
+
end
|
80
|
+
|
81
|
+
def size_from_json(model, value)
|
82
|
+
model.size = value - 10
|
83
|
+
end
|
84
|
+
|
85
|
+
def desc_to_json(model, doc)
|
86
|
+
doc["desc"] = "JSON Description: #{model.description}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def desc_from_json(model, value)
|
90
|
+
model.description = value&.sub(/^JSON Description: /, "")
|
91
|
+
end
|
92
|
+
|
93
|
+
# Custom methods for XML
|
94
|
+
def id_to_xml(model, parent, doc)
|
95
|
+
doc.add_attribute(parent, "id", "XML-#{model.id}")
|
96
|
+
end
|
97
|
+
|
98
|
+
def id_from_xml(model, value)
|
99
|
+
model.id = value&.sub(/^XML-/, "")
|
100
|
+
end
|
101
|
+
|
102
|
+
def name_to_xml(model, parent, doc)
|
103
|
+
el = doc.create_element("name")
|
104
|
+
doc.add_text(el, "XML Model: #{model.full_name}")
|
105
|
+
doc.add_element(parent, el)
|
106
|
+
end
|
107
|
+
|
108
|
+
def name_from_xml(model, value)
|
109
|
+
model.full_name = value.sub(/^XML Model: /, "")
|
110
|
+
end
|
111
|
+
|
112
|
+
def color_to_xml(model, parent, doc)
|
113
|
+
el = doc.create_element("color")
|
114
|
+
doc.add_text(el, model.color.upcase)
|
115
|
+
doc.add_element(parent, el)
|
116
|
+
end
|
117
|
+
|
118
|
+
def color_from_xml(model, value)
|
119
|
+
model.color = value.downcase
|
120
|
+
end
|
121
|
+
|
122
|
+
def size_to_xml(model, parent, doc)
|
123
|
+
el = doc.create_element("size")
|
124
|
+
doc.add_text(el, (model.size + 10).to_s)
|
125
|
+
doc.add_element(parent, el)
|
126
|
+
end
|
127
|
+
|
128
|
+
def size_from_xml(model, value)
|
129
|
+
model.size = (value.to_i || 0) - 10
|
130
|
+
end
|
131
|
+
|
132
|
+
def desc_to_xml(model, parent, doc)
|
133
|
+
el = doc.create_element("desc")
|
134
|
+
doc.add_text(el, "XML Description: #{model.description}")
|
135
|
+
doc.add_element(parent, el)
|
136
|
+
end
|
137
|
+
|
138
|
+
def desc_from_xml(model, value)
|
139
|
+
model.description = value.sub(/^XML Description: /, "")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
RSpec.describe MultipleMapping do
|
145
|
+
context "with key-value formats" do
|
146
|
+
context "with YAML format" do
|
147
|
+
let(:yaml_with_name) { "product_name: Coffee Maker\ndescription: Premium coffee maker" }
|
148
|
+
let(:yaml_with_desc) { "---\nname: Coffee Maker\ndesc: Premium coffee maker\n" }
|
149
|
+
|
150
|
+
it "handles bidirectional conversion" do
|
151
|
+
product1 = MultipleMapping::Product.from_yaml(yaml_with_name)
|
152
|
+
product2 = MultipleMapping::Product.from_yaml(yaml_with_desc)
|
153
|
+
|
154
|
+
# keys for name and description are :name and :desc respectively since
|
155
|
+
# they are first element in their respective mapping array
|
156
|
+
|
157
|
+
expected_yaml = "---\nname: Coffee Maker\ndesc: Premium coffee maker\n"
|
158
|
+
expect(product1.to_yaml).to eq(expected_yaml)
|
159
|
+
expect(product2.to_yaml).to eq(yaml_with_desc)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "with JSON format" do
|
164
|
+
let(:json_with_name) { '{"product_name":"Coffee Maker","description":"Premium coffee maker"}' }
|
165
|
+
let(:json_with_desc) { '{"name":"Coffee Maker","desc":"Premium coffee maker"}' }
|
166
|
+
|
167
|
+
it "handles bidirectional conversion" do
|
168
|
+
product1 = MultipleMapping::Product.from_json(json_with_name)
|
169
|
+
product2 = MultipleMapping::Product.from_json(json_with_desc)
|
170
|
+
|
171
|
+
# keys for name and description are :name and :desc respectively since
|
172
|
+
# they are first element in their respective mapping array
|
173
|
+
expected_json = '{"name":"Coffee Maker","desc":"Premium coffee maker"}'
|
174
|
+
|
175
|
+
expect(product1.to_json).to eq(expected_json)
|
176
|
+
expect(product2.to_json).to eq(json_with_desc)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "with XML format" do
|
182
|
+
shared_examples "xml adapter with multiple mappings" do |adapter_class|
|
183
|
+
before do
|
184
|
+
Lutaml::Model::Config.xml_adapter = adapter_class
|
185
|
+
end
|
186
|
+
|
187
|
+
around do |example|
|
188
|
+
old_adapter = Lutaml::Model::Config.xml_adapter
|
189
|
+
Lutaml::Model::Config.xml_adapter = adapter_class
|
190
|
+
|
191
|
+
example.run
|
192
|
+
ensure
|
193
|
+
Lutaml::Model::Config.xml_adapter = old_adapter
|
194
|
+
end
|
195
|
+
|
196
|
+
let(:xml_with_attributes) do
|
197
|
+
<<~XML
|
198
|
+
<product status="active">
|
199
|
+
Some content here
|
200
|
+
<name>Coffee Maker</name>
|
201
|
+
<description>Premium coffee maker</description>
|
202
|
+
</product>
|
203
|
+
XML
|
204
|
+
end
|
205
|
+
|
206
|
+
let(:xml_with_alternate_attributes) do
|
207
|
+
<<~XML
|
208
|
+
<product product-status="in-stock">
|
209
|
+
Different content
|
210
|
+
<product-name>Coffee Maker</product-name>
|
211
|
+
<desc>Premium coffee maker</desc>
|
212
|
+
</product>
|
213
|
+
XML
|
214
|
+
end
|
215
|
+
|
216
|
+
it "handles bidirectional conversion with attributes and content" do
|
217
|
+
product1 = MultipleMapping::Product.from_xml(xml_with_attributes)
|
218
|
+
product2 = MultipleMapping::Product.from_xml(xml_with_alternate_attributes)
|
219
|
+
|
220
|
+
# Key for element name is :name since it is first element in mapping array and same for status attribute
|
221
|
+
expected_xml_product1 = <<~XML
|
222
|
+
<product status="active">
|
223
|
+
<name>Coffee Maker</name>
|
224
|
+
<desc>Premium coffee maker</desc>
|
225
|
+
Some content here
|
226
|
+
</product>
|
227
|
+
XML
|
228
|
+
|
229
|
+
expected_xml_product2 = <<~XML
|
230
|
+
<product status="in-stock">
|
231
|
+
<name>Coffee Maker</name>
|
232
|
+
<desc>Premium coffee maker</desc>
|
233
|
+
Different content
|
234
|
+
</product>
|
235
|
+
XML
|
236
|
+
|
237
|
+
expect(product1.name).to eq("Coffee Maker")
|
238
|
+
expect(product1.status).to eq("active")
|
239
|
+
expect(product2.status).to eq("in-stock")
|
240
|
+
|
241
|
+
expect(product1.to_xml).to be_equivalent_to(expected_xml_product1)
|
242
|
+
expect(product2.to_xml).to be_equivalent_to(expected_xml_product2)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "with Nokogiri adapter" do
|
247
|
+
it_behaves_like "xml adapter with multiple mappings", Lutaml::Model::XmlAdapter::NokogiriAdapter
|
248
|
+
end
|
249
|
+
|
250
|
+
context "with Ox adapter" do
|
251
|
+
it_behaves_like "xml adapter with multiple mappings", Lutaml::Model::XmlAdapter::OxAdapter
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "with CustomModel" do
|
256
|
+
context "with JSON format" do
|
257
|
+
let(:json_with_alternate) { '{"custom_name":"JSON Model: Vase","shade":"BLUE","dimension":22,"description":"JSON Description: A beautiful ceramic vase"}' }
|
258
|
+
let(:json_with_standard) { '{"name":"JSON Model: Vase","color":"BLUE","size":22,"desc":"JSON Description: A beautiful ceramic vase"}' }
|
259
|
+
|
260
|
+
it "handles bidirectional conversion with custom methods" do
|
261
|
+
model1 = MultipleMapping::CustomModel.from_json(json_with_alternate)
|
262
|
+
model2 = MultipleMapping::CustomModel.from_json(json_with_standard)
|
263
|
+
|
264
|
+
# keys are 'name', 'color', 'size', 'desc' respectively since
|
265
|
+
# they are first element in their respective mapping array
|
266
|
+
expected_json = '{"name":"JSON Model: Vase","color":"BLUE","size":22,"desc":"JSON Description: A beautiful ceramic vase"}'
|
267
|
+
|
268
|
+
expect(model1.to_json).to eq(expected_json)
|
269
|
+
expect(model2.to_json).to eq(expected_json)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context "with XML format" do
|
274
|
+
shared_examples "xml adapter with custom methods" do |_adapter_class|
|
275
|
+
before do
|
276
|
+
Lutaml::Model::Config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
|
277
|
+
end
|
278
|
+
|
279
|
+
let(:xml_with_alternate) do
|
280
|
+
<<~XML
|
281
|
+
<CustomModel identifier="123">
|
282
|
+
<custom-name>XML Model: Vase</custom-name>
|
283
|
+
<shade>BLUE</shade>
|
284
|
+
<dimension>22</dimension>
|
285
|
+
<description>XML Description: A beautiful ceramic vase</description>
|
286
|
+
</CustomModel>
|
287
|
+
XML
|
288
|
+
end
|
289
|
+
|
290
|
+
let(:xml_with_standard) do
|
291
|
+
<<~XML
|
292
|
+
<CustomModel identifier="123">
|
293
|
+
<name>XML Model: Vase</name>
|
294
|
+
<color>BLUE</color>
|
295
|
+
<size>22</size>
|
296
|
+
<desc>XML Description: A beautiful ceramic vase</desc>
|
297
|
+
</CustomModel>
|
298
|
+
XML
|
299
|
+
end
|
300
|
+
|
301
|
+
it "handles bidirectional conversion with custom methods" do
|
302
|
+
model1 = MultipleMapping::CustomModel.from_xml(xml_with_alternate)
|
303
|
+
model2 = MultipleMapping::CustomModel.from_xml(xml_with_standard)
|
304
|
+
|
305
|
+
# Element names are 'name', 'color', 'size', 'desc' respectively since
|
306
|
+
# they are first element in their respective mapping array
|
307
|
+
expected_xml = <<~XML
|
308
|
+
<CustomModel id="XML-123">
|
309
|
+
<name>XML Model: Vase</name>
|
310
|
+
<color>BLUE</color>
|
311
|
+
<size>22</size>
|
312
|
+
<desc>XML Description: A beautiful ceramic vase</desc>
|
313
|
+
</CustomModel>
|
314
|
+
XML
|
315
|
+
expect(model1.to_xml).to be_equivalent_to(expected_xml)
|
316
|
+
expect(model2.to_xml).to be_equivalent_to(expected_xml)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context "with Nokogiri adapter" do
|
321
|
+
it_behaves_like "xml adapter with custom methods", Lutaml::Model::XmlAdapter::NokogiriAdapter
|
322
|
+
end
|
323
|
+
|
324
|
+
context "with Ox adapter" do
|
325
|
+
it_behaves_like "xml adapter with custom methods", Lutaml::Model::XmlAdapter::OxAdapter
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
@@ -77,7 +77,7 @@ RSpec.describe "OrderedContent" do
|
|
77
77
|
it_behaves_like "ordered content behavior", described_class
|
78
78
|
end
|
79
79
|
|
80
|
-
describe Lutaml::Model::XmlAdapter::OgaAdapter
|
80
|
+
describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
81
81
|
it_behaves_like "ordered content behavior", described_class
|
82
82
|
end
|
83
83
|
end
|
@@ -42,6 +42,7 @@ class RenderNil < Lutaml::Model::Serializable
|
|
42
42
|
map "clay_type", to: :clay_type, render_nil: false
|
43
43
|
map "glaze", to: :glaze, render_nil: true
|
44
44
|
map "dimensions", to: :dimensions, render_nil: false
|
45
|
+
map "render_nil_nested", to: :render_nil_nested, render_nil: false
|
45
46
|
end
|
46
47
|
|
47
48
|
toml do
|
@@ -59,8 +60,10 @@ RSpec.describe RenderNil do
|
|
59
60
|
clay_type: nil,
|
60
61
|
glaze: nil,
|
61
62
|
dimensions: nil,
|
63
|
+
render_nil_nested: RenderNilNested.new,
|
62
64
|
}
|
63
65
|
end
|
66
|
+
|
64
67
|
let(:model) { described_class.new(attributes) }
|
65
68
|
|
66
69
|
it "serializes to JSON with render_nil option" do
|
@@ -68,7 +71,6 @@ RSpec.describe RenderNil do
|
|
68
71
|
name: nil,
|
69
72
|
clay_type: nil,
|
70
73
|
glaze: nil,
|
71
|
-
dimensions: [],
|
72
74
|
}.to_json
|
73
75
|
|
74
76
|
expect(model.to_json).to eq(expected_json)
|
@@ -113,7 +115,6 @@ RSpec.describe RenderNil do
|
|
113
115
|
---
|
114
116
|
name:
|
115
117
|
glaze:
|
116
|
-
dimensions: []
|
117
118
|
YAML
|
118
119
|
|
119
120
|
generated_yaml = model.to_yaml.strip
|
@@ -87,7 +87,7 @@ RSpec.describe Lutaml::Model::Serializable do
|
|
87
87
|
end.to change(
|
88
88
|
described_class, :model
|
89
89
|
)
|
90
|
-
.from(
|
90
|
+
.from(described_class)
|
91
91
|
.to(SerializeableSpec::TestModel)
|
92
92
|
end
|
93
93
|
end
|
@@ -131,8 +131,8 @@ RSpec.describe Lutaml::Model::Serializable do
|
|
131
131
|
|
132
132
|
let(:expected_hash) do
|
133
133
|
{
|
134
|
-
na
|
135
|
-
ag
|
134
|
+
"na" => "John",
|
135
|
+
"ag" => "18",
|
136
136
|
}
|
137
137
|
end
|
138
138
|
|
@@ -1,5 +1,23 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
+
module BooleanSpec
|
4
|
+
class Employee < Lutaml::Model::Serializable
|
5
|
+
attribute :name, :string
|
6
|
+
attribute :full_time, :boolean
|
7
|
+
attribute :on_leave, :boolean
|
8
|
+
attribute :remote, :boolean
|
9
|
+
attribute :active, :boolean
|
10
|
+
|
11
|
+
key_value do
|
12
|
+
map "name", to: :name
|
13
|
+
map "full_time", to: :full_time
|
14
|
+
map "on_leave", to: :on_leave
|
15
|
+
map "remote", to: :remote, render_nil: true
|
16
|
+
map "active", to: :active, render_nil: false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
3
21
|
RSpec.describe Lutaml::Model::Type::Boolean do
|
4
22
|
describe ".cast" do
|
5
23
|
let(:truthy_values) { [true, "true", "t", "yes", "y", "1"] }
|
@@ -51,4 +69,48 @@ RSpec.describe Lutaml::Model::Type::Boolean do
|
|
51
69
|
expect(described_class.serialize(true)).to be true
|
52
70
|
end
|
53
71
|
end
|
72
|
+
|
73
|
+
context "with key-value serialization" do
|
74
|
+
let(:yaml) do
|
75
|
+
{
|
76
|
+
"name" => "John Smith",
|
77
|
+
"full_time" => true,
|
78
|
+
"on_leave" => false,
|
79
|
+
"remote" => nil,
|
80
|
+
"active" => nil,
|
81
|
+
}.to_yaml
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:expected_yaml) do
|
85
|
+
{
|
86
|
+
"name" => "John Smith",
|
87
|
+
"full_time" => true,
|
88
|
+
"on_leave" => false,
|
89
|
+
"remote" => nil,
|
90
|
+
}.to_yaml
|
91
|
+
end
|
92
|
+
|
93
|
+
it "deserializes boolean values correctly" do
|
94
|
+
employee = BooleanSpec::Employee.from_yaml(yaml)
|
95
|
+
|
96
|
+
expect(employee.name).to eq("John Smith")
|
97
|
+
expect(employee.full_time).to be true
|
98
|
+
expect(employee.on_leave).to be false
|
99
|
+
expect(employee.remote).to be_nil
|
100
|
+
expect(employee.active).to be_nil
|
101
|
+
end
|
102
|
+
|
103
|
+
it "serializes boolean values correctly" do
|
104
|
+
employee = BooleanSpec::Employee.new(
|
105
|
+
name: "John Smith",
|
106
|
+
full_time: true,
|
107
|
+
on_leave: false,
|
108
|
+
remote: nil,
|
109
|
+
active: nil,
|
110
|
+
)
|
111
|
+
|
112
|
+
yaml_output = employee.to_yaml
|
113
|
+
expect(yaml_output).to eq(expected_yaml)
|
114
|
+
end
|
115
|
+
end
|
54
116
|
end
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
require "oga"
|
3
3
|
require_relative "../../../../lib/lutaml/model/xml_adapter/oga_adapter"
|
4
4
|
|
5
|
-
RSpec.
|
5
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
6
6
|
let(:xml_string) do
|
7
7
|
<<~XML
|
8
8
|
<root xmlns="http://example.com/default" xmlns:prefix="http://example.com/prefixed">
|
@@ -14,21 +14,21 @@ RSpec.xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
|
14
14
|
let(:document) { described_class.parse(xml_string) }
|
15
15
|
|
16
16
|
context "parsing XML with namespaces" do
|
17
|
+
let(:child) { document.root.children[1] }
|
18
|
+
|
17
19
|
it "parses the root element with default namespace" do
|
18
20
|
expect(document.root.name).to eq("root")
|
19
|
-
expect(document.root.namespace).to eq("http://example.com/default")
|
20
|
-
expect(document.root.
|
21
|
+
expect(document.root.namespace.uri).to eq("http://example.com/default")
|
22
|
+
expect(document.root.namespace.prefix).to be_nil
|
21
23
|
end
|
22
24
|
|
23
25
|
it "parses child element with prefixed namespace" do
|
24
|
-
child
|
25
|
-
expect(child.
|
26
|
-
expect(child.namespace).to eq("
|
27
|
-
expect(child.namespace_prefix).to eq("prefix")
|
26
|
+
expect(child.name).to eq("prefix:child")
|
27
|
+
expect(child.namespace.uri).to eq("http://example.com/prefixed")
|
28
|
+
expect(child.namespace.prefix).to eq("prefix")
|
28
29
|
end
|
29
30
|
|
30
31
|
it "parses attributes with and without namespaces" do
|
31
|
-
child = document.root.children.first
|
32
32
|
expect(child.attributes["attr"].value).to eq("value")
|
33
33
|
expect(child.attributes["attr"].namespace).to be_nil
|
34
34
|
expect(child.attributes["prefix:attr"].value).to eq("prefixed_value")
|
@@ -42,12 +42,12 @@ RSpec.xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
|
42
42
|
xml_output = document.to_xml
|
43
43
|
parsed_output = Oga.parse_xml(xml_output)
|
44
44
|
|
45
|
-
root = parsed_output.
|
45
|
+
root = parsed_output.children.first
|
46
46
|
expect(root.name).to eq("root")
|
47
47
|
expect(root.namespace.uri).to eq("http://example.com/default")
|
48
48
|
|
49
|
-
child = root.children
|
50
|
-
expect(child.
|
49
|
+
child = root.children[1]
|
50
|
+
expect(child.expanded_name).to eq("prefix:child")
|
51
51
|
expect(child.namespace.uri).to eq("http://example.com/prefixed")
|
52
52
|
expect(child.get("attr")).to eq("value")
|
53
53
|
expect(child.get("prefix:attr")).to eq("prefixed_value")
|
@@ -246,6 +246,6 @@ RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
|
|
246
246
|
it_behaves_like "an XML namespace parser", described_class
|
247
247
|
end
|
248
248
|
|
249
|
-
RSpec.
|
249
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
250
250
|
it_behaves_like "an XML namespace parser", described_class
|
251
251
|
end
|
@@ -119,7 +119,7 @@ RSpec.shared_examples "an XML adapter" do |adapter_class|
|
|
119
119
|
|
120
120
|
parsed = XmlAdapterSpec::Maths.from_xml(input_xml)
|
121
121
|
|
122
|
-
expect(parsed.to_xml.strip).to
|
122
|
+
expect(parsed.to_xml.strip).to be_equivalent_to(output_xml.strip)
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
@@ -173,6 +173,6 @@ RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
|
|
173
173
|
it_behaves_like "an XML adapter", described_class
|
174
174
|
end
|
175
175
|
|
176
|
-
RSpec.
|
176
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
177
177
|
it_behaves_like "an XML adapter", described_class
|
178
178
|
end
|
@@ -325,7 +325,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
|
|
325
325
|
end
|
326
326
|
|
327
327
|
# Skipping for OX because it does not handle namespaces
|
328
|
-
context "overriding child namespace prefix", skip: adapter_class
|
328
|
+
context "overriding child namespace prefix", skip: adapter_class == Lutaml::Model::XmlAdapter::OxAdapter do
|
329
329
|
let(:input_xml) do
|
330
330
|
<<~XML
|
331
331
|
<OverrideDefaultNamespacePrefix
|
@@ -342,9 +342,20 @@ RSpec.describe Lutaml::Model::XmlMapping do
|
|
342
342
|
XML
|
343
343
|
end
|
344
344
|
|
345
|
+
let(:oga_expected_xml) do
|
346
|
+
"<OverrideDefaultNamespacePrefix xmlns:abc=\"http://www.omg.org/spec/XMI/20131001\">" +
|
347
|
+
"<abc:SameElementName App=\"hello\" xmlns:GML=\"http://www.sparxsystems.com/profiles/GML/1.0\" xmlns:CityGML=\"http://www.sparxsystems.com/profiles/CityGML/1.0\">" +
|
348
|
+
"<GML:ApplicationSchema>GML App</GML:ApplicationSchema>" +
|
349
|
+
"<CityGML:ApplicationSchema>CityGML App</CityGML:ApplicationSchema>" +
|
350
|
+
"<abc:ApplicationSchema>App</abc:ApplicationSchema>" +
|
351
|
+
"</abc:SameElementName>" +
|
352
|
+
"</OverrideDefaultNamespacePrefix>"
|
353
|
+
end
|
354
|
+
|
345
355
|
it "expect to round-trips" do
|
346
356
|
parsed = XmlMapping::OverrideDefaultNamespacePrefix.from_xml(input_xml)
|
347
|
-
|
357
|
+
expected_xml = adapter_class.type == "oga" ? oga_expected_xml : input_xml
|
358
|
+
expect(parsed.to_xml).to be_equivalent_to(expected_xml)
|
348
359
|
end
|
349
360
|
end
|
350
361
|
|
@@ -379,6 +390,15 @@ RSpec.describe Lutaml::Model::XmlMapping do
|
|
379
390
|
"ApplicationSchema",
|
380
391
|
"ApplicationSchema",
|
381
392
|
],
|
393
|
+
Lutaml::Model::XmlAdapter::OgaAdapter => [
|
394
|
+
"text",
|
395
|
+
"ApplicationSchema",
|
396
|
+
"text",
|
397
|
+
"ApplicationSchema",
|
398
|
+
"text",
|
399
|
+
"ApplicationSchema",
|
400
|
+
"text",
|
401
|
+
],
|
382
402
|
}
|
383
403
|
end
|
384
404
|
|
@@ -1032,12 +1052,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
|
|
1032
1052
|
end
|
1033
1053
|
|
1034
1054
|
it "round-trips xml" do
|
1035
|
-
expected_xml =
|
1036
|
-
expected_nokogiri_xml
|
1037
|
-
else
|
1038
|
-
expected_ox_xml
|
1039
|
-
end
|
1040
|
-
|
1055
|
+
expected_xml = adapter_class.type == "ox" ? expected_ox_xml : expected_nokogiri_xml
|
1041
1056
|
expect(XmlMapping::SpecialCharContentWithMapAll.from_xml(xml).to_xml).to eq(expected_xml)
|
1042
1057
|
end
|
1043
1058
|
end
|
@@ -1066,7 +1081,7 @@ RSpec.describe Lutaml::Model::XmlMapping do
|
|
1066
1081
|
it_behaves_like "having XML Mappings", described_class
|
1067
1082
|
end
|
1068
1083
|
|
1069
|
-
describe Lutaml::Model::XmlAdapter::OgaAdapter
|
1084
|
+
describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
1070
1085
|
it_behaves_like "having XML Mappings", described_class
|
1071
1086
|
end
|
1072
1087
|
end
|