media_types-serialization 1.3.9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +32 -32
  3. data/.github/workflows/publish-bookworm.yml +33 -0
  4. data/.github/workflows/publish-sid.yml +33 -0
  5. data/.gitignore +22 -12
  6. data/.idea/.rakeTasks +7 -7
  7. data/.idea/dictionaries/Derk_Jan.xml +6 -6
  8. data/.idea/encodings.xml +3 -3
  9. data/.idea/inspectionProfiles/Project_Default.xml +5 -5
  10. data/.idea/media_types-serialization.iml +76 -76
  11. data/.idea/misc.xml +6 -6
  12. data/.idea/modules.xml +7 -7
  13. data/.idea/runConfigurations/test.xml +19 -19
  14. data/.idea/vcs.xml +5 -5
  15. data/CHANGELOG.md +190 -178
  16. data/CODE_OF_CONDUCT.md +74 -74
  17. data/Gemfile +4 -4
  18. data/LICENSE.txt +21 -21
  19. data/README.md +1048 -1035
  20. data/Rakefile +10 -10
  21. data/bin/console +14 -14
  22. data/bin/setup +8 -8
  23. data/lib/media_types/problem.rb +67 -67
  24. data/lib/media_types/serialization/base.rb +269 -216
  25. data/lib/media_types/serialization/error.rb +193 -193
  26. data/lib/media_types/serialization/fake_validator.rb +53 -53
  27. data/lib/media_types/serialization/serialization_dsl.rb +135 -117
  28. data/lib/media_types/serialization/serialization_registration.rb +245 -245
  29. data/lib/media_types/serialization/serializers/api_viewer.rb +383 -136
  30. data/lib/media_types/serialization/serializers/common_css.rb +212 -168
  31. data/lib/media_types/serialization/serializers/endpoint_description_serializer.rb +80 -80
  32. data/lib/media_types/serialization/serializers/fallback_not_acceptable_serializer.rb +85 -85
  33. data/lib/media_types/serialization/serializers/fallback_unsupported_media_type_serializer.rb +58 -58
  34. data/lib/media_types/serialization/serializers/input_validation_error_serializer.rb +93 -93
  35. data/lib/media_types/serialization/serializers/problem_serializer.rb +111 -104
  36. data/lib/media_types/serialization/utils/accept_header.rb +77 -77
  37. data/lib/media_types/serialization/utils/accept_language_header.rb +82 -82
  38. data/lib/media_types/serialization/version.rb +7 -7
  39. data/lib/media_types/serialization.rb +682 -671
  40. data/media_types-serialization.gemspec +48 -48
  41. metadata +17 -16
  42. data/Gemfile.lock +0 -137
@@ -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)
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)
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