media_types-serialization 1.0.1 → 1.2.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 +7 -3
- data/.prettierrc +1 -0
- data/CHANGELOG.md +31 -7
- data/CODE_OF_CONDUCT.md +11 -11
- data/Gemfile.lock +64 -70
- data/README.md +98 -53
- data/lib/media_types/serialization.rb +84 -11
- data/lib/media_types/serialization/base.rb +8 -4
- data/lib/media_types/serialization/error.rb +11 -3
- data/lib/media_types/serialization/fake_validator.rb +1 -1
- data/lib/media_types/serialization/serialization_registration.rb +19 -9
- data/lib/media_types/serialization/serializers/problem_serializer.rb +23 -10
- data/lib/media_types/serialization/utils/accept_header.rb +77 -0
- data/lib/media_types/serialization/utils/accept_language_header.rb +82 -0
- data/lib/media_types/serialization/utils/header_list.rb +89 -0
- data/lib/media_types/serialization/version.rb +1 -1
- data/media_types-serialization.gemspec +3 -5
- metadata +14 -42
@@ -15,8 +15,7 @@ require 'active_support/concern'
|
|
15
15
|
require 'active_support/core_ext/module/attribute_accessors'
|
16
16
|
require 'active_support/core_ext/object/blank'
|
17
17
|
|
18
|
-
require '
|
19
|
-
|
18
|
+
require 'media_types/serialization/utils/accept_header'
|
20
19
|
require 'media_types/serialization/base'
|
21
20
|
require 'media_types/serialization/error'
|
22
21
|
require 'media_types/serialization/serialization_dsl'
|
@@ -44,7 +43,8 @@ end
|
|
44
43
|
module MediaTypes
|
45
44
|
module Serialization
|
46
45
|
|
47
|
-
HEADER_ACCEPT = 'HTTP_ACCEPT'
|
46
|
+
HEADER_ACCEPT = 'HTTP_ACCEPT'.freeze
|
47
|
+
HEADER_ACCEPT_LANGUAGE = 'HTTP_ACCEPT_LANGUAGE'.freeze
|
48
48
|
|
49
49
|
mattr_accessor :json_encoder, :json_decoder
|
50
50
|
if defined?(::Oj)
|
@@ -67,7 +67,21 @@ module MediaTypes
|
|
67
67
|
quirks_mode: false
|
68
68
|
)
|
69
69
|
}
|
70
|
-
self.json_decoder =
|
70
|
+
self.json_decoder = ->(obj) {
|
71
|
+
Oj.load(obj,
|
72
|
+
mode: :compat,
|
73
|
+
ascii_only: false,
|
74
|
+
allow_nan: false,
|
75
|
+
symbol_keys: true,
|
76
|
+
allow_nil: false,
|
77
|
+
allow_invalid_unicode: false,
|
78
|
+
array_class: ::Array,
|
79
|
+
create_additions: false,
|
80
|
+
hash_class: ::Hash,
|
81
|
+
nilnil: false,
|
82
|
+
quirks_mode: false
|
83
|
+
)
|
84
|
+
}
|
71
85
|
else
|
72
86
|
require 'json'
|
73
87
|
self.json_encoder = JSON.method(:pretty_generate)
|
@@ -169,7 +183,66 @@ module MediaTypes
|
|
169
183
|
@serialization_output_registrations = @serialization_output_registrations.merge(mergeable_outputs)
|
170
184
|
end
|
171
185
|
end
|
172
|
-
|
186
|
+
|
187
|
+
def allow_output_html(as: nil, view: nil, layout: nil, **filter_opts)
|
188
|
+
before_action(**filter_opts) do
|
189
|
+
raise SerializersAlreadyFrozenError if defined? @serialization_frozen
|
190
|
+
|
191
|
+
@serialization_output_registrations ||= SerializationRegistration.new(:output)
|
192
|
+
|
193
|
+
html_registration = SerializationRegistration.new(:output)
|
194
|
+
output_identifier = 'text/html'
|
195
|
+
output_identifier += "; variant=#{as}" unless as.nil?
|
196
|
+
|
197
|
+
validator = FakeValidator.new(as.nil? ? 'text/html' : as)
|
198
|
+
|
199
|
+
block = lambda { |_, _, controller|
|
200
|
+
if layout.nil?
|
201
|
+
if view.nil?
|
202
|
+
controller.render_to_string
|
203
|
+
else
|
204
|
+
controller.render_to_string(template: view)
|
205
|
+
end
|
206
|
+
else
|
207
|
+
if view.nil?
|
208
|
+
controller.render_to_string(layout: layout)
|
209
|
+
else
|
210
|
+
controller.render_to_string(template: view, layout: layout)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
}
|
214
|
+
|
215
|
+
html_registration.register_block(nil, validator, nil, block, true, wildcards: true)
|
216
|
+
html_registration.registrations[validator.identifier].display_identifier = output_identifier
|
217
|
+
html_registration.registrations["#{validator.identifier.split('/')[0]}/*"].display_identifier = output_identifier
|
218
|
+
html_registration.registrations['*/*'].display_identifier = output_identifier
|
219
|
+
|
220
|
+
@serialization_output_registrations = @serialization_output_registrations.merge(html_registration)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def allow_output_docs(description, **filter_opts)
|
225
|
+
before_action(**filter_opts) do
|
226
|
+
raise SerializersAlreadyFrozenError if defined? @serialization_frozen
|
227
|
+
|
228
|
+
@serialization_output_registrations ||= SerializationRegistration.new(:output)
|
229
|
+
|
230
|
+
docs_registration = SerializationRegistration.new(:output)
|
231
|
+
validator = FakeValidator.new('text/vnd.delftsolutions.docs')
|
232
|
+
|
233
|
+
block = lambda { |_, _, _|
|
234
|
+
description
|
235
|
+
}
|
236
|
+
|
237
|
+
docs_registration.register_block(nil, validator, nil, block, true, wildcards: true)
|
238
|
+
docs_registration.registrations['text/vnd.delftsolutions.docs'].display_identifier = 'text/plain; charset=utf-8'
|
239
|
+
docs_registration.registrations['text/*'].display_identifier = 'text/plain; charset=utf-8'
|
240
|
+
docs_registration.registrations['*/*'].display_identifier = 'text/plain; charset=utf-8'
|
241
|
+
|
242
|
+
@serialization_output_registrations = @serialization_output_registrations.merge(docs_registration)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
173
246
|
def allow_api_viewer(serializer: MediaTypes::Serialization::Serializers::ApiViewer, **filter_opts)
|
174
247
|
before_action do
|
175
248
|
@serialization_api_viewer_enabled ||= {}
|
@@ -202,7 +275,7 @@ module MediaTypes
|
|
202
275
|
raise ArrayInViewParameterError, :allow_input_serializer if view.is_a? Array
|
203
276
|
views = [view] if views.nil?
|
204
277
|
raise ViewsNotAnArrayError unless views.is_a? Array
|
205
|
-
|
278
|
+
|
206
279
|
before_action do
|
207
280
|
@serialization_available_serializers ||= {}
|
208
281
|
@serialization_available_serializers[:input] ||= {}
|
@@ -245,8 +318,8 @@ module MediaTypes
|
|
245
318
|
##
|
246
319
|
# Freezes additions to the serializes and notifies the controller what it will be able to respond to.
|
247
320
|
#
|
248
|
-
def freeze_io!
|
249
|
-
before_action :serializer_freeze_io_internal
|
321
|
+
def freeze_io!(**filter_opts)
|
322
|
+
before_action :serializer_freeze_io_internal, **filter_opts
|
250
323
|
|
251
324
|
output_error MediaTypes::Serialization::NoInputReceivedError do |p, error|
|
252
325
|
p.title 'Providing input is mandatory. Please set a Content-Type', lang: 'en'
|
@@ -352,7 +425,7 @@ module MediaTypes
|
|
352
425
|
return nil if identifier.nil?
|
353
426
|
|
354
427
|
registration = registration.registrations[identifier]
|
355
|
-
|
428
|
+
|
356
429
|
raise 'Assertion failed, inconsistent answer from resolve_media_type' if registration.nil?
|
357
430
|
registration.serializer
|
358
431
|
end
|
@@ -372,7 +445,7 @@ module MediaTypes
|
|
372
445
|
#
|
373
446
|
#
|
374
447
|
|
375
|
-
accept_header =
|
448
|
+
accept_header = Utils::AcceptHeader.new(request.get_header(HEADER_ACCEPT)) || ''
|
376
449
|
accept_header.each do |mime_type|
|
377
450
|
stripped = mime_type.to_s.split(';')[0]
|
378
451
|
next unless registration.has? stripped
|
@@ -389,7 +462,7 @@ module MediaTypes
|
|
389
462
|
identifier = serializer.validator.identifier
|
390
463
|
obj = { request: request, registrations: registrations }
|
391
464
|
new_registrations = serializer.outputs_for(views: [nil])
|
392
|
-
|
465
|
+
|
393
466
|
serialization_render_resolved(obj: obj, serializer: serializer, identifier: identifier, registrations: new_registrations, options: {})
|
394
467
|
response.status = :not_acceptable
|
395
468
|
end
|
@@ -30,6 +30,10 @@ module MediaTypes
|
|
30
30
|
self.serializer_disable_wildcards = true
|
31
31
|
end
|
32
32
|
|
33
|
+
def enable_wildcards
|
34
|
+
self.serializer_disable_wildcards = false
|
35
|
+
end
|
36
|
+
|
33
37
|
def output(view: nil, version: nil, versions: nil, &block)
|
34
38
|
versions = [version] if versions.nil?
|
35
39
|
raise VersionsNotAnArrayError unless versions.is_a? Array
|
@@ -57,18 +61,18 @@ module MediaTypes
|
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
60
|
-
def output_alias(media_type_identifier, view: nil)
|
64
|
+
def output_alias(media_type_identifier, view: nil, hide_variant: false)
|
61
65
|
validator = serializer_validator.view(view)
|
62
66
|
victim_identifier = validator.identifier
|
63
67
|
|
64
|
-
serializer_output_registration.register_alias(self, media_type_identifier, victim_identifier, false, wildcards: !self.serializer_disable_wildcards)
|
68
|
+
serializer_output_registration.register_alias(self, media_type_identifier, victim_identifier, false, hide_variant, wildcards: !self.serializer_disable_wildcards)
|
65
69
|
end
|
66
70
|
|
67
|
-
def output_alias_optional(media_type_identifier, view: nil)
|
71
|
+
def output_alias_optional(media_type_identifier, view: nil, hide_variant: false)
|
68
72
|
validator = serializer_validator.view(view)
|
69
73
|
victim_identifier = validator.identifier
|
70
74
|
|
71
|
-
serializer_output_registration.register_alias(self, media_type_identifier, victim_identifier, true, wildcards: !self.serializer_disable_wildcards)
|
75
|
+
serializer_output_registration.register_alias(self, media_type_identifier, victim_identifier, true, hide_variant, wildcards: !self.serializer_disable_wildcards)
|
72
76
|
end
|
73
77
|
|
74
78
|
def input(view: nil, version: nil, versions: nil, &block)
|
@@ -73,21 +73,29 @@ module MediaTypes
|
|
73
73
|
def initialize(identifier, inout)
|
74
74
|
super(
|
75
75
|
"Serializer tried to define an #{inout}_alias that points to the media type identifier #{identifier} but no such #{inout} has been defined yet. Please move the #{inout} definition above the alias.\n\n" \
|
76
|
-
"Move the
|
76
|
+
"Move the #{inout} definition above the alias:\n" \
|
77
77
|
"\n" \
|
78
78
|
"class MySerializer < MediaTypes::Serialization::Base\n" \
|
79
79
|
"#...\n" \
|
80
|
-
"
|
80
|
+
"#{inout} do\n" \
|
81
81
|
" # ...\n" \
|
82
82
|
"end\n" \
|
83
83
|
"\n" \
|
84
|
-
"
|
84
|
+
"#{inout}_alias 'text/html'\n" \
|
85
85
|
"# ^----- move here\n" \
|
86
86
|
'end'
|
87
87
|
)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
class VersionedAliasDefinitionError < ConfigurationError
|
92
|
+
def initialize(identifier, inout, prefix_match)
|
93
|
+
super(
|
94
|
+
"Serializer tried to define an #{inout}_alias that points to the media type identifier #{identifier} but no such #{inout} has been defined yet. An #{inout} named #{prefix_match} was found. Often this can be fixed by providing an #{inout} with a nil version."
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
91
99
|
class DuplicateDefinitionError < ConfigurationError
|
92
100
|
def initialize(identifier, inout)
|
93
101
|
super("Serializer tried to define an #{inout} using the media type identifier #{identifier}, but another #{inout} was already defined with that identifier. Please remove one of the two.")
|
@@ -27,8 +27,8 @@ class FakeValidator
|
|
27
27
|
def identifier
|
28
28
|
suffix = suffixes[[internal_view, internal_version]] || ''
|
29
29
|
result = prefix
|
30
|
-
result += '.' + internal_view.to_s unless internal_view.nil?
|
31
30
|
result += '.v' + internal_version.to_s unless internal_version.nil?
|
31
|
+
result += '.' + internal_view.to_s unless internal_view.nil?
|
32
32
|
result += '+' + suffix.to_s unless suffix.empty?
|
33
33
|
|
34
34
|
result
|
@@ -31,14 +31,23 @@ module MediaTypes
|
|
31
31
|
register_wildcards(identifier, registration) if wildcards && inout == :output
|
32
32
|
end
|
33
33
|
|
34
|
-
def register_alias(serializer, alias_identifier, target_identifier, optional, wildcards: true)
|
35
|
-
raise DuplicateDefinitionError.new(
|
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
36
|
|
37
|
-
|
37
|
+
unless registrations.key? target_identifier
|
38
|
+
potential_match = registrations.keys.find do |k|
|
39
|
+
k.starts_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
|
38
44
|
|
39
45
|
target = registrations[target_identifier]
|
40
46
|
|
41
|
-
|
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
|
42
51
|
registrations[alias_identifier] = registration
|
43
52
|
|
44
53
|
register_wildcards(alias_identifier, registration) if wildcards && inout == :output
|
@@ -103,7 +112,7 @@ module MediaTypes
|
|
103
112
|
private
|
104
113
|
|
105
114
|
def register_wildcards(identifier, registration)
|
106
|
-
new_alias = SerializationAliasRegistration.new registration.serializer, registration.inout, registration.validator, identifier, registration, true
|
115
|
+
new_alias = SerializationAliasRegistration.new registration.serializer, registration.inout, registration.validator, identifier, registration, true, true
|
107
116
|
|
108
117
|
registrations['*/*'] = new_alias unless has? '*/*'
|
109
118
|
|
@@ -160,14 +169,14 @@ module MediaTypes
|
|
160
169
|
begin
|
161
170
|
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
162
171
|
validator.validate!(victim)
|
163
|
-
rescue MediaTypes::Scheme::ValidationError, Oj::ParseError, JSON::ParserError => inner
|
172
|
+
rescue MediaTypes::Scheme::ValidationError, Oj::ParseError, JSON::ParserError, EncodingError => inner
|
164
173
|
raise InputValidationFailedError, inner
|
165
174
|
end
|
166
175
|
else
|
167
176
|
begin
|
168
177
|
victim = MediaTypes::Serialization.json_decoder.call(victim)
|
169
178
|
validator.validate!(victim)
|
170
|
-
rescue MediaTypes::Scheme::ValidationError, JSON::ParserError => inner
|
179
|
+
rescue MediaTypes::Scheme::ValidationError, JSON::ParserError, EncodingError => inner
|
171
180
|
raise InputValidationFailedError, inner
|
172
181
|
end
|
173
182
|
end
|
@@ -204,9 +213,10 @@ module MediaTypes
|
|
204
213
|
|
205
214
|
# A registration that calls another registration when called.
|
206
215
|
class SerializationAliasRegistration < SerializationBaseRegistration
|
207
|
-
def initialize(serializer, inout, validator, display_identifier, target, optional)
|
216
|
+
def initialize(serializer, inout, validator, display_identifier, target, optional, hide_variant)
|
208
217
|
self.target = target
|
209
218
|
self.optional = optional
|
219
|
+
self.hide_variant = hide_variant
|
210
220
|
super(serializer, inout, validator, display_identifier)
|
211
221
|
end
|
212
222
|
|
@@ -229,7 +239,7 @@ module MediaTypes
|
|
229
239
|
target.call(victim, context, dsl: dsl, raw: raw)
|
230
240
|
end
|
231
241
|
|
232
|
-
attr_accessor :target, :optional
|
242
|
+
attr_accessor :target, :optional, :hide_variant
|
233
243
|
end
|
234
244
|
end
|
235
245
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'erb'
|
4
4
|
require 'media_types/serialization/base'
|
5
|
+
require 'media_types/serialization/utils/accept_language_header'
|
5
6
|
|
6
7
|
module MediaTypes
|
7
8
|
module Serialization
|
@@ -9,13 +10,19 @@ module MediaTypes
|
|
9
10
|
class ProblemSerializer < MediaTypes::Serialization::Base
|
10
11
|
|
11
12
|
unvalidated 'application/vnd.delftsolutions.problem'
|
13
|
+
disable_wildcards
|
12
14
|
|
13
15
|
output do |problem, _, context|
|
14
16
|
raise 'No translations defined, add at least one title' unless problem.translations.keys.any?
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
accept_language_header = Utils::AcceptLanguageHeader.new(context.request.get_header(HEADER_ACCEPT_LANGUAGE) || '')
|
19
|
+
translation_entry = accept_language_header.map do |locale|
|
20
|
+
problem.translations.keys.find do |l|
|
21
|
+
l.start_with? locale.locale
|
22
|
+
end
|
23
|
+
end.compact.first || problem.translations.keys.first
|
24
|
+
translation = problem.translations[translation_entry]
|
25
|
+
|
19
26
|
title = translation[:title]
|
20
27
|
detail = translation[:detail] || problem.error.message
|
21
28
|
|
@@ -33,12 +40,19 @@ module MediaTypes
|
|
33
40
|
output_alias 'application/problem+json'
|
34
41
|
|
35
42
|
output_raw view: :html do |problem, _, context|
|
36
|
-
|
37
|
-
|
38
|
-
|
43
|
+
accept_language_header = Utils::AcceptLanguageHeader.new(context.request.get_header(HEADER_ACCEPT_LANGUAGE) || '')
|
44
|
+
translation_entry = accept_language_header.map do |locale|
|
45
|
+
problem.translations.keys.find do |l|
|
46
|
+
l.starts_with? locale.locale
|
47
|
+
end
|
48
|
+
end.compact.first || problem.translations.keys.first
|
49
|
+
translation = problem.translations[translation_entry]
|
50
|
+
|
39
51
|
title = translation[:title]
|
40
52
|
detail = translation[:detail] || problem.error.message
|
41
53
|
|
54
|
+
detail_lang = translation[:detail].nil? ? 'en' : translation_entry
|
55
|
+
|
42
56
|
input = OpenStruct.new(
|
43
57
|
title: title,
|
44
58
|
detail: detail,
|
@@ -61,11 +75,11 @@ module MediaTypes
|
|
61
75
|
</header>
|
62
76
|
<section id="content">
|
63
77
|
<nav>
|
64
|
-
<section id="description">
|
78
|
+
<section id="description" lang="#{translation_entry}">
|
65
79
|
<h2><a href="<%= help_url %>"><%= CGI::escapeHTML(title) %></a></h2>
|
66
80
|
</section>
|
67
81
|
</nav>
|
68
|
-
<main>
|
82
|
+
<main lang="#{detail_lang}">
|
69
83
|
<p><%= detail %>
|
70
84
|
</main>
|
71
85
|
</section>
|
@@ -76,8 +90,7 @@ module MediaTypes
|
|
76
90
|
template.result(input.instance_eval { binding })
|
77
91
|
end
|
78
92
|
|
79
|
-
|
80
|
-
self.serializer_output_registration.registrations.delete('*/*')
|
93
|
+
enable_wildcards
|
81
94
|
|
82
95
|
output_alias_optional 'text/html', view: :html
|
83
96
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
=begin
|
2
|
+
The MIT License (MIT)
|
3
|
+
|
4
|
+
Copyright (c) 2019 Derk-Jan Karrenbeld
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
23
|
+
=end
|
24
|
+
|
25
|
+
require 'media_types/serialization/utils/header_list'
|
26
|
+
|
27
|
+
module MediaTypes
|
28
|
+
module Serialization
|
29
|
+
module Utils
|
30
|
+
class AcceptHeader < DelegateClass(Array)
|
31
|
+
def initialize(value)
|
32
|
+
__setobj__ HeaderList.new(value, entry_klazz: AcceptHeader::Entry)
|
33
|
+
end
|
34
|
+
|
35
|
+
class Entry
|
36
|
+
def initialize(media_type, index:, parameters:)
|
37
|
+
self.media_type = media_type
|
38
|
+
self.parameters = parameters
|
39
|
+
self.index = index
|
40
|
+
|
41
|
+
freeze
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :media_type
|
45
|
+
|
46
|
+
# noinspection RubyInstanceMethodNamingConvention
|
47
|
+
def q
|
48
|
+
parameters.fetch(:q) { 1.0 }.to_f
|
49
|
+
end
|
50
|
+
|
51
|
+
def <=>(other)
|
52
|
+
quality = other.q <=> q
|
53
|
+
return quality unless quality.zero?
|
54
|
+
index <=> other.send(:index)
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](parameter)
|
58
|
+
parameters.fetch(String(parameter).to_sym)
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_header
|
62
|
+
to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
[media_type].concat(parameters.map { |k, v| "#{k}=#{v}" }).compact.reject(&:empty?).join('; ')
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_writer :media_type
|
72
|
+
attr_accessor :parameters, :index
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|