lutaml-model 0.4.0 → 0.5.0
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 +34 -18
- data/README.adoc +166 -8
- 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 +67 -52
- data/lib/lutaml/model/type/decimal.rb +5 -0
- 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/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 -0
- data/spec/lutaml/model/serializable_spec.rb +1 -1
- 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 +8 -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
|
@@ -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
|