lutaml-model 0.6.0 → 0.6.2

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos.json +2 -1
  3. data/.rubocop_todo.yml +10 -80
  4. data/lib/lutaml/model/attribute.rb +9 -5
  5. data/lib/lutaml/model/schema/xml_compiler.rb +3 -1
  6. data/lib/lutaml/model/serialize.rb +6 -8
  7. data/lib/lutaml/model/type/float.rb +0 -4
  8. data/lib/lutaml/model/version.rb +1 -1
  9. data/lib/lutaml/model/xml_adapter/xml_document.rb +0 -4
  10. data/lib/lutaml/model/xml_adapter/xml_element.rb +1 -3
  11. data/spec/address_spec.rb +3 -3
  12. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +3 -3
  13. data/spec/lutaml/model/collection_spec.rb +0 -16
  14. data/spec/lutaml/model/custom_model_spec.rb +49 -1
  15. data/spec/lutaml/model/json_adapter_spec.rb +26 -24
  16. data/spec/lutaml/model/key_value_mapping_spec.rb +1 -13
  17. data/spec/lutaml/model/schema/json_schema_spec.rb +12 -12
  18. data/spec/lutaml/model/schema/relaxng_schema_spec.rb +12 -12
  19. data/spec/lutaml/model/schema/xml_compiler_spec.rb +447 -147
  20. data/spec/lutaml/model/schema/xsd_schema_spec.rb +12 -12
  21. data/spec/lutaml/model/schema/yaml_schema_spec.rb +12 -12
  22. data/spec/lutaml/model/sequence_spec.rb +129 -113
  23. data/spec/lutaml/model/toml_adapter_spec.rb +27 -25
  24. data/spec/lutaml/model/transformation_spec.rb +80 -80
  25. data/spec/lutaml/model/type/boolean_spec.rb +4 -10
  26. data/spec/lutaml/model/type/decimal_spec.rb +3 -3
  27. data/spec/lutaml/model/type/hash_spec.rb +39 -26
  28. data/spec/lutaml/model/type/integer_spec.rb +2 -2
  29. data/spec/lutaml/model/type/time_without_date_spec.rb +0 -6
  30. data/spec/lutaml/model/type_spec.rb +6 -26
  31. data/spec/lutaml/model/utils_spec.rb +25 -30
  32. data/spec/lutaml/model/validation_spec.rb +9 -6
  33. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  34. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  35. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +280 -281
  36. data/spec/lutaml/model/xml_adapter_spec.rb +128 -120
  37. data/spec/lutaml/model/xml_mapping_spec.rb +47 -16
  38. data/spec/person_spec.rb +6 -16
  39. metadata +2 -2
@@ -1,21 +1,21 @@
1
1
  require "spec_helper"
2
2
  require "lutaml/model/schema"
3
3
 
4
- RSpec.describe Lutaml::Model::Schema::XsdSchema do
5
- module SchemaGeneration
6
- class Glaze < Lutaml::Model::Serializable
7
- attribute :color, Lutaml::Model::Type::String
8
- attribute :finish, Lutaml::Model::Type::String
9
- end
4
+ module SchemaGeneration
5
+ class Glaze < Lutaml::Model::Serializable
6
+ attribute :color, Lutaml::Model::Type::String
7
+ attribute :finish, Lutaml::Model::Type::String
8
+ end
10
9
 
11
- class Vase < Lutaml::Model::Serializable
12
- attribute :height, Lutaml::Model::Type::Float
13
- attribute :diameter, Lutaml::Model::Type::Float
14
- attribute :glaze, Glaze
15
- attribute :materials, Lutaml::Model::Type::String, collection: true
16
- end
10
+ class Vase < Lutaml::Model::Serializable
11
+ attribute :height, Lutaml::Model::Type::Float
12
+ attribute :diameter, Lutaml::Model::Type::Float
13
+ attribute :glaze, Glaze
14
+ attribute :materials, Lutaml::Model::Type::String, collection: true
17
15
  end
16
+ end
18
17
 
18
+ RSpec.describe Lutaml::Model::Schema::XsdSchema do
19
19
  describe ".generate" do
20
20
  it "generates an XSD schema for nested Serialize objects" do
21
21
  schema = described_class.generate(SchemaGeneration::Vase, pretty: true)
@@ -1,21 +1,21 @@
1
1
  require "spec_helper"
2
2
  require "lutaml/model/schema"
3
3
 
4
- RSpec.describe Lutaml::Model::Schema::YamlSchema do
5
- module SchemaGeneration
6
- class Glaze < Lutaml::Model::Serializable
7
- attribute :color, Lutaml::Model::Type::String
8
- attribute :finish, Lutaml::Model::Type::String
9
- end
4
+ module SchemaGeneration
5
+ class Glaze < Lutaml::Model::Serializable
6
+ attribute :color, Lutaml::Model::Type::String
7
+ attribute :finish, Lutaml::Model::Type::String
8
+ end
10
9
 
11
- class Vase < Lutaml::Model::Serializable
12
- attribute :height, Lutaml::Model::Type::Float
13
- attribute :diameter, Lutaml::Model::Type::Float
14
- attribute :glaze, Glaze
15
- attribute :materials, Lutaml::Model::Type::String, collection: true
16
- end
10
+ class Vase < Lutaml::Model::Serializable
11
+ attribute :height, Lutaml::Model::Type::Float
12
+ attribute :diameter, Lutaml::Model::Type::Float
13
+ attribute :glaze, Glaze
14
+ attribute :materials, Lutaml::Model::Type::String, collection: true
17
15
  end
16
+ end
18
17
 
18
+ RSpec.describe Lutaml::Model::Schema::YamlSchema do
19
19
  describe ".generate" do
20
20
  it "generates a YAML schema for nested Serialize objects" do
21
21
  schema = described_class.generate(SchemaGeneration::Vase)
@@ -56,45 +56,10 @@ RSpec.describe "Sequence" do
56
56
  context "with nesting sequence" do
57
57
  let(:mapper) { SequenceSpec::Ceramic }
58
58
 
59
- it "don't raise error for a valid instance, if given attribute for sequence has correct order" do
60
- xml = <<~XML
61
- <Ceramic>
62
- <tag>Nik</tag>
63
- <id>1</id>
64
- <name>Vase</name>
65
- <type>Decorative</type>
66
- <color>Blue</color>
67
- <bold>Heading</bold>
68
- <text>Header</text>
69
- <usage>Indoor</usage>
70
- <size>Medium</size>
71
- <first_name>Dale</first_name>
72
- <last_name>Steyn</last_name>
73
- <temperature>Normal</temperature>
74
- </Ceramic>
75
- XML
76
-
77
- expect { mapper.from_xml(xml) }.not_to raise_error
78
- end
79
-
80
- it "don't raise error for a valid instance with sequence range, if given attribute for sequence has correct order" do
81
- xml = <<~XML
82
- <collection>
83
- <ceramic>
84
- <tag>Nik</tag>
85
- <id>1</id>
86
- <name>Vase</name>
87
- <type>Decorative</type>
88
- <color>Blue</color>
89
- <bold>Heading</bold>
90
- <text>Header</text>
91
- <usage>Indoor</usage>
92
- <size>Medium</size>
93
- <first_name>Dale</first_name>
94
- <last_name>Steyn</last_name>
95
- <temperature>Normal</temperature>
96
- </ceramic>
97
- <ceramic>
59
+ context "when given attribute for sequence has correct order" do
60
+ let(:xml) do
61
+ <<~XML
62
+ <Ceramic>
98
63
  <tag>Nik</tag>
99
64
  <id>1</id>
100
65
  <name>Vase</name>
@@ -107,95 +72,146 @@ RSpec.describe "Sequence" do
107
72
  <first_name>Dale</first_name>
108
73
  <last_name>Steyn</last_name>
109
74
  <temperature>Normal</temperature>
110
- </ceramic>
111
- </collection>
112
- XML
75
+ </Ceramic>
76
+ XML
77
+ end
113
78
 
114
- expect do
115
- SequenceSpec::CeramicCollection.from_xml(xml)
116
- end.not_to raise_error
79
+ it "does not raise error" do
80
+ expect { mapper.from_xml(xml) }.not_to raise_error
81
+ end
117
82
  end
118
83
 
119
- it "raises error, if given attributes order is incorrect in sequence" do
120
- xml = <<~XML
121
- <Ceramic>
122
- <tag>Nik</tag>
123
- <temperature>High</temperature>
124
- <first_name>Micheal</first_name>
125
- <id>1</id>
126
- <name>Vase</name>
127
- <type>Decorative</type>
128
- <color>Blue</color>
129
- <bold>Heading</bold>
130
- <usage>Indoor</usage>
131
- <size>Medium</size>
132
- <last_name>Johnson</last_name>
133
- <text>Header</text>
134
- </Ceramic>
135
- XML
84
+ context "when given attribute for sequence collection has correct order" do
85
+ let(:xml) do
86
+ <<~XML
87
+ <collection>
88
+ <ceramic>
89
+ <tag>Nik</tag>
90
+ <id>1</id>
91
+ <name>Vase</name>
92
+ <type>Decorative</type>
93
+ <color>Blue</color>
94
+ <bold>Heading</bold>
95
+ <text>Header</text>
96
+ <usage>Indoor</usage>
97
+ <size>Medium</size>
98
+ <first_name>Dale</first_name>
99
+ <last_name>Steyn</last_name>
100
+ <temperature>Normal</temperature>
101
+ </ceramic>
102
+ <ceramic>
103
+ <tag>Nik</tag>
104
+ <id>1</id>
105
+ <name>Vase</name>
106
+ <type>Decorative</type>
107
+ <color>Blue</color>
108
+ <bold>Heading</bold>
109
+ <text>Header</text>
110
+ <usage>Indoor</usage>
111
+ <size>Medium</size>
112
+ <first_name>Dale</first_name>
113
+ <last_name>Steyn</last_name>
114
+ <temperature>Normal</temperature>
115
+ </ceramic>
116
+ </collection>
117
+ XML
118
+ end
136
119
 
137
- expect do
138
- mapper.from_xml(xml)
139
- end.to raise_error(Lutaml::Model::IncorrectSequenceError) do |error|
140
- expect(error.message).to eq("Element `usage` does not match the expected sequence order element `text`")
120
+ it "does not raise error" do
121
+ expect do
122
+ SequenceSpec::CeramicCollection.from_xml(xml)
123
+ end.not_to raise_error
141
124
  end
142
125
  end
143
126
 
144
- it "raises error with sequence range, if given attributes order is incorrect in sequence" do
145
- invalid_xml = <<~XML
146
- <collection>
147
- <ceramic>
127
+ context "when given attributes order is incorrect in sequence" do
128
+ let(:xml) do
129
+ <<~XML
130
+ <Ceramic>
131
+ <tag>Nik</tag>
132
+ <temperature>High</temperature>
133
+ <first_name>Micheal</first_name>
148
134
  <id>1</id>
149
135
  <name>Vase</name>
150
136
  <type>Decorative</type>
151
137
  <color>Blue</color>
152
138
  <bold>Heading</bold>
153
- <text>Header</text>
154
139
  <usage>Indoor</usage>
155
140
  <size>Medium</size>
156
- <first_name>Dale</first_name>
157
- <last_name>Steyn</last_name>
158
- <temperature>Normal</temperature>
159
- <tag>Nik</tag>
160
- </ceramic>
161
-
162
- <ceramic>
163
- <id>2</id>
164
- <name>Nick</name>
165
- <type>Unique</type>
166
- <color>Red</color>
167
- <bold>Name</bold>
168
- <text>Body</text>
169
- <usage>Outdoor</usage>
170
- <size>Small</size>
171
- <first_name>Smith</first_name>
172
- <last_name>Ash</last_name>
173
- <temperature>High</temperature>
174
- <tag>Adid</tag>
175
- </ceramic>
176
-
177
- <ceramic>
178
- <id>3</id>
179
- <name>Starc</name>
180
- <type>Int</type>
181
- <color>White</color>
182
- <bold>Act</bold>
183
- <text>Footer</text>
184
- <usage>Nothing</usage>
185
- <size>Large</size>
186
- <first_name>Dale</first_name>
187
- <last_name>Steyn</last_name>
188
- <temperature>Normal</temperature>
189
- <tag>Bet</tag>
190
- </ceramic>
191
- </collection>
192
- XML
141
+ <last_name>Johnson</last_name>
142
+ <text>Header</text>
143
+ </Ceramic>
144
+ XML
145
+ end
193
146
 
194
- expect do
195
- SequenceSpec::CeramicCollection.from_xml(invalid_xml).validate!
196
- end.to raise_error(Lutaml::Model::ValidationError) do |error|
197
- expect(error).to include(Lutaml::Model::CollectionCountOutOfRangeError)
198
- expect(error.error_messages).to eq(["ceramic count is 3, must be between 1 and 2"])
147
+ it "raises IncorrectSequenceError error" do
148
+ expect do
149
+ mapper.from_xml(xml)
150
+ end.to raise_error(Lutaml::Model::IncorrectSequenceError) do |error|
151
+ expect(error.message).to eq("Element `usage` does not match the expected sequence order element `text`")
152
+ end
153
+ end
154
+ end
155
+
156
+ context "when given attributes order is incorrect in sequence collection" do
157
+ let(:xml) do
158
+ <<~XML
159
+ <collection>
160
+ <ceramic>
161
+ <id>1</id>
162
+ <name>Vase</name>
163
+ <type>Decorative</type>
164
+ <color>Blue</color>
165
+ <bold>Heading</bold>
166
+ <text>Header</text>
167
+ <usage>Indoor</usage>
168
+ <size>Medium</size>
169
+ <first_name>Dale</first_name>
170
+ <last_name>Steyn</last_name>
171
+ <temperature>Normal</temperature>
172
+ <tag>Nik</tag>
173
+ </ceramic>
174
+
175
+ <ceramic>
176
+ <id>2</id>
177
+ <name>Nick</name>
178
+ <type>Unique</type>
179
+ <color>Red</color>
180
+ <bold>Name</bold>
181
+ <text>Body</text>
182
+ <usage>Outdoor</usage>
183
+ <size>Small</size>
184
+ <first_name>Smith</first_name>
185
+ <last_name>Ash</last_name>
186
+ <temperature>High</temperature>
187
+ <tag>Adid</tag>
188
+ </ceramic>
189
+
190
+ <ceramic>
191
+ <id>3</id>
192
+ <name>Starc</name>
193
+ <type>Int</type>
194
+ <color>White</color>
195
+ <bold>Act</bold>
196
+ <text>Footer</text>
197
+ <usage>Nothing</usage>
198
+ <size>Large</size>
199
+ <first_name>Dale</first_name>
200
+ <last_name>Steyn</last_name>
201
+ <temperature>Normal</temperature>
202
+ <tag>Bet</tag>
203
+ </ceramic>
204
+ </collection>
205
+ XML
206
+ end
207
+
208
+ it "raises CollectionCountOutOfRangeError error" do
209
+ expect do
210
+ SequenceSpec::CeramicCollection.from_xml(xml).validate!
211
+ end.to raise_error(Lutaml::Model::ValidationError) do |error|
212
+ expect(error).to include(Lutaml::Model::CollectionCountOutOfRangeError)
213
+ expect(error.error_messages).to eq(["ceramic count is 3, must be between 1 and 2"])
214
+ end
199
215
  end
200
216
  end
201
217
 
@@ -3,37 +3,39 @@ require "lutaml/model/toml_adapter/toml_rb_adapter"
3
3
  require "lutaml/model/toml_adapter/tomlib_adapter"
4
4
  require_relative "../../fixtures/sample_model"
5
5
 
6
- RSpec.shared_examples "a TOML adapter" do |adapter_class|
7
- let(:attributes) { { name: "John Doe", age: 30 } }
8
- let(:model) { SampleModel.new(attributes) }
9
-
10
- let(:expected_toml) do
11
- if adapter_class == Lutaml::Model::TomlAdapter::TomlRbAdapter
12
- TomlRB.dump(attributes)
13
- elsif adapter_class == Lutaml::Model::TomlAdapter::TomlibAdapter
14
- Tomlib.dump(attributes)
6
+ RSpec.describe "TomlAdapter" do
7
+ shared_examples "a TOML adapter" do |adapter_class|
8
+ let(:attributes) { { name: "John Doe", age: 30 } }
9
+ let(:model) { SampleModel.new(attributes) }
10
+
11
+ let(:expected_toml) do
12
+ if adapter_class == Lutaml::Model::TomlAdapter::TomlRbAdapter
13
+ TomlRB.dump(attributes)
14
+ elsif adapter_class == Lutaml::Model::TomlAdapter::TomlibAdapter
15
+ Tomlib.dump(attributes)
16
+ end
15
17
  end
16
- end
17
18
 
18
- it "serializes to TOML" do
19
- toml = adapter_class.new(attributes).to_toml
19
+ it "serializes to TOML" do
20
+ toml = adapter_class.new(attributes).to_toml
20
21
 
21
- expect(toml).to eq(expected_toml)
22
- end
22
+ expect(toml).to eq(expected_toml)
23
+ end
23
24
 
24
- it "deserializes from TOML" do
25
- doc = adapter_class.parse(expected_toml)
26
- new_model = SampleModel.new(doc.to_h)
25
+ it "deserializes from TOML" do
26
+ doc = adapter_class.parse(expected_toml)
27
+ new_model = SampleModel.new(doc.to_h)
27
28
 
28
- expect(new_model.name).to eq("John Doe")
29
- expect(new_model.age).to eq(30)
29
+ expect(new_model.name).to eq("John Doe")
30
+ expect(new_model.age).to eq(30)
31
+ end
30
32
  end
31
- end
32
33
 
33
- RSpec.describe Lutaml::Model::TomlAdapter::TomlRbAdapter do
34
- it_behaves_like "a TOML adapter", described_class
35
- end
34
+ describe Lutaml::Model::TomlAdapter::TomlRbAdapter do
35
+ it_behaves_like "a TOML adapter", described_class
36
+ end
36
37
 
37
- RSpec.describe Lutaml::Model::TomlAdapter::TomlibAdapter do
38
- it_behaves_like "a TOML adapter", described_class
38
+ describe Lutaml::Model::TomlAdapter::TomlibAdapter do
39
+ it_behaves_like "a TOML adapter", described_class
40
+ end
39
41
  end
@@ -1,97 +1,97 @@
1
1
  require "spec_helper"
2
2
 
3
- RSpec.describe "Value Transformations" do
4
- module TransformationSpec
5
- # Class with only attribute-level transformations
6
- class AttributeTransformPerson < Lutaml::Model::Serializable
7
- attribute :name, :string, transform: {
8
- export: ->(value) { value.to_s.upcase },
3
+ module TransformationSpec
4
+ # Class with only attribute-level transformations
5
+ class AttributeTransformPerson < Lutaml::Model::Serializable
6
+ attribute :name, :string, transform: {
7
+ export: ->(value) { value.to_s.upcase },
8
+ }
9
+ attribute :email, :string, transform: {
10
+ import: ->(value) { "#{value}@example.com" },
11
+ }
12
+ attribute :tags, :string, collection: true, transform: {
13
+ export: ->(value) { value.map(&:upcase) },
14
+ import: ->(value) { value.map { |v| "#{v}-1" } },
15
+ }
16
+ end
17
+
18
+ # Class with only mapping-level transformations
19
+ class MappingTransformPerson < Lutaml::Model::Serializable
20
+ attribute :name, :string
21
+ attribute :email, :string
22
+ attribute :tags, :string, collection: true
23
+
24
+ json do
25
+ map "fullName", to: :name, transform: {
26
+ export: ->(value) { "Dr. #{value}" },
9
27
  }
10
- attribute :email, :string, transform: {
11
- import: ->(value) { "#{value}@example.com" },
28
+ map "emailAddress", to: :email, transform: {
29
+ import: ->(value) { value.gsub("at", "@") },
12
30
  }
13
- attribute :tags, :string, collection: true, transform: {
14
- export: ->(value) { value.map(&:upcase) },
15
- import: ->(value) { value.map { |v| "#{v}-1" } },
31
+ map "labels", to: :tags, transform: {
32
+ export: ->(value) { value.join("-|-") },
33
+ import: ->(value) { value.split("|") },
16
34
  }
17
35
  end
18
36
 
19
- # Class with only mapping-level transformations
20
- class MappingTransformPerson < Lutaml::Model::Serializable
21
- attribute :name, :string
22
- attribute :email, :string
23
- attribute :tags, :string, collection: true
24
-
25
- json do
26
- map "fullName", to: :name, transform: {
27
- export: ->(value) { "Dr. #{value}" },
28
- }
29
- map "emailAddress", to: :email, transform: {
30
- import: ->(value) { value.gsub("at", "@") },
31
- }
32
- map "labels", to: :tags, transform: {
33
- export: ->(value) { value.join("-|-") },
34
- import: ->(value) { value.split("|") },
35
- }
36
- end
37
-
38
- xml do
39
- root "person"
40
- map_element "full-name", to: :name, transform: {
41
- export: ->(value) { "Dr. #{value}" },
42
- }
43
- map_element "email-address", to: :email, transform: {
44
- import: ->(value) { value.gsub("at", "@") },
45
- }
46
- map_element "labels", to: :tags, transform: {
47
- export: ->(value) { value.join("-|-") },
48
- import: ->(value) { value.split("|") },
49
- }
50
- end
51
- end
52
-
53
- # Class with both attribute and mapping transformations
54
- class CombinedTransformPerson < Lutaml::Model::Serializable
55
- attribute :name, :string, transform: {
56
- export: ->(value) { value.to_s.capitalize },
57
- import: ->(value) { value.to_s.downcase },
37
+ xml do
38
+ root "person"
39
+ map_element "full-name", to: :name, transform: {
40
+ export: ->(value) { "Dr. #{value}" },
58
41
  }
59
- attribute :email, :string, transform: {
60
- export: lambda(&:downcase),
61
- import: lambda(&:downcase),
42
+ map_element "email-address", to: :email, transform: {
43
+ import: ->(value) { value.gsub("at", "@") },
44
+ }
45
+ map_element "labels", to: :tags, transform: {
46
+ export: ->(value) { value.join("-|-") },
47
+ import: ->(value) { value.split("|") },
48
+ }
49
+ end
50
+ end
51
+
52
+ # Class with both attribute and mapping transformations
53
+ class CombinedTransformPerson < Lutaml::Model::Serializable
54
+ attribute :name, :string, transform: {
55
+ export: ->(value) { value.to_s.capitalize },
56
+ import: ->(value) { value.to_s.downcase },
57
+ }
58
+ attribute :email, :string, transform: {
59
+ export: lambda(&:downcase),
60
+ import: lambda(&:downcase),
61
+ }
62
+ attribute :tags, :string, collection: true, transform: {
63
+ export: ->(value) { value.map(&:upcase) },
64
+ import: ->(value) { value.map { |v| "#{v}-1" } },
65
+ }
66
+
67
+ json do
68
+ map "fullName", to: :name, transform: {
69
+ export: ->(value) { "Prof. #{value}" },
70
+ import: ->(value) { value.gsub("Prof. ", "") },
62
71
  }
63
- attribute :tags, :string, collection: true, transform: {
64
- export: ->(value) { value.map(&:upcase) },
65
- import: ->(value) { value.map { |v| "#{v}-1" } },
72
+ map "contactEmail", to: :email, transform: {
73
+ export: ->(value) { "contact+#{value}" },
74
+ import: ->(value) { value.gsub("contact+", "") },
66
75
  }
76
+ map "skills", to: :tags
77
+ end
67
78
 
68
- json do
69
- map "fullName", to: :name, transform: {
70
- export: ->(value) { "Prof. #{value}" },
71
- import: ->(value) { value.gsub("Prof. ", "") },
72
- }
73
- map "contactEmail", to: :email, transform: {
74
- export: ->(value) { "contact+#{value}" },
75
- import: ->(value) { value.gsub("contact+", "") },
76
- }
77
- map "skills", to: :tags
78
- end
79
-
80
- xml do
81
- root "person"
82
- map_element "full-name", to: :name, transform: {
83
- export: ->(value) { "Prof. #{value}" },
84
- import: ->(value) { value.gsub("Prof. ", "") },
85
- }
86
- map_element "contact-email", to: :email, transform: {
87
- export: ->(value) { "contact+#{value}" },
88
- import: ->(value) { value.gsub("contact+", "") },
89
- }
90
- map_element "skills", to: :tags
91
- end
79
+ xml do
80
+ root "person"
81
+ map_element "full-name", to: :name, transform: {
82
+ export: ->(value) { "Prof. #{value}" },
83
+ import: ->(value) { value.gsub("Prof. ", "") },
84
+ }
85
+ map_element "contact-email", to: :email, transform: {
86
+ export: ->(value) { "contact+#{value}" },
87
+ import: ->(value) { value.gsub("contact+", "") },
88
+ }
89
+ map_element "skills", to: :tags
92
90
  end
93
91
  end
92
+ end
94
93
 
94
+ RSpec.describe "Value Transformations" do
95
95
  describe "Attribute-only transformations" do
96
96
  let(:attribute_person) do
97
97
  TransformationSpec::AttributeTransformPerson.new(
@@ -71,14 +71,14 @@ RSpec.describe Lutaml::Model::Type::Boolean do
71
71
  end
72
72
 
73
73
  context "with key-value serialization" do
74
- let(:yaml) do
74
+ let(:attrs) do
75
75
  {
76
76
  "name" => "John Smith",
77
77
  "full_time" => true,
78
78
  "on_leave" => false,
79
79
  "remote" => nil,
80
80
  "active" => nil,
81
- }.to_yaml
81
+ }
82
82
  end
83
83
 
84
84
  let(:expected_yaml) do
@@ -91,7 +91,7 @@ RSpec.describe Lutaml::Model::Type::Boolean do
91
91
  end
92
92
 
93
93
  it "deserializes boolean values correctly" do
94
- employee = BooleanSpec::Employee.from_yaml(yaml)
94
+ employee = BooleanSpec::Employee.from_yaml(attrs.to_yaml)
95
95
 
96
96
  expect(employee.name).to eq("John Smith")
97
97
  expect(employee.full_time).to be true
@@ -101,13 +101,7 @@ RSpec.describe Lutaml::Model::Type::Boolean do
101
101
  end
102
102
 
103
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
- )
104
+ employee = BooleanSpec::Employee.new(attrs)
111
105
 
112
106
  yaml_output = employee.to_yaml
113
107
  expect(yaml_output).to eq(expected_yaml)
@@ -112,10 +112,10 @@ RSpec.describe Lutaml::Model::Type do
112
112
  hide_const("BigDecimal")
113
113
  end
114
114
 
115
+ let(:serialized) { Lutaml::Model::Type::Decimal.serialize("123.45") }
116
+
115
117
  it "raises TypeNotEnabledError" do
116
- expect do
117
- Lutaml::Model::Type::Decimal.serialize("123.45")
118
- end.to raise_error(
118
+ expect { serialized }.to raise_error(
119
119
  Lutaml::Model::TypeNotEnabledError,
120
120
  /Decimal/,
121
121
  )