media_types-serialization 2.0.4 → 2.1.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/.github/workflows/ci.yml +32 -32
- data/.github/workflows/publish-bookworm.yml +34 -34
- data/.github/workflows/publish-sid.yml +34 -34
- data/.gitignore +22 -22
- data/.idea/.rakeTasks +7 -7
- data/.idea/dictionaries/Derk_Jan.xml +6 -6
- data/.idea/encodings.xml +3 -3
- data/.idea/inspectionProfiles/Project_Default.xml +5 -5
- data/.idea/media_types-serialization.iml +76 -76
- data/.idea/misc.xml +6 -6
- data/.idea/modules.xml +7 -7
- data/.idea/runConfigurations/test.xml +19 -19
- data/.idea/vcs.xml +5 -5
- data/CHANGELOG.md +207 -200
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +4 -4
- data/Gemfile.lock +176 -169
- data/LICENSE.txt +21 -21
- data/README.md +1058 -1048
- data/Rakefile +10 -10
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/lib/media_types/problem.rb +67 -67
- data/lib/media_types/serialization/base.rb +269 -269
- data/lib/media_types/serialization/error.rb +193 -193
- data/lib/media_types/serialization/fake_validator.rb +53 -53
- data/lib/media_types/serialization/serialization_dsl.rb +139 -135
- data/lib/media_types/serialization/serialization_registration.rb +245 -245
- data/lib/media_types/serialization/serializers/api_viewer.rb +383 -383
- data/lib/media_types/serialization/serializers/common_css.rb +212 -212
- data/lib/media_types/serialization/serializers/endpoint_description_serializer.rb +80 -80
- data/lib/media_types/serialization/serializers/fallback_not_acceptable_serializer.rb +85 -85
- data/lib/media_types/serialization/serializers/fallback_unsupported_media_type_serializer.rb +58 -58
- data/lib/media_types/serialization/serializers/input_validation_error_serializer.rb +95 -93
- data/lib/media_types/serialization/serializers/problem_serializer.rb +111 -111
- data/lib/media_types/serialization/utils/accept_header.rb +77 -77
- data/lib/media_types/serialization/utils/accept_language_header.rb +82 -82
- data/lib/media_types/serialization/version.rb +7 -7
- data/lib/media_types/serialization.rb +689 -689
- data/media_types-serialization.gemspec +48 -48
- metadata +3 -3
@@ -1,245 +1,245 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'media_types/serialization/error'
|
4
|
-
require 'media_types'
|
5
|
-
|
6
|
-
module MediaTypes
|
7
|
-
module Serialization
|
8
|
-
# A collection that manages media type identifier registrations
|
9
|
-
class SerializationRegistration
|
10
|
-
def initialize(direction)
|
11
|
-
self.registrations = {}
|
12
|
-
self.inout = direction
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_accessor :registrations, :inout
|
16
|
-
|
17
|
-
def has?(identifier)
|
18
|
-
registrations.key? identifier
|
19
|
-
end
|
20
|
-
|
21
|
-
def register_block(serializer, validator, version, block, raw, wildcards: true)
|
22
|
-
identifier = validator.identifier
|
23
|
-
|
24
|
-
raise DuplicateDefinitionError.new(identifier, inout) if registrations.key? identifier
|
25
|
-
|
26
|
-
raise ValidatorNotDefinedError.new(identifier, inout) unless raw || validator.validatable?
|
27
|
-
|
28
|
-
registration = SerializationBlockRegistration.new serializer, inout, validator, identifier, version, block, raw
|
29
|
-
registrations[identifier] = registration
|
30
|
-
|
31
|
-
register_wildcards(identifier, registration) if wildcards && inout == :output
|
32
|
-
end
|
33
|
-
|
34
|
-
def register_alias(serializer, alias_identifier, target_identifier, optional, hide_variant, wildcards: true)
|
35
|
-
raise DuplicateDefinitionError.new(alias_identifier, inout) if registrations.key? alias_identifier
|
36
|
-
|
37
|
-
unless registrations.key? target_identifier
|
38
|
-
potential_match = registrations.keys.find do |k|
|
39
|
-
k.start_with? target_identifier
|
40
|
-
end
|
41
|
-
raise VersionedAliasDefinitionError.new(target_identifier, inout, potential_match) unless potential_match.nil?
|
42
|
-
raise UnbackedAliasDefinitionError.new(target_identifier, inout)
|
43
|
-
end
|
44
|
-
|
45
|
-
target = registrations[target_identifier]
|
46
|
-
|
47
|
-
result_content_type = alias_identifier
|
48
|
-
result_content_type += "; variant=#{target_identifier}" unless hide_variant
|
49
|
-
|
50
|
-
registration = SerializationAliasRegistration.new serializer, inout, target.validator, result_content_type, target, optional, hide_variant
|
51
|
-
registrations[alias_identifier] = registration
|
52
|
-
|
53
|
-
register_wildcards(alias_identifier, registration) if wildcards && inout == :output
|
54
|
-
end
|
55
|
-
|
56
|
-
def merge(other)
|
57
|
-
raise Error, 'Trying to merge two SerializationRegistration objects with a different direction.' unless inout == other.inout
|
58
|
-
|
59
|
-
result = SerializationRegistration.new(inout)
|
60
|
-
|
61
|
-
prev_keys = Set.new(registrations.keys)
|
62
|
-
new_keys = Set.new(other.registrations.keys)
|
63
|
-
overlap = prev_keys & new_keys
|
64
|
-
|
65
|
-
result.registrations = registrations.merge(other.registrations)
|
66
|
-
overlap.each do |identifier|
|
67
|
-
prev_item = registrations[identifier]
|
68
|
-
new_item = other.registrations[identifier]
|
69
|
-
merge_result = prev_item.merge(new_item)
|
70
|
-
|
71
|
-
raise DuplicateUsageError.new(identifier, inout, prev_item.serializer, new_item.serializer) if merge_result.nil?
|
72
|
-
|
73
|
-
result.registrations[identifier] = merge_result
|
74
|
-
end
|
75
|
-
|
76
|
-
result
|
77
|
-
end
|
78
|
-
|
79
|
-
def decode(victim, media_type, context)
|
80
|
-
registration = registrations[media_type]
|
81
|
-
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
82
|
-
|
83
|
-
registration.decode(victim, context)
|
84
|
-
end
|
85
|
-
|
86
|
-
def call(victim, media_type, context, dsl: nil, raw: nil)
|
87
|
-
registration = registrations[media_type]
|
88
|
-
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
89
|
-
|
90
|
-
registration.call(victim, context, dsl: dsl, raw: raw)
|
91
|
-
end
|
92
|
-
|
93
|
-
def identifier_for(input_identifier)
|
94
|
-
registration = registrations[input_identifier]
|
95
|
-
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
96
|
-
|
97
|
-
registration.display_identifier
|
98
|
-
end
|
99
|
-
|
100
|
-
def filter(views:)
|
101
|
-
result = SerializationRegistration.new inout
|
102
|
-
|
103
|
-
registrations.each do |identifier, registration|
|
104
|
-
if views.include? registration.validator.view
|
105
|
-
result.registrations[identifier] = registration
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
result
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def register_wildcards(identifier, registration)
|
115
|
-
new_alias = SerializationAliasRegistration.new registration.serializer, registration.inout, registration.validator, identifier, registration, true, true
|
116
|
-
|
117
|
-
registrations['*/*'] = new_alias unless has? '*/*'
|
118
|
-
|
119
|
-
partial = "#{identifier.split('/')[0]}/*"
|
120
|
-
registrations[partial] = new_alias unless has? partial
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# A registration in a SerializationRegistration collection
|
125
|
-
class SerializationBaseRegistration
|
126
|
-
def initialize(serializer, inout, validator, display_identifier)
|
127
|
-
self.serializer = serializer
|
128
|
-
self.inout = inout
|
129
|
-
self.validator = validator
|
130
|
-
self.display_identifier = display_identifier
|
131
|
-
end
|
132
|
-
|
133
|
-
def merge(_other)
|
134
|
-
nil
|
135
|
-
end
|
136
|
-
|
137
|
-
def decode(_victim, _context)
|
138
|
-
raise 'Assertion failed, decode function called on base registration.'
|
139
|
-
end
|
140
|
-
def call(_victim, _context, dsl: nil, raw: nil)
|
141
|
-
raise 'Assertion failed, call function called on base registration.'
|
142
|
-
end
|
143
|
-
|
144
|
-
attr_accessor :serializer, :inout, :validator, :display_identifier
|
145
|
-
end
|
146
|
-
|
147
|
-
# A registration with a block to be executed when called.
|
148
|
-
class SerializationBlockRegistration < SerializationBaseRegistration
|
149
|
-
def initialize(serializer, inout, validator, display_identifier, version, block, raw)
|
150
|
-
self.version = version
|
151
|
-
self.block = block
|
152
|
-
self.raw = raw
|
153
|
-
super(serializer, inout, validator, display_identifier)
|
154
|
-
end
|
155
|
-
|
156
|
-
def merge(other)
|
157
|
-
return nil unless other.is_a?(SerializationAliasRegistration)
|
158
|
-
|
159
|
-
return self if other.optional
|
160
|
-
|
161
|
-
nil
|
162
|
-
end
|
163
|
-
|
164
|
-
def decode(victim, _context)
|
165
|
-
raise CannotDecodeOutputError if inout != :input
|
166
|
-
|
167
|
-
unless raw
|
168
|
-
if defined? Oj::ParseError
|
169
|
-
begin
|
170
|
-
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
171
|
-
validator.validate!(victim, loose: true)
|
172
|
-
rescue MediaTypes::Scheme::ValidationError, Oj::ParseError, JSON::ParserError, EncodingError => inner
|
173
|
-
raise InputValidationFailedError, inner
|
174
|
-
end
|
175
|
-
else
|
176
|
-
begin
|
177
|
-
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
178
|
-
validator.validate!(victim, loose: true)
|
179
|
-
rescue MediaTypes::Scheme::ValidationError, JSON::ParserError, EncodingError => inner
|
180
|
-
raise InputValidationFailedError, inner
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
victim
|
186
|
-
end
|
187
|
-
|
188
|
-
def call(victim, context, dsl: nil, raw: nil)
|
189
|
-
raw = self.raw if raw.nil?
|
190
|
-
|
191
|
-
result = nil
|
192
|
-
if dsl.nil?
|
193
|
-
result = victim
|
194
|
-
result = block.call(victim, version, context) if block
|
195
|
-
else
|
196
|
-
result = dsl.instance_exec victim, version, context, &block
|
197
|
-
end
|
198
|
-
|
199
|
-
if !raw && inout == :output
|
200
|
-
begin
|
201
|
-
validator.validate!(result)
|
202
|
-
rescue MediaTypes::Scheme::ValidationError => inner
|
203
|
-
raise OutputValidationFailedError, inner
|
204
|
-
end
|
205
|
-
result = MediaTypes::Serialization.json_encoder.call(result)
|
206
|
-
end
|
207
|
-
|
208
|
-
result
|
209
|
-
end
|
210
|
-
|
211
|
-
attr_accessor :version, :block, :raw
|
212
|
-
end
|
213
|
-
|
214
|
-
# A registration that calls another registration when called.
|
215
|
-
class SerializationAliasRegistration < SerializationBaseRegistration
|
216
|
-
def initialize(serializer, inout, validator, display_identifier, target, optional, hide_variant)
|
217
|
-
self.target = target
|
218
|
-
self.optional = optional
|
219
|
-
self.hide_variant = hide_variant
|
220
|
-
super(serializer, inout, validator, display_identifier)
|
221
|
-
end
|
222
|
-
|
223
|
-
def merge(other)
|
224
|
-
if optional
|
225
|
-
return other unless other.is_a?(SerializationAliasRegistration)
|
226
|
-
else
|
227
|
-
return nil if other.is_a?(SerializationAliasRegistration) && !other.optional # two non-optional can't merge
|
228
|
-
return self
|
229
|
-
end
|
230
|
-
|
231
|
-
other # if both optional, or other is !optional, newer one wins.
|
232
|
-
end
|
233
|
-
|
234
|
-
def decode(victim, context)
|
235
|
-
target.decode(victim, context)
|
236
|
-
end
|
237
|
-
|
238
|
-
def call(victim, context, dsl: nil, raw: nil)
|
239
|
-
target.call(victim, context, dsl: dsl, raw: raw)
|
240
|
-
end
|
241
|
-
|
242
|
-
attr_accessor :target, :optional, :hide_variant
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/serialization/error'
|
4
|
+
require 'media_types'
|
5
|
+
|
6
|
+
module MediaTypes
|
7
|
+
module Serialization
|
8
|
+
# A collection that manages media type identifier registrations
|
9
|
+
class SerializationRegistration
|
10
|
+
def initialize(direction)
|
11
|
+
self.registrations = {}
|
12
|
+
self.inout = direction
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :registrations, :inout
|
16
|
+
|
17
|
+
def has?(identifier)
|
18
|
+
registrations.key? identifier
|
19
|
+
end
|
20
|
+
|
21
|
+
def register_block(serializer, validator, version, block, raw, wildcards: true)
|
22
|
+
identifier = validator.identifier
|
23
|
+
|
24
|
+
raise DuplicateDefinitionError.new(identifier, inout) if registrations.key? identifier
|
25
|
+
|
26
|
+
raise ValidatorNotDefinedError.new(identifier, inout) unless raw || validator.validatable?
|
27
|
+
|
28
|
+
registration = SerializationBlockRegistration.new serializer, inout, validator, identifier, version, block, raw
|
29
|
+
registrations[identifier] = registration
|
30
|
+
|
31
|
+
register_wildcards(identifier, registration) if wildcards && inout == :output
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_alias(serializer, alias_identifier, target_identifier, optional, hide_variant, wildcards: true)
|
35
|
+
raise DuplicateDefinitionError.new(alias_identifier, inout) if registrations.key? alias_identifier
|
36
|
+
|
37
|
+
unless registrations.key? target_identifier
|
38
|
+
potential_match = registrations.keys.find do |k|
|
39
|
+
k.start_with? target_identifier
|
40
|
+
end
|
41
|
+
raise VersionedAliasDefinitionError.new(target_identifier, inout, potential_match) unless potential_match.nil?
|
42
|
+
raise UnbackedAliasDefinitionError.new(target_identifier, inout)
|
43
|
+
end
|
44
|
+
|
45
|
+
target = registrations[target_identifier]
|
46
|
+
|
47
|
+
result_content_type = alias_identifier
|
48
|
+
result_content_type += "; variant=#{target_identifier}" unless hide_variant
|
49
|
+
|
50
|
+
registration = SerializationAliasRegistration.new serializer, inout, target.validator, result_content_type, target, optional, hide_variant
|
51
|
+
registrations[alias_identifier] = registration
|
52
|
+
|
53
|
+
register_wildcards(alias_identifier, registration) if wildcards && inout == :output
|
54
|
+
end
|
55
|
+
|
56
|
+
def merge(other)
|
57
|
+
raise Error, 'Trying to merge two SerializationRegistration objects with a different direction.' unless inout == other.inout
|
58
|
+
|
59
|
+
result = SerializationRegistration.new(inout)
|
60
|
+
|
61
|
+
prev_keys = Set.new(registrations.keys)
|
62
|
+
new_keys = Set.new(other.registrations.keys)
|
63
|
+
overlap = prev_keys & new_keys
|
64
|
+
|
65
|
+
result.registrations = registrations.merge(other.registrations)
|
66
|
+
overlap.each do |identifier|
|
67
|
+
prev_item = registrations[identifier]
|
68
|
+
new_item = other.registrations[identifier]
|
69
|
+
merge_result = prev_item.merge(new_item)
|
70
|
+
|
71
|
+
raise DuplicateUsageError.new(identifier, inout, prev_item.serializer, new_item.serializer) if merge_result.nil?
|
72
|
+
|
73
|
+
result.registrations[identifier] = merge_result
|
74
|
+
end
|
75
|
+
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
def decode(victim, media_type, context)
|
80
|
+
registration = registrations[media_type]
|
81
|
+
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
82
|
+
|
83
|
+
registration.decode(victim, context)
|
84
|
+
end
|
85
|
+
|
86
|
+
def call(victim, media_type, context, dsl: nil, raw: nil)
|
87
|
+
registration = registrations[media_type]
|
88
|
+
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
89
|
+
|
90
|
+
registration.call(victim, context, dsl: dsl, raw: raw)
|
91
|
+
end
|
92
|
+
|
93
|
+
def identifier_for(input_identifier)
|
94
|
+
registration = registrations[input_identifier]
|
95
|
+
raise UnregisteredMediaTypeUsageError.new(media_type, registrations.keys) if registration.nil?
|
96
|
+
|
97
|
+
registration.display_identifier
|
98
|
+
end
|
99
|
+
|
100
|
+
def filter(views:)
|
101
|
+
result = SerializationRegistration.new inout
|
102
|
+
|
103
|
+
registrations.each do |identifier, registration|
|
104
|
+
if views.include? registration.validator.view
|
105
|
+
result.registrations[identifier] = registration
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def register_wildcards(identifier, registration)
|
115
|
+
new_alias = SerializationAliasRegistration.new registration.serializer, registration.inout, registration.validator, identifier, registration, true, true
|
116
|
+
|
117
|
+
registrations['*/*'] = new_alias unless has? '*/*'
|
118
|
+
|
119
|
+
partial = "#{identifier.split('/')[0]}/*"
|
120
|
+
registrations[partial] = new_alias unless has? partial
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# A registration in a SerializationRegistration collection
|
125
|
+
class SerializationBaseRegistration
|
126
|
+
def initialize(serializer, inout, validator, display_identifier)
|
127
|
+
self.serializer = serializer
|
128
|
+
self.inout = inout
|
129
|
+
self.validator = validator
|
130
|
+
self.display_identifier = display_identifier
|
131
|
+
end
|
132
|
+
|
133
|
+
def merge(_other)
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def decode(_victim, _context)
|
138
|
+
raise 'Assertion failed, decode function called on base registration.'
|
139
|
+
end
|
140
|
+
def call(_victim, _context, dsl: nil, raw: nil)
|
141
|
+
raise 'Assertion failed, call function called on base registration.'
|
142
|
+
end
|
143
|
+
|
144
|
+
attr_accessor :serializer, :inout, :validator, :display_identifier
|
145
|
+
end
|
146
|
+
|
147
|
+
# A registration with a block to be executed when called.
|
148
|
+
class SerializationBlockRegistration < SerializationBaseRegistration
|
149
|
+
def initialize(serializer, inout, validator, display_identifier, version, block, raw)
|
150
|
+
self.version = version
|
151
|
+
self.block = block
|
152
|
+
self.raw = raw
|
153
|
+
super(serializer, inout, validator, display_identifier)
|
154
|
+
end
|
155
|
+
|
156
|
+
def merge(other)
|
157
|
+
return nil unless other.is_a?(SerializationAliasRegistration)
|
158
|
+
|
159
|
+
return self if other.optional
|
160
|
+
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def decode(victim, _context)
|
165
|
+
raise CannotDecodeOutputError if inout != :input
|
166
|
+
|
167
|
+
unless raw
|
168
|
+
if defined? Oj::ParseError
|
169
|
+
begin
|
170
|
+
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
171
|
+
validator.validate!(victim, loose: true)
|
172
|
+
rescue MediaTypes::Scheme::ValidationError, Oj::ParseError, JSON::ParserError, EncodingError => inner
|
173
|
+
raise InputValidationFailedError, inner
|
174
|
+
end
|
175
|
+
else
|
176
|
+
begin
|
177
|
+
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
178
|
+
validator.validate!(victim, loose: true)
|
179
|
+
rescue MediaTypes::Scheme::ValidationError, JSON::ParserError, EncodingError => inner
|
180
|
+
raise InputValidationFailedError, inner
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
victim
|
186
|
+
end
|
187
|
+
|
188
|
+
def call(victim, context, dsl: nil, raw: nil)
|
189
|
+
raw = self.raw if raw.nil?
|
190
|
+
|
191
|
+
result = nil
|
192
|
+
if dsl.nil?
|
193
|
+
result = victim
|
194
|
+
result = block.call(victim, version, context) if block
|
195
|
+
else
|
196
|
+
result = dsl.instance_exec victim, version, context, &block
|
197
|
+
end
|
198
|
+
|
199
|
+
if !raw && inout == :output
|
200
|
+
begin
|
201
|
+
validator.validate!(result)
|
202
|
+
rescue MediaTypes::Scheme::ValidationError => inner
|
203
|
+
raise OutputValidationFailedError, inner
|
204
|
+
end
|
205
|
+
result = MediaTypes::Serialization.json_encoder.call(result)
|
206
|
+
end
|
207
|
+
|
208
|
+
result
|
209
|
+
end
|
210
|
+
|
211
|
+
attr_accessor :version, :block, :raw
|
212
|
+
end
|
213
|
+
|
214
|
+
# A registration that calls another registration when called.
|
215
|
+
class SerializationAliasRegistration < SerializationBaseRegistration
|
216
|
+
def initialize(serializer, inout, validator, display_identifier, target, optional, hide_variant)
|
217
|
+
self.target = target
|
218
|
+
self.optional = optional
|
219
|
+
self.hide_variant = hide_variant
|
220
|
+
super(serializer, inout, validator, display_identifier)
|
221
|
+
end
|
222
|
+
|
223
|
+
def merge(other)
|
224
|
+
if optional
|
225
|
+
return other unless other.is_a?(SerializationAliasRegistration)
|
226
|
+
else
|
227
|
+
return nil if other.is_a?(SerializationAliasRegistration) && !other.optional # two non-optional can't merge
|
228
|
+
return self
|
229
|
+
end
|
230
|
+
|
231
|
+
other # if both optional, or other is !optional, newer one wins.
|
232
|
+
end
|
233
|
+
|
234
|
+
def decode(victim, context)
|
235
|
+
target.decode(victim, context)
|
236
|
+
end
|
237
|
+
|
238
|
+
def call(victim, context, dsl: nil, raw: nil)
|
239
|
+
target.call(victim, context, dsl: dsl, raw: raw)
|
240
|
+
end
|
241
|
+
|
242
|
+
attr_accessor :target, :optional, :hide_variant
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|