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,192 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model"
|
3
|
+
|
4
|
+
module IncludedSpec
|
5
|
+
class Base
|
6
|
+
include Lutaml::Model::Serialize
|
7
|
+
|
8
|
+
attribute :text, Lutaml::Model::Type::String
|
9
|
+
attribute :id, Lutaml::Model::Type::String
|
10
|
+
attribute :name, Lutaml::Model::Type::String
|
11
|
+
|
12
|
+
xml do
|
13
|
+
map_content to: :text
|
14
|
+
map_attribute "id", to: :id
|
15
|
+
map_element "name", to: :name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Implementation1
|
20
|
+
include Lutaml::Model::Serialize
|
21
|
+
|
22
|
+
attribute :text, Lutaml::Model::Type::String
|
23
|
+
attribute :id, Lutaml::Model::Type::String
|
24
|
+
attribute :name, Lutaml::Model::Type::String
|
25
|
+
attribute :age, Lutaml::Model::Type::Integer
|
26
|
+
|
27
|
+
xml do
|
28
|
+
root "impl_one"
|
29
|
+
map_content to: :text
|
30
|
+
map_attribute "id", to: :id
|
31
|
+
map_element "name", to: :name
|
32
|
+
map_element "age", to: :age
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Implementation2
|
37
|
+
include Lutaml::Model::Serialize
|
38
|
+
|
39
|
+
attribute :text, Lutaml::Model::Type::String
|
40
|
+
attribute :id, Lutaml::Model::Type::String
|
41
|
+
attribute :name, Lutaml::Model::Type::String
|
42
|
+
attribute :age, Lutaml::Model::Type::Integer
|
43
|
+
|
44
|
+
xml do
|
45
|
+
root "impl_two"
|
46
|
+
map_content to: :text
|
47
|
+
map_attribute "id", to: :id
|
48
|
+
map_element "name", to: :name
|
49
|
+
map_element "gender", to: :age
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ParentClass
|
54
|
+
include Lutaml::Model::Serialize
|
55
|
+
|
56
|
+
attribute :parent_name, Lutaml::Model::Type::String
|
57
|
+
attribute :parent_id, Lutaml::Model::Type::String
|
58
|
+
|
59
|
+
xml do
|
60
|
+
root "parent"
|
61
|
+
map_attribute "id", to: :parent_id
|
62
|
+
map_element "parent_name", to: :parent_name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module ChildClass
|
67
|
+
include ParentClass
|
68
|
+
|
69
|
+
attribute :child_name, Lutaml::Model::Type::String
|
70
|
+
attribute :child_type, Lutaml::Model::Type::String
|
71
|
+
attribute :child_text, Lutaml::Model::Type::String
|
72
|
+
|
73
|
+
xml do
|
74
|
+
root "child"
|
75
|
+
map_attribute "type", to: :child_type
|
76
|
+
map_element "child_name", to: :child_name
|
77
|
+
map_content to: :child_text
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class GrandChildClass
|
82
|
+
include ChildClass
|
83
|
+
|
84
|
+
attribute :grandchild_name, Lutaml::Model::Type::String
|
85
|
+
attribute :grandchild_version, Lutaml::Model::Type::String
|
86
|
+
attribute :grandchild_text, Lutaml::Model::Type::String
|
87
|
+
|
88
|
+
xml do
|
89
|
+
root "grandchild"
|
90
|
+
map_attribute "version", to: :grandchild_version
|
91
|
+
map_element "grandchild_name", to: :grandchild_name
|
92
|
+
map_content to: :grandchild_text
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
RSpec.describe "Included" do
|
98
|
+
subject(:impl_object) do
|
99
|
+
IncludedSpec::Implementation1.new(
|
100
|
+
{
|
101
|
+
text: "Some text",
|
102
|
+
name: "John Doe",
|
103
|
+
id: "foobar",
|
104
|
+
age: 30,
|
105
|
+
},
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:expected_xml) do
|
110
|
+
'<impl_one id="foobar"><name>John Doe</name><age>30</age>Some text</impl_one>'
|
111
|
+
end
|
112
|
+
|
113
|
+
it "uses included module attributes" do
|
114
|
+
expect(impl_object.to_xml(pretty: true)).to eq(expected_xml)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "with multiple implementing classes" do
|
118
|
+
describe "Implementation1" do
|
119
|
+
let(:impl1) { IncludedSpec::Implementation1 }
|
120
|
+
|
121
|
+
it "has correct mappings" do
|
122
|
+
expect(impl1.mappings_for(:xml).mappings.count).to eq(4)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "has correct attributes" do
|
126
|
+
expect(impl1.attributes.count).to eq(4)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "has correct model" do
|
130
|
+
expect(impl1.model).to eq(impl1)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "Implementation2" do
|
135
|
+
let(:impl2) { IncludedSpec::Implementation2 }
|
136
|
+
|
137
|
+
it "has correct mappings" do
|
138
|
+
expect(impl2.mappings_for(:xml).mappings.count).to eq(4)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "has correct attributes" do
|
142
|
+
expect(impl2.attributes.count).to eq(4)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "has correct model" do
|
146
|
+
expect(impl2.model).to eq(impl2)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "with nested module inclusion" do
|
152
|
+
let(:grandchild) do
|
153
|
+
IncludedSpec::GrandChildClass.new(
|
154
|
+
parent_name: "Parent Name",
|
155
|
+
parent_id: "P123",
|
156
|
+
child_name: "Child Name",
|
157
|
+
child_type: "Type A",
|
158
|
+
child_text: "Child Text",
|
159
|
+
grandchild_name: "GrandChild Name",
|
160
|
+
grandchild_version: "1.0",
|
161
|
+
grandchild_text: "GrandChild Text",
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "inherits attributes through the chain" do
|
166
|
+
expect(IncludedSpec::GrandChildClass.attributes.keys).to include(
|
167
|
+
:parent_name, :parent_id,
|
168
|
+
:child_name, :child_type, :child_text,
|
169
|
+
:grandchild_name, :grandchild_version, :grandchild_text
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "maintains correct XML mappings through inheritance" do
|
174
|
+
expected_xml = <<~XML
|
175
|
+
<grandchild id="P123" type="Type A" version="1.0">
|
176
|
+
<parent_name>Parent Name</parent_name>
|
177
|
+
<child_name>Child Name</child_name>
|
178
|
+
<grandchild_name>GrandChild Name</grandchild_name>
|
179
|
+
GrandChild Text
|
180
|
+
</grandchild>
|
181
|
+
XML
|
182
|
+
|
183
|
+
expect(grandchild.to_xml(pretty: true)).to be_equivalent_to(expected_xml)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "preserves separate mapping configurations" do
|
187
|
+
expect(IncludedSpec::ParentClass.mappings_for(:xml).root_element).to eq("parent")
|
188
|
+
expect(IncludedSpec::ChildClass.mappings_for(:xml).root_element).to eq("child")
|
189
|
+
expect(IncludedSpec::GrandChildClass.mappings_for(:xml).root_element).to eq("grandchild")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -524,15 +524,12 @@ RSpec.describe "MixedContent" do
|
|
524
524
|
describe ".from_xml" do
|
525
525
|
let(:expected_nokogiri_content) { "B <p>R&C</p>\n C <p>J—C</p>\n O <p>A & B </p>\n F <p>Z ©S</p>" }
|
526
526
|
let(:expected_ox_content) { "B <p>R&C</p>\n C <p>J—C</p>\n O <p>A & B </p>\n F <p>Z ©S</p>" }
|
527
|
+
let(:expected_oga_content) { "B <p>R&C</p>\n C <p>J—C</p>\n O <p>A & B </p>\n F <p>Z ©S</p>" }
|
527
528
|
|
528
529
|
it "deserializes special char mixed content correctly" do
|
529
530
|
parsed = MixedContentSpec::SpecialCharContentWithRawAndMixedOption.from_xml(xml)
|
530
|
-
expected_content =
|
531
|
-
|
532
|
-
if adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
|
533
|
-
expected_content = expected_ox_content
|
534
|
-
parsed.special.force_encoding("UTF-8")
|
535
|
-
end
|
531
|
+
expected_content = public_send(:"expected_#{adapter_class.type}_content")
|
532
|
+
parsed.special.force_encoding("UTF-8") unless adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
536
533
|
|
537
534
|
expect(parsed.special.strip).to eq(expected_content)
|
538
535
|
end
|
@@ -562,12 +559,23 @@ RSpec.describe "MixedContent" do
|
|
562
559
|
XML
|
563
560
|
end
|
564
561
|
|
562
|
+
let(:expected_oga_xml) do
|
563
|
+
<<~XML
|
564
|
+
<SpecialCharContentWithRawOptionAndMixedOption>
|
565
|
+
<special> B <p>R&C</p>
|
566
|
+
C <p>J—C</p>
|
567
|
+
O <p>A & B </p>
|
568
|
+
F <p>Z ©S</p>
|
569
|
+
</special>
|
570
|
+
</SpecialCharContentWithRawOptionAndMixedOption>
|
571
|
+
XML
|
572
|
+
end
|
573
|
+
|
565
574
|
it "serializes special char mixed content correctly" do
|
566
575
|
parsed = MixedContentSpec::SpecialCharContentWithRawAndMixedOption.from_xml(xml)
|
567
576
|
serialized = parsed.to_xml
|
568
577
|
|
569
|
-
|
570
|
-
expect(serialized).to be_equivalent_to(expected_output)
|
578
|
+
expect(serialized).to be_equivalent_to(send(:"expected_#{adapter_class.type}_xml"))
|
571
579
|
end
|
572
580
|
end
|
573
581
|
end
|
@@ -590,21 +598,21 @@ RSpec.describe "MixedContent" do
|
|
590
598
|
it "deserializes special char mixed content correctly" do
|
591
599
|
parsed = MixedContentSpec::SpecialCharContentWithRawAndMixedOption.from_xml(xml)
|
592
600
|
|
593
|
-
expected_output = adapter_class == Lutaml::Model::XmlAdapter::
|
601
|
+
expected_output = adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter ? expected_nokogiri_content : expected_ox_content
|
594
602
|
expect(parsed.special.strip).to eq(expected_output)
|
595
603
|
end
|
596
604
|
end
|
597
605
|
|
598
606
|
describe ".to_xml" do
|
599
607
|
let(:expected_nokogiri_xml) { "B <p>R</p>" }
|
608
|
+
let(:expected_oga_xml) { "B <p>R&C</p>" }
|
600
609
|
let(:expected_ox_xml) { "B <p>R&amp;C</p>" }
|
601
610
|
|
602
611
|
it "serializes special char mixed content correctly" do
|
603
612
|
parsed = MixedContentSpec::SpecialCharContentWithRawAndMixedOption.from_xml(xml)
|
604
613
|
serialized = parsed.to_xml
|
605
614
|
|
606
|
-
|
607
|
-
expect(serialized).to include(expected_output)
|
615
|
+
expect(serialized).to include(send(:"expected_#{adapter_class.type}_xml"))
|
608
616
|
end
|
609
617
|
end
|
610
618
|
end
|
@@ -630,12 +638,13 @@ RSpec.describe "MixedContent" do
|
|
630
638
|
|
631
639
|
describe ".to_xml" do
|
632
640
|
let(:expected_xml) { "<TextualSupport>\n <value><computer security> type of operation specified by an access right</value>\n</TextualSupport>" }
|
641
|
+
let(:expected_oga_xml) { "<TextualSupport><value><computer security> type of operation specified by an access right</value></TextualSupport>" }
|
633
642
|
|
634
643
|
it "serializes special char mixed content correctly" do
|
635
644
|
parsed = MixedContentSpec::TextualSupport.from_xml(xml)
|
636
645
|
serialized = parsed.to_xml
|
637
|
-
|
638
|
-
expect(serialized.strip).to include(
|
646
|
+
expected = adapter_class.type == "oga" ? expected_oga_xml : expected_xml
|
647
|
+
expect(serialized.strip).to include(expected)
|
639
648
|
end
|
640
649
|
end
|
641
650
|
end
|
@@ -679,10 +688,10 @@ RSpec.describe "MixedContent" do
|
|
679
688
|
parsed = MixedContentSpec::HexCode.from_xml(xml)
|
680
689
|
serialized = parsed.to_xml(encoding: nil)
|
681
690
|
|
682
|
-
expected_output = if adapter_class == Lutaml::Model::XmlAdapter::
|
683
|
-
expected_encoding_nil_ox_xml
|
684
|
-
else
|
691
|
+
expected_output = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
685
692
|
expected_encoding_nil_nokogiri_xml
|
693
|
+
else
|
694
|
+
expected_encoding_nil_ox_xml
|
686
695
|
end
|
687
696
|
|
688
697
|
expect(serialized.strip).to include(expected_output)
|
@@ -715,10 +724,12 @@ RSpec.describe "MixedContent" do
|
|
715
724
|
it "deserializes SHIFT encoded content incorrectly without explicit encoding option" do
|
716
725
|
parsed = MixedContentSpec::Shift.from_xml(fixture)
|
717
726
|
|
718
|
-
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::
|
719
|
-
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("UTF-8")
|
720
|
-
else
|
727
|
+
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
721
728
|
"�菑���p���P"
|
729
|
+
elsif adapter_class == Lutaml::Model::XmlAdapter::OgaAdapter
|
730
|
+
"手書き英字1"
|
731
|
+
else
|
732
|
+
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("UTF-8")
|
722
733
|
end
|
723
734
|
|
724
735
|
expect(parsed.field).to include(expected_content)
|
@@ -729,8 +740,8 @@ RSpec.describe "MixedContent" do
|
|
729
740
|
it "serializes SHIFT-JIS encoding content correctly reading from file" do
|
730
741
|
parsed = MixedContentSpec::Shift.from_xml(fixture, encoding: "Shift_JIS")
|
731
742
|
serialized = parsed.to_xml
|
732
|
-
|
733
|
-
expect(serialized.strip).to eq(
|
743
|
+
expected = adapter_class.type == "oga" ? fixture.gsub(/\s+/, "") : fixture.strip
|
744
|
+
expect(serialized.strip).to eq(expected)
|
734
745
|
end
|
735
746
|
|
736
747
|
it "serializes SHIFT encoded content correctly with explicit encoding option both in parsing and deserializing" do
|
@@ -780,13 +791,13 @@ RSpec.describe "MixedContent" do
|
|
780
791
|
it "serializes SHIFT-JIS content incorrectly bcz no encoding provided during parsing" do
|
781
792
|
parsed = MixedContentSpec::Shift.from_xml(fixture)
|
782
793
|
serialized = parsed.to_xml(encoding: "Shift_JIS")
|
783
|
-
|
784
|
-
|
794
|
+
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
795
|
+
"<root>\n <FieldName>�菑���p���P</FieldName>\n <FieldName>123456</FieldName>\n</root>"
|
796
|
+
elsif adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
|
785
797
|
"<root>\n <FieldName>\x8E菑\x82\xAB\x89p\x8E\x9A\x82P</FieldName>\n <FieldName>123456</FieldName>\n</root>\n"
|
786
798
|
else
|
787
|
-
"<root
|
799
|
+
"<root><FieldName>手書き英字1</FieldName><FieldName>123456</FieldName></root>".encode("Shift_JIS")
|
788
800
|
end
|
789
|
-
|
790
801
|
expect(serialized).to eq(expected_content)
|
791
802
|
end
|
792
803
|
|
@@ -831,10 +842,12 @@ RSpec.describe "MixedContent" do
|
|
831
842
|
it "deserializes latin encoded content incorrectly" do
|
832
843
|
parsed = MixedContentSpec::Latin.from_xml(fixture)
|
833
844
|
|
834
|
-
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::
|
835
|
-
["M\xFCller", "Jos\xE9"]
|
836
|
-
else
|
845
|
+
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
837
846
|
["M�ller", "Jos�"]
|
847
|
+
elsif adapter_class == Lutaml::Model::XmlAdapter::OgaAdapter
|
848
|
+
["Müller", "José"]
|
849
|
+
else
|
850
|
+
["M\xFCller", "Jos\xE9"]
|
838
851
|
end
|
839
852
|
|
840
853
|
expect(parsed.from).to eq(expected_content[0])
|
@@ -846,8 +859,12 @@ RSpec.describe "MixedContent" do
|
|
846
859
|
it "serializes latin encoded content correctly" do
|
847
860
|
parsed = MixedContentSpec::Latin.from_xml(fixture, encoding: "ISO-8859-1")
|
848
861
|
serialized = parsed.to_xml
|
849
|
-
|
850
|
-
|
862
|
+
expected_xml = if adapter_class == Lutaml::Model::XmlAdapter::OgaAdapter
|
863
|
+
"<note><to>Jos\xE9</to><from>M\xFCller</from><heading>Reminder</heading></note>"
|
864
|
+
else
|
865
|
+
"<note>\n <to>Jos\xE9</to>\n <from>M\xFCller</from>\n <heading>Reminder</heading>\n</note>"
|
866
|
+
end
|
867
|
+
expect(serialized.strip).to eq(expected_xml.force_encoding("ISO-8859-1"))
|
851
868
|
end
|
852
869
|
end
|
853
870
|
end
|
@@ -868,8 +885,7 @@ RSpec.describe "MixedContent" do
|
|
868
885
|
it_behaves_like "mixed content behavior", described_class
|
869
886
|
end
|
870
887
|
|
871
|
-
|
872
|
-
xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
888
|
+
describe Lutaml::Model::XmlAdapter::OgaAdapter do
|
873
889
|
it_behaves_like "mixed content behavior", described_class
|
874
890
|
end
|
875
891
|
end
|