lutaml-model 0.5.4 → 0.6.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 +58 -21
- data/Gemfile +1 -0
- data/README.adoc +1112 -264
- data/lib/lutaml/model/attribute.rb +33 -10
- data/lib/lutaml/model/choice.rb +56 -0
- data/lib/lutaml/model/config.rb +1 -0
- data/lib/lutaml/model/error/choice_lower_bound_error.rb +9 -0
- data/lib/lutaml/model/error/choice_upper_bound_error.rb +9 -0
- data/lib/lutaml/model/error/import_model_with_root_error.rb +9 -0
- data/lib/lutaml/model/error/incorrect_sequence_error.rb +9 -0
- data/lib/lutaml/model/error/invalid_choice_range_error.rb +20 -0
- data/lib/lutaml/model/error/no_root_mapping_error.rb +9 -0
- data/lib/lutaml/model/error/no_root_namespace_error.rb +9 -0
- data/lib/lutaml/model/error/unknown_sequence_mapping_error.rb +9 -0
- data/lib/lutaml/model/error.rb +8 -0
- data/lib/lutaml/model/json_adapter/standard_json_adapter.rb +6 -1
- data/lib/lutaml/model/key_value_mapping.rb +3 -1
- data/lib/lutaml/model/key_value_mapping_rule.rb +4 -2
- data/lib/lutaml/model/liquefiable.rb +59 -0
- data/lib/lutaml/model/mapping_hash.rb +1 -1
- data/lib/lutaml/model/mapping_rule.rb +15 -2
- data/lib/lutaml/model/schema/xml_compiler.rb +68 -26
- data/lib/lutaml/model/schema_location.rb +7 -0
- data/lib/lutaml/model/sequence.rb +71 -0
- data/lib/lutaml/model/serialize.rb +125 -35
- data/lib/lutaml/model/type/decimal.rb +0 -4
- data/lib/lutaml/model/type/time.rb +3 -3
- data/lib/lutaml/model/utils.rb +19 -15
- data/lib/lutaml/model/validation.rb +12 -1
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/oga.rb +10 -7
- data/lib/lutaml/model/xml_adapter/builder/ox.rb +20 -13
- data/lib/lutaml/model/xml_adapter/element.rb +32 -0
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +8 -8
- data/lib/lutaml/model/xml_adapter/oga/element.rb +14 -13
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +86 -19
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +19 -15
- data/lib/lutaml/model/xml_adapter/xml_document.rb +74 -13
- data/lib/lutaml/model/xml_adapter/xml_element.rb +57 -3
- data/lib/lutaml/model/xml_mapping.rb +49 -7
- data/lib/lutaml/model/xml_mapping_rule.rb +8 -3
- data/lib/lutaml/model.rb +1 -0
- data/lutaml-model.gemspec +5 -0
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +75 -0
- data/spec/ceramic_spec.rb +39 -0
- data/spec/fixtures/ceramic.rb +23 -0
- data/spec/fixtures/xml/address_example_260.xsd +9 -0
- data/spec/fixtures/xml/user.xsd +10 -0
- data/spec/lutaml/model/cdata_spec.rb +4 -5
- data/spec/lutaml/model/choice_spec.rb +168 -0
- data/spec/lutaml/model/collection_spec.rb +1 -1
- data/spec/lutaml/model/custom_model_spec.rb +6 -7
- data/spec/lutaml/model/custom_serialization_spec.rb +74 -2
- data/spec/lutaml/model/defaults_spec.rb +3 -1
- data/spec/lutaml/model/delegation_spec.rb +7 -5
- data/spec/lutaml/model/enum_spec.rb +35 -0
- data/spec/lutaml/model/group_spec.rb +160 -0
- data/spec/lutaml/model/inheritance_spec.rb +25 -0
- data/spec/lutaml/model/liquefiable_spec.rb +121 -0
- data/spec/lutaml/model/mixed_content_spec.rb +80 -41
- data/spec/lutaml/model/multiple_mapping_spec.rb +22 -10
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +218 -25
- data/spec/lutaml/model/sequence_spec.rb +216 -0
- data/spec/lutaml/model/transformation_spec.rb +230 -0
- data/spec/lutaml/model/type_spec.rb +138 -31
- data/spec/lutaml/model/utils_spec.rb +32 -0
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -7
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +51 -0
- data/spec/lutaml/model/xml_mapping_spec.rb +143 -112
- metadata +67 -2
@@ -0,0 +1,160 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model"
|
3
|
+
|
4
|
+
module GroupSpec
|
5
|
+
class Ceramic < Lutaml::Model::Serializable
|
6
|
+
attribute :type, :string
|
7
|
+
attribute :name, :string
|
8
|
+
|
9
|
+
xml do
|
10
|
+
no_root
|
11
|
+
map_element :type, to: :type
|
12
|
+
map_element :name, to: :name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class CeramicCollection < Lutaml::Model::Serializable
|
17
|
+
attribute :ceramic, Ceramic, collection: 1..2
|
18
|
+
|
19
|
+
xml do
|
20
|
+
root "collection"
|
21
|
+
map_element "ceramic", to: :ceramic
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class AttributeValueType < Lutaml::Model::Type::Decimal
|
26
|
+
end
|
27
|
+
|
28
|
+
class GroupOfItems < Lutaml::Model::Serializable
|
29
|
+
attribute :name, :string
|
30
|
+
attribute :type, :string
|
31
|
+
attribute :description, :string
|
32
|
+
attribute :code, :string
|
33
|
+
|
34
|
+
xml do
|
35
|
+
no_root
|
36
|
+
sequence do
|
37
|
+
map_element "name", to: :name
|
38
|
+
map_element "type", to: :type
|
39
|
+
map_element "description", to: :description,
|
40
|
+
namespace: "http://www.sparxsystems.com/profiles/GML/1.0",
|
41
|
+
prefix: "GML"
|
42
|
+
end
|
43
|
+
map_attribute "code", to: :code, namespace: "http://www.example.com", prefix: "ex1"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ComplexType < Lutaml::Model::Serializable
|
48
|
+
attribute :tag, AttributeValueType
|
49
|
+
attribute :content, :string
|
50
|
+
attribute :group, :string
|
51
|
+
import_model_attributes GroupOfItems
|
52
|
+
|
53
|
+
xml do
|
54
|
+
root "GroupOfItems"
|
55
|
+
map_attribute "tag", to: :tag
|
56
|
+
map_content to: :content
|
57
|
+
map_element :group, to: :group
|
58
|
+
import_model_mappings GroupOfItems
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class SimpleType < Lutaml::Model::Serializable
|
63
|
+
import_model GroupOfItems
|
64
|
+
end
|
65
|
+
|
66
|
+
class GenericType < Lutaml::Model::Serializable
|
67
|
+
import_model_mappings GroupOfItems
|
68
|
+
end
|
69
|
+
|
70
|
+
class GroupWithRoot < Lutaml::Model::Serializable
|
71
|
+
attribute :name, :string
|
72
|
+
|
73
|
+
xml do
|
74
|
+
root "group"
|
75
|
+
map_element :name, to: :name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
RSpec.describe "Group" do
|
81
|
+
context "with no_root" do
|
82
|
+
let(:mapper) { GroupSpec::CeramicCollection }
|
83
|
+
|
84
|
+
it "raises error if root-less class used directly for parsing" do
|
85
|
+
xml = <<~XML
|
86
|
+
<type>Data</type>
|
87
|
+
<name>Smith</name>
|
88
|
+
XML
|
89
|
+
|
90
|
+
expect { GroupSpec::Ceramic.from_xml(xml) }.to raise_error(
|
91
|
+
Lutaml::Model::NoRootMappingError,
|
92
|
+
"GroupSpec::Ceramic has `no_root`, it allowed only for reusable models",
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "raises error if root_less class used for deserializing" do
|
97
|
+
ceramic = GroupSpec::Ceramic.new(type: "Data", name: "Starc")
|
98
|
+
|
99
|
+
expect { ceramic.to_xml }.to raise_error(
|
100
|
+
Lutaml::Model::NoRootMappingError,
|
101
|
+
"GroupSpec::Ceramic has `no_root`, it allowed only for reusable models",
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "correctly get the element of root-less class" do
|
106
|
+
xml = <<~XML
|
107
|
+
<collection>
|
108
|
+
<ceramic>
|
109
|
+
<type>Data</type>
|
110
|
+
</ceramic>
|
111
|
+
</collection>
|
112
|
+
XML
|
113
|
+
|
114
|
+
expect { mapper.from_xml(xml) }.not_to raise_error
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "with model" do
|
119
|
+
it "import attributes" do
|
120
|
+
expect(GroupSpec::ComplexType.attributes).to include(GroupSpec::GroupOfItems.attributes)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "import mappings in xml block" do
|
124
|
+
expect(GroupSpec::ComplexType.mappings_for(:xml).elements).to include(*GroupSpec::GroupOfItems.mappings_for(:xml).elements)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "import mappings outside xml block" do
|
128
|
+
expect(GroupSpec::GenericType.mappings_for(:xml).elements).to include(*GroupSpec::GroupOfItems.mappings_for(:xml).elements)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "import attributes and mappings in xml block" do
|
132
|
+
expect(GroupSpec::ComplexType.attributes).to include(GroupSpec::GroupOfItems.attributes)
|
133
|
+
expect(GroupSpec::ComplexType.mappings_for(:xml).elements).to include(*GroupSpec::GroupOfItems.mappings_for(:xml).elements)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "import attributes and mappings outside the xml block" do
|
137
|
+
expect(GroupSpec::SimpleType.attributes).to include(GroupSpec::GroupOfItems.attributes)
|
138
|
+
expect(GroupSpec::SimpleType.mappings_for(:xml).elements).to include(*GroupSpec::GroupOfItems.mappings_for(:xml).elements)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "raises error if root is defined on imported class" do
|
142
|
+
expect do
|
143
|
+
Class.new(Lutaml::Model::Serializable) do
|
144
|
+
import_model GroupSpec::GroupWithRoot
|
145
|
+
end
|
146
|
+
end.to raise_error(Lutaml::Model::ImportModelWithRootError, "Cannot import a model `GroupSpec::GroupWithRoot` with a root element")
|
147
|
+
end
|
148
|
+
|
149
|
+
it "raises error if namespace is defined with no_root" do
|
150
|
+
expect do
|
151
|
+
Class.new(Lutaml::Model::Serializable) do
|
152
|
+
xml do
|
153
|
+
no_root
|
154
|
+
namespace "http://www.omg.org/spec/XMI/20131001", "xmi"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end.to raise_error(Lutaml::Model::NoRootNamespaceError, "Cannot assign namespace to `no_root`")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -34,6 +34,22 @@ module InheritanceSpec
|
|
34
34
|
map_element "gender", to: :age
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
class ParentWithMapAll < Lutaml::Model::Serializable
|
39
|
+
attribute :id, :string
|
40
|
+
attribute :description, :string
|
41
|
+
|
42
|
+
xml do
|
43
|
+
map_attribute "id", to: :id
|
44
|
+
map_all_content to: :description
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Child < ParentWithMapAll
|
49
|
+
xml do
|
50
|
+
root "child"
|
51
|
+
end
|
52
|
+
end
|
37
53
|
end
|
38
54
|
|
39
55
|
RSpec.describe "Inheritance" do
|
@@ -89,4 +105,13 @@ RSpec.describe "Inheritance" do
|
|
89
105
|
end
|
90
106
|
end
|
91
107
|
end
|
108
|
+
|
109
|
+
context "with map_all in parent" do
|
110
|
+
let(:xml) { "<child id=\"en\">Some <b>bold</b> Content</child>" }
|
111
|
+
|
112
|
+
it "round trip correctly" do
|
113
|
+
parsed = InheritanceSpec::Child.from_xml(xml)
|
114
|
+
expect(parsed.to_xml).to eq(xml)
|
115
|
+
end
|
116
|
+
end
|
92
117
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../../fixtures/address"
|
3
|
+
|
4
|
+
class LiquefiableClass
|
5
|
+
include Lutaml::Model::Liquefiable
|
6
|
+
|
7
|
+
attr_accessor :name, :value
|
8
|
+
|
9
|
+
def initialize(name, value)
|
10
|
+
@name = name
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def display_name
|
15
|
+
"#{name} (#{value})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.describe Lutaml::Model::Liquefiable do
|
20
|
+
before do
|
21
|
+
stub_const("DummyModel", Class.new(LiquefiableClass))
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:dummy) { DummyModel.new("TestName", 42) }
|
25
|
+
|
26
|
+
describe ".register_liquid_drop_class" do
|
27
|
+
context "when drop class does not exist" do
|
28
|
+
it "creates a new drop class" do
|
29
|
+
expect { dummy.class.register_liquid_drop_class }.to change {
|
30
|
+
dummy.class.const_defined?(:DummyModelDrop)
|
31
|
+
}
|
32
|
+
.from(false)
|
33
|
+
.to(true)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when drop class already exists" do
|
38
|
+
it "raises an error" do
|
39
|
+
dummy.class.register_liquid_drop_class
|
40
|
+
expect { dummy.class.register_liquid_drop_class }.to raise_error(RuntimeError, "DummyModelDrop Already exists!")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".drop_class_name" do
|
46
|
+
it "returns the correct drop class name" do
|
47
|
+
expect(dummy.class.drop_class_name).to eq("DummyModelDrop")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe ".drop_class" do
|
52
|
+
context "when drop class exists" do
|
53
|
+
it "returns the drop class" do
|
54
|
+
dummy.class.register_liquid_drop_class
|
55
|
+
expect(dummy.class.drop_class).to eq(DummyModel::DummyModelDrop)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when drop class does not exist" do
|
60
|
+
it "returns nil" do
|
61
|
+
expect(dummy.class.drop_class).to be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe ".register_drop_method" do
|
67
|
+
before do
|
68
|
+
dummy.class.register_liquid_drop_class
|
69
|
+
end
|
70
|
+
|
71
|
+
it "defines a method on the drop class" do
|
72
|
+
expect { dummy.class.register_drop_method(:display_name) }.to change {
|
73
|
+
dummy.to_liquid.respond_to?(:display_name)
|
74
|
+
}
|
75
|
+
.from(false)
|
76
|
+
.to(true)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe ".to_liquid" do
|
81
|
+
before do
|
82
|
+
dummy.class.register_liquid_drop_class
|
83
|
+
dummy.class.register_drop_method(:display_name)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns an instance of the drop class" do
|
87
|
+
expect(dummy.to_liquid).to be_a(dummy.class.drop_class)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "allows access to registered methods via the drop class" do
|
91
|
+
expect(dummy.to_liquid.display_name).to eq("TestName (42)")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "with serializeable classes" do
|
96
|
+
let(:address) do
|
97
|
+
Address.new(
|
98
|
+
{
|
99
|
+
country: "US",
|
100
|
+
post_code: "12345",
|
101
|
+
person: [Person.new, Person.new],
|
102
|
+
},
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
describe ".to_liquid" do
|
107
|
+
it "returns correct drop object" do
|
108
|
+
expect(address.to_liquid).to be_a(Address::AddressDrop)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns array of drops for collection objects" do
|
112
|
+
person_classes = address.to_liquid.person.map(&:class)
|
113
|
+
expect(person_classes).to eq([Person::PersonDrop, Person::PersonDrop])
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns `US` for country" do
|
117
|
+
expect(address.to_liquid.country).to eq("US")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -467,7 +467,9 @@ RSpec.describe "MixedContent" do
|
|
467
467
|
end
|
468
468
|
|
469
469
|
describe ".from_xml" do
|
470
|
-
let(:expected_content)
|
470
|
+
let(:expected_content) do
|
471
|
+
"Moon&Mars Distanced©its — surface covered & processed"
|
472
|
+
end
|
471
473
|
|
472
474
|
it "deserializes special char mixed content correctly" do
|
473
475
|
parsed = MixedContentSpec::SpecialCharContentWithMixedTrue.from_xml(xml)
|
@@ -476,7 +478,9 @@ RSpec.describe "MixedContent" do
|
|
476
478
|
end
|
477
479
|
|
478
480
|
describe ".to_xml" do
|
479
|
-
let(:expected_xml)
|
481
|
+
let(:expected_xml) do
|
482
|
+
"Moon&Mars Distanced©its — surface covered & processed"
|
483
|
+
end
|
480
484
|
|
481
485
|
it "serializes special char mixed content correctly" do
|
482
486
|
parsed = MixedContentSpec::SpecialCharContentWithMixedTrue.from_xml(xml)
|
@@ -522,9 +526,15 @@ RSpec.describe "MixedContent" do
|
|
522
526
|
end
|
523
527
|
|
524
528
|
describe ".from_xml" do
|
525
|
-
let(:expected_nokogiri_content)
|
526
|
-
|
527
|
-
|
529
|
+
let(:expected_nokogiri_content) do
|
530
|
+
"B <p>R&C</p>\n C <p>J—C</p>\n O <p>A & B </p>\n F <p>Z ©S</p>"
|
531
|
+
end
|
532
|
+
let(:expected_ox_content) do
|
533
|
+
"B <p>R&C</p> C <p>J—C</p> O <p>A & B </p> F <p>Z ©S</p>"
|
534
|
+
end
|
535
|
+
let(:expected_oga_content) do
|
536
|
+
"B <p>R&C</p>\n C <p>J—C</p>\n O <p>A & B </p>\n F <p>Z ©S</p>"
|
537
|
+
end
|
528
538
|
|
529
539
|
it "deserializes special char mixed content correctly" do
|
530
540
|
parsed = MixedContentSpec::SpecialCharContentWithRawAndMixedOption.from_xml(xml)
|
@@ -627,7 +637,9 @@ RSpec.describe "MixedContent" do
|
|
627
637
|
end
|
628
638
|
|
629
639
|
describe ".from_xml" do
|
630
|
-
let(:expected_content)
|
640
|
+
let(:expected_content) do
|
641
|
+
"<computer security> type of operation specified by an access right"
|
642
|
+
end
|
631
643
|
|
632
644
|
it "deserializes special char mixed content correctly" do
|
633
645
|
parsed = MixedContentSpec::TextualSupport.from_xml(xml)
|
@@ -637,8 +649,12 @@ RSpec.describe "MixedContent" do
|
|
637
649
|
end
|
638
650
|
|
639
651
|
describe ".to_xml" do
|
640
|
-
let(:expected_xml)
|
641
|
-
|
652
|
+
let(:expected_xml) do
|
653
|
+
"<TextualSupport>\n <value><computer security> type of operation specified by an access right</value>\n</TextualSupport>"
|
654
|
+
end
|
655
|
+
let(:expected_oga_xml) do
|
656
|
+
"<TextualSupport><value><computer security> type of operation specified by an access right</value></TextualSupport>"
|
657
|
+
end
|
642
658
|
|
643
659
|
it "serializes special char mixed content correctly" do
|
644
660
|
parsed = MixedContentSpec::TextualSupport.from_xml(xml)
|
@@ -659,7 +675,9 @@ RSpec.describe "MixedContent" do
|
|
659
675
|
end
|
660
676
|
|
661
677
|
describe ".from_xml" do
|
662
|
-
let(:expected_content)
|
678
|
+
let(:expected_content) do
|
679
|
+
"∑computer security∏ type of operation specified µ by an access right"
|
680
|
+
end
|
663
681
|
|
664
682
|
it "deserializes special char mixed content correctly" do
|
665
683
|
parsed = MixedContentSpec::HexCode.from_xml(xml)
|
@@ -670,7 +688,9 @@ RSpec.describe "MixedContent" do
|
|
670
688
|
|
671
689
|
describe ".to_xml" do
|
672
690
|
context "when default encoding xml" do
|
673
|
-
let(:expected_default_encoding_xml)
|
691
|
+
let(:expected_default_encoding_xml) do
|
692
|
+
"∑computer security∏ type of operation specified µ by an access right"
|
693
|
+
end
|
674
694
|
|
675
695
|
it "serializes special char mixed content correctly with default encoding: UTF-8" do
|
676
696
|
parsed = MixedContentSpec::HexCode.from_xml(xml)
|
@@ -681,20 +701,36 @@ RSpec.describe "MixedContent" do
|
|
681
701
|
end
|
682
702
|
|
683
703
|
context "when encoding: nil xml" do
|
684
|
-
let(:expected_encoding_nil_nokogiri_xml)
|
685
|
-
|
704
|
+
let(:expected_encoding_nil_nokogiri_xml) do
|
705
|
+
"∑computer security∏ type of ​ operation specified µ by an access right"
|
706
|
+
end
|
707
|
+
let(:expected_encoding_nil_ox_xml) do
|
708
|
+
"<HexCode> \xE2\x88\x91computer security\xE2\x88\x8F type of \xE2\x80\x8B operation specified \xC2\xB5 by an access right </HexCode>\n".force_encoding("ASCII-8BIT")
|
709
|
+
end
|
710
|
+
let(:expected_encoding_nil_oga_xml) do
|
711
|
+
"<HexCode>\n ∑computer security∏ type of operation specified µ by an access right\n</HexCode>"
|
712
|
+
end
|
686
713
|
|
687
714
|
it "serializes special char mixed content correctly with encoding: nil to get hexcode" do
|
688
|
-
parsed = MixedContentSpec::HexCode.from_xml(xml)
|
715
|
+
parsed = MixedContentSpec::HexCode.from_xml(xml, encoding: nil)
|
689
716
|
serialized = parsed.to_xml(encoding: nil)
|
690
717
|
|
691
718
|
expected_output = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
692
719
|
expected_encoding_nil_nokogiri_xml
|
693
|
-
|
720
|
+
elsif adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
|
694
721
|
expected_encoding_nil_ox_xml
|
722
|
+
else
|
723
|
+
expected_encoding_nil_oga_xml
|
695
724
|
end
|
696
725
|
|
697
|
-
expect(
|
726
|
+
expect(parsed.encoding).to be_nil
|
727
|
+
expect(serialized.strip).to include(expected_output.strip)
|
728
|
+
|
729
|
+
if adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
|
730
|
+
expect(serialized.encoding.to_s).to eq("ASCII-8BIT")
|
731
|
+
else
|
732
|
+
expect(serialized.encoding.to_s).to eq("UTF-8")
|
733
|
+
end
|
698
734
|
end
|
699
735
|
end
|
700
736
|
end
|
@@ -702,7 +738,9 @@ RSpec.describe "MixedContent" do
|
|
702
738
|
|
703
739
|
context "when use encoding in parsing" do
|
704
740
|
context "when use SHIFT-JIS encoding" do
|
705
|
-
let(:fixture)
|
741
|
+
let(:fixture) do
|
742
|
+
File.read(fixture_path("xml/shift_jis.xml"), encoding: "Shift_JIS")
|
743
|
+
end
|
706
744
|
|
707
745
|
describe ".from_xml" do
|
708
746
|
it "verifies the encoding of file read" do
|
@@ -712,10 +750,10 @@ RSpec.describe "MixedContent" do
|
|
712
750
|
it "deserializes SHIFT encoded content correctly with explicit encoding option" do
|
713
751
|
parsed = MixedContentSpec::Shift.from_xml(fixture, encoding: "Shift_JIS")
|
714
752
|
|
715
|
-
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::
|
716
|
-
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
717
|
-
else
|
753
|
+
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
718
754
|
"手書き英字1"
|
755
|
+
else
|
756
|
+
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
719
757
|
end
|
720
758
|
|
721
759
|
expect(parsed.field).to include(expected_content)
|
@@ -725,13 +763,12 @@ RSpec.describe "MixedContent" do
|
|
725
763
|
parsed = MixedContentSpec::Shift.from_xml(fixture)
|
726
764
|
|
727
765
|
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
728
|
-
"�菑���p���P"
|
729
|
-
elsif adapter_class == Lutaml::Model::XmlAdapter::OgaAdapter
|
730
766
|
"手書き英字1"
|
731
767
|
else
|
732
|
-
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("
|
768
|
+
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
733
769
|
end
|
734
770
|
|
771
|
+
expect(parsed.encoding).to eq("Shift_JIS")
|
735
772
|
expect(parsed.field).to include(expected_content)
|
736
773
|
end
|
737
774
|
end
|
@@ -748,13 +785,13 @@ RSpec.describe "MixedContent" do
|
|
748
785
|
parsed = MixedContentSpec::Shift.from_xml(fixture, encoding: "Shift_JIS")
|
749
786
|
serialized = parsed.to_xml(encoding: "UTF-8")
|
750
787
|
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
788
|
+
parsed_xml = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
789
|
+
"手書き英字1"
|
790
|
+
else
|
791
|
+
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
792
|
+
end
|
756
793
|
|
757
|
-
expect(parsed.field).to include(
|
794
|
+
expect(parsed.field).to include(parsed_xml)
|
758
795
|
expect(parsed.encoding).to eq("Shift_JIS")
|
759
796
|
|
760
797
|
expect(serialized).to include("手書き英字1")
|
@@ -765,10 +802,10 @@ RSpec.describe "MixedContent" do
|
|
765
802
|
parsed = MixedContentSpec::Shift.from_xml(fixture, encoding: "Shift_JIS")
|
766
803
|
serialized = parsed.to_xml(encoding: "Shift_JIS")
|
767
804
|
|
768
|
-
expected_xml = if adapter_class == Lutaml::Model::XmlAdapter::
|
769
|
-
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
770
|
-
else
|
805
|
+
expected_xml = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
771
806
|
"手書き英字1"
|
807
|
+
else
|
808
|
+
"\x8E\xE8\x8F\x91\x82\xAB\x89p\x8E\x9A\x82P".force_encoding("Shift_JIS")
|
772
809
|
end
|
773
810
|
|
774
811
|
expect(parsed.field).to include(expected_xml)
|
@@ -788,16 +825,18 @@ RSpec.describe "MixedContent" do
|
|
788
825
|
expect(serialized.encoding.to_s).to eq("Shift_JIS")
|
789
826
|
end
|
790
827
|
|
791
|
-
it "serializes SHIFT-JIS content
|
828
|
+
it "serializes SHIFT-JIS content correctly bcz xml.encoding used during parsing" do
|
792
829
|
parsed = MixedContentSpec::Shift.from_xml(fixture)
|
793
830
|
serialized = parsed.to_xml(encoding: "Shift_JIS")
|
831
|
+
|
794
832
|
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
795
|
-
"<root>\n <FieldName
|
833
|
+
"<root>\n <FieldName>手書き英字1</FieldName>\n <FieldName>123456</FieldName>\n</root>".encode("Shift_JIS")
|
796
834
|
elsif adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
|
797
|
-
"<root>\n <FieldName
|
835
|
+
"<root>\n <FieldName>手書き英字1</FieldName>\n <FieldName>123456</FieldName>\n</root>\n".encode("Shift_JIS")
|
798
836
|
else
|
799
837
|
"<root><FieldName>手書き英字1</FieldName><FieldName>123456</FieldName></root>".encode("Shift_JIS")
|
800
838
|
end
|
839
|
+
|
801
840
|
expect(serialized).to eq(expected_content)
|
802
841
|
end
|
803
842
|
|
@@ -829,27 +868,27 @@ RSpec.describe "MixedContent" do
|
|
829
868
|
it "deserializes latin encoded content correctly" do
|
830
869
|
parsed = MixedContentSpec::Latin.from_xml(fixture, encoding: "ISO-8859-1")
|
831
870
|
|
832
|
-
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::
|
833
|
-
["M\xFCller".force_encoding("ISO-8859-1"), "Jos\xE9".force_encoding("ISO-8859-1")]
|
834
|
-
else
|
871
|
+
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
835
872
|
["Müller", "José"]
|
873
|
+
else
|
874
|
+
["M\xFCller".force_encoding("ISO-8859-1"), "Jos\xE9".force_encoding("ISO-8859-1")]
|
836
875
|
end
|
837
876
|
|
877
|
+
expect(parsed.encoding).to eq("ISO-8859-1")
|
838
878
|
expect(parsed.from).to eq(expected_content[0])
|
839
879
|
expect(parsed.the).to eq(expected_content[1])
|
840
880
|
end
|
841
881
|
|
842
|
-
it "deserializes latin encoded content
|
882
|
+
it "deserializes latin encoded content correctly, bcz xml.encoding used for parsing" do
|
843
883
|
parsed = MixedContentSpec::Latin.from_xml(fixture)
|
844
884
|
|
845
885
|
expected_content = if adapter_class == Lutaml::Model::XmlAdapter::NokogiriAdapter
|
846
|
-
["M�ller", "Jos�"]
|
847
|
-
elsif adapter_class == Lutaml::Model::XmlAdapter::OgaAdapter
|
848
886
|
["Müller", "José"]
|
849
887
|
else
|
850
|
-
["M\xFCller", "Jos\xE9"]
|
888
|
+
["M\xFCller".force_encoding("ISO-8859-1"), "Jos\xE9".force_encoding("ISO-8859-1")]
|
851
889
|
end
|
852
890
|
|
891
|
+
expect(parsed.encoding).to eq("ISO-8859-1")
|
853
892
|
expect(parsed.from).to eq(expected_content[0])
|
854
893
|
expect(parsed.the).to eq(expected_content[1])
|
855
894
|
end
|
@@ -106,7 +106,7 @@ module MultipleMapping
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def name_from_xml(model, value)
|
109
|
-
model.full_name = value.sub(/^XML Model: /, "")
|
109
|
+
model.full_name = value.text.sub(/^XML Model: /, "")
|
110
110
|
end
|
111
111
|
|
112
112
|
def color_to_xml(model, parent, doc)
|
@@ -116,7 +116,7 @@ module MultipleMapping
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def color_from_xml(model, value)
|
119
|
-
model.color = value.downcase
|
119
|
+
model.color = value.text.downcase
|
120
120
|
end
|
121
121
|
|
122
122
|
def size_to_xml(model, parent, doc)
|
@@ -126,7 +126,7 @@ module MultipleMapping
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def size_from_xml(model, value)
|
129
|
-
model.size = (value.to_i || 0) - 10
|
129
|
+
model.size = (value.text.to_i || 0) - 10
|
130
130
|
end
|
131
131
|
|
132
132
|
def desc_to_xml(model, parent, doc)
|
@@ -136,7 +136,7 @@ module MultipleMapping
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def desc_from_xml(model, value)
|
139
|
-
model.description = value.sub(/^XML Description: /, "")
|
139
|
+
model.description = value.text.sub(/^XML Description: /, "")
|
140
140
|
end
|
141
141
|
end
|
142
142
|
end
|
@@ -144,8 +144,12 @@ end
|
|
144
144
|
RSpec.describe MultipleMapping do
|
145
145
|
context "with key-value formats" do
|
146
146
|
context "with YAML format" do
|
147
|
-
let(:yaml_with_name)
|
148
|
-
|
147
|
+
let(:yaml_with_name) do
|
148
|
+
"product_name: Coffee Maker\ndescription: Premium coffee maker"
|
149
|
+
end
|
150
|
+
let(:yaml_with_desc) do
|
151
|
+
"---\nname: Coffee Maker\ndesc: Premium coffee maker\n"
|
152
|
+
end
|
149
153
|
|
150
154
|
it "handles bidirectional conversion" do
|
151
155
|
product1 = MultipleMapping::Product.from_yaml(yaml_with_name)
|
@@ -161,8 +165,12 @@ RSpec.describe MultipleMapping do
|
|
161
165
|
end
|
162
166
|
|
163
167
|
context "with JSON format" do
|
164
|
-
let(:json_with_name)
|
165
|
-
|
168
|
+
let(:json_with_name) do
|
169
|
+
'{"product_name":"Coffee Maker","description":"Premium coffee maker"}'
|
170
|
+
end
|
171
|
+
let(:json_with_desc) do
|
172
|
+
'{"name":"Coffee Maker","desc":"Premium coffee maker"}'
|
173
|
+
end
|
166
174
|
|
167
175
|
it "handles bidirectional conversion" do
|
168
176
|
product1 = MultipleMapping::Product.from_json(json_with_name)
|
@@ -254,8 +262,12 @@ RSpec.describe MultipleMapping do
|
|
254
262
|
|
255
263
|
context "with CustomModel" do
|
256
264
|
context "with JSON format" do
|
257
|
-
let(:json_with_alternate)
|
258
|
-
|
265
|
+
let(:json_with_alternate) do
|
266
|
+
'{"custom_name":"JSON Model: Vase","shade":"BLUE","dimension":22,"description":"JSON Description: A beautiful ceramic vase"}'
|
267
|
+
end
|
268
|
+
let(:json_with_standard) do
|
269
|
+
'{"name":"JSON Model: Vase","color":"BLUE","size":22,"desc":"JSON Description: A beautiful ceramic vase"}'
|
270
|
+
end
|
259
271
|
|
260
272
|
it "handles bidirectional conversion with custom methods" do
|
261
273
|
model1 = MultipleMapping::CustomModel.from_json(json_with_alternate)
|