hanami-controller 2.2.0 → 2.3.0.beta2
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/CHANGELOG.md +88 -0
- data/README.md +87 -88
- data/hanami-controller.gemspec +3 -3
- data/lib/hanami/action/cache/cache_control.rb +1 -0
- data/lib/hanami/action/cache/conditional_get.rb +1 -1
- data/lib/hanami/action/cache/expires.rb +1 -0
- data/lib/hanami/action/config/formats.rb +153 -78
- data/lib/hanami/action/config.rb +30 -1
- data/lib/hanami/action/constants.rb +8 -8
- data/lib/hanami/action/errors.rb +1 -1
- data/lib/hanami/action/mime.rb +202 -101
- data/lib/hanami/action/params.rb +1 -7
- data/lib/hanami/action/rack/file.rb +2 -2
- data/lib/hanami/action/rack_utils.rb +11 -0
- data/lib/hanami/action/request/session.rb +68 -0
- data/lib/hanami/action/request.rb +29 -3
- data/lib/hanami/action/response.rb +8 -5
- data/lib/hanami/action.rb +17 -5
- data/lib/hanami/controller/version.rb +1 -1
- metadata +12 -13
|
@@ -11,35 +11,57 @@ module Hanami
|
|
|
11
11
|
# @since 2.0.0
|
|
12
12
|
# @api private
|
|
13
13
|
class Formats
|
|
14
|
-
include Dry.Equalizer(:
|
|
14
|
+
include Dry.Equalizer(:accepted, :mapping)
|
|
15
15
|
|
|
16
|
-
# Default MIME type to format mapping
|
|
17
|
-
#
|
|
18
16
|
# @since 2.0.0
|
|
19
17
|
# @api private
|
|
20
|
-
|
|
21
|
-
"application/octet-stream" => :all,
|
|
22
|
-
"*/*" => :all
|
|
23
|
-
}.freeze
|
|
18
|
+
attr_reader :mapping
|
|
24
19
|
|
|
20
|
+
# The array of formats to accept requests by.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# config.formats.accepted = [:html, :json]
|
|
24
|
+
# config.formats.accepted # => [:html, :json]
|
|
25
|
+
#
|
|
25
26
|
# @since 2.0.0
|
|
26
|
-
# @api
|
|
27
|
-
attr_reader :
|
|
27
|
+
# @api public
|
|
28
|
+
attr_reader :accepted
|
|
29
|
+
|
|
30
|
+
# @see #accepted
|
|
31
|
+
#
|
|
32
|
+
# @since 2.0.0
|
|
33
|
+
# @api public
|
|
34
|
+
def values
|
|
35
|
+
msg = <<~TEXT
|
|
36
|
+
Hanami::Action `config.formats.values` is deprecated and will be removed in Hanami 2.4.
|
|
37
|
+
|
|
38
|
+
Please use `config.formats.accepted` instead.
|
|
39
|
+
|
|
40
|
+
See https://guides.hanamirb.org/v2.3/actions/formats-and-mime-types/ for details.
|
|
41
|
+
TEXT
|
|
42
|
+
warn(msg, category: :deprecated)
|
|
43
|
+
|
|
44
|
+
accepted
|
|
45
|
+
end
|
|
28
46
|
|
|
29
|
-
#
|
|
47
|
+
# Returns the default format name.
|
|
48
|
+
#
|
|
49
|
+
# When a request is received that cannot
|
|
50
|
+
#
|
|
51
|
+
# @return [Symbol, nil] the default format name, if any
|
|
30
52
|
#
|
|
31
53
|
# @example
|
|
32
|
-
# config.formats.
|
|
33
|
-
# config.formats.values # => [:html, :json]
|
|
54
|
+
# @config.formats.default # => :json
|
|
34
55
|
#
|
|
35
56
|
# @since 2.0.0
|
|
36
57
|
# @api public
|
|
37
|
-
attr_reader :
|
|
58
|
+
attr_reader :default
|
|
38
59
|
|
|
39
60
|
# @since 2.0.0
|
|
40
61
|
# @api private
|
|
41
|
-
def initialize(
|
|
42
|
-
@
|
|
62
|
+
def initialize(accepted: [], default: nil, mapping: {})
|
|
63
|
+
@accepted = accepted
|
|
64
|
+
@default = default
|
|
43
65
|
@mapping = mapping
|
|
44
66
|
end
|
|
45
67
|
|
|
@@ -47,15 +69,74 @@ module Hanami
|
|
|
47
69
|
# @api private
|
|
48
70
|
private def initialize_copy(original) # rubocop:disable Style/AccessModifierDeclarations
|
|
49
71
|
super
|
|
50
|
-
@
|
|
72
|
+
@accepted = original.accepted.dup
|
|
73
|
+
@default = original.default
|
|
51
74
|
@mapping = original.mapping.dup
|
|
52
75
|
end
|
|
53
76
|
|
|
77
|
+
# !@attribute [w] accepted
|
|
78
|
+
# @since 2.3.0
|
|
79
|
+
# @api public
|
|
80
|
+
def accepted=(formats)
|
|
81
|
+
@accepted = formats.map { |f| Hanami::Utils::Kernel.Symbol(f) }
|
|
82
|
+
end
|
|
83
|
+
|
|
54
84
|
# !@attribute [w] values
|
|
55
85
|
# @since 2.0.0
|
|
56
86
|
# @api public
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
alias_method :values=, :accepted=
|
|
88
|
+
|
|
89
|
+
# @since 2.3.0
|
|
90
|
+
def accept(*formats)
|
|
91
|
+
self.default = formats.first if default.nil?
|
|
92
|
+
self.accepted = accepted | formats
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @api private
|
|
96
|
+
def accepted_formats(standard_formats = {})
|
|
97
|
+
accepted.to_h { |format|
|
|
98
|
+
[
|
|
99
|
+
format,
|
|
100
|
+
mapping.fetch(format) { standard_formats[format] }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @since 2.3.0
|
|
106
|
+
def default=(format)
|
|
107
|
+
@default = format.to_sym
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Registers a format and its associated media types.
|
|
111
|
+
#
|
|
112
|
+
# @param format [Symbol] the format name
|
|
113
|
+
# @param media_type [String] the format's media type
|
|
114
|
+
# @param accept_types [Array<String>] media types to accept in request `Accept` headers
|
|
115
|
+
# @param content_types [Array<String>] media types to accept in request `Content-Type` headers
|
|
116
|
+
#
|
|
117
|
+
# @example
|
|
118
|
+
# config.formats.register(:scim, media_type: "application/json+scim")
|
|
119
|
+
#
|
|
120
|
+
# config.formats.register(
|
|
121
|
+
# :jsonapi,
|
|
122
|
+
# "application/vnd.api+json",
|
|
123
|
+
# accept_types: ["application/vnd.api+json", "application/json"],
|
|
124
|
+
# content_types: ["application/vnd.api+json", "application/json"]
|
|
125
|
+
# )
|
|
126
|
+
#
|
|
127
|
+
# @return [self]
|
|
128
|
+
#
|
|
129
|
+
# @since 2.3.0
|
|
130
|
+
# @api public
|
|
131
|
+
def register(format, media_type, accept_types: [media_type], content_types: [media_type])
|
|
132
|
+
mapping[format] = Mime::Format.new(
|
|
133
|
+
name: format.to_sym,
|
|
134
|
+
media_type: media_type,
|
|
135
|
+
accept_types: accept_types,
|
|
136
|
+
content_types: content_types
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self
|
|
59
140
|
end
|
|
60
141
|
|
|
61
142
|
# @overload add(format)
|
|
@@ -83,20 +164,30 @@ module Hanami
|
|
|
83
164
|
# @param mime_types [Array<String>]
|
|
84
165
|
#
|
|
85
166
|
# @example
|
|
86
|
-
# config.formats.add(:json, ["application/json+scim"
|
|
167
|
+
# config.formats.add(:json, ["application/json+scim"])
|
|
87
168
|
#
|
|
88
169
|
# @return [self]
|
|
89
170
|
#
|
|
90
171
|
# @since 2.0.0
|
|
91
172
|
# @api public
|
|
92
|
-
def add(format, mime_types
|
|
93
|
-
|
|
173
|
+
def add(format, mime_types)
|
|
174
|
+
msg = <<~TEXT
|
|
175
|
+
Hanami::Action `config.formats.add` is deprecated and will be removed in Hanami 2.4.
|
|
176
|
+
|
|
177
|
+
Please use `config.formats.register` instead.
|
|
178
|
+
|
|
179
|
+
See https://guides.hanamirb.org/v2.3/actions/formats-and-mime-types/ for details.
|
|
180
|
+
TEXT
|
|
181
|
+
warn(msg, category: :deprecated)
|
|
182
|
+
|
|
183
|
+
mime_type = Array(mime_types).first
|
|
94
184
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
end
|
|
185
|
+
# The old behaviour would have subsequent mime types _replacing_ previous ones
|
|
186
|
+
mapping.reject! { |_, format| format.media_type == mime_type }
|
|
98
187
|
|
|
99
|
-
|
|
188
|
+
register(format, Array(mime_types).first, accept_types: mime_types)
|
|
189
|
+
|
|
190
|
+
accept(format) unless @accepted.include?(format)
|
|
100
191
|
|
|
101
192
|
self
|
|
102
193
|
end
|
|
@@ -104,31 +195,19 @@ module Hanami
|
|
|
104
195
|
# @since 2.0.0
|
|
105
196
|
# @api private
|
|
106
197
|
def empty?
|
|
107
|
-
|
|
198
|
+
accepted.empty?
|
|
108
199
|
end
|
|
109
200
|
|
|
110
201
|
# @since 2.0.0
|
|
111
202
|
# @api private
|
|
112
203
|
def any?
|
|
113
|
-
@
|
|
204
|
+
@accepted.any?
|
|
114
205
|
end
|
|
115
206
|
|
|
116
207
|
# @since 2.0.0
|
|
117
208
|
# @api private
|
|
118
209
|
def map(&blk)
|
|
119
|
-
@
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# @since 2.0.0
|
|
123
|
-
# @api private
|
|
124
|
-
def mapping=(mappings)
|
|
125
|
-
@mapping = {}
|
|
126
|
-
|
|
127
|
-
mappings.each do |format_name, mime_types|
|
|
128
|
-
Array(mime_types).each do |mime_type|
|
|
129
|
-
add(format_name, mime_type)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
210
|
+
@accepted.map(&blk)
|
|
132
211
|
end
|
|
133
212
|
|
|
134
213
|
# Clears any previously added mappings and format values.
|
|
@@ -138,15 +217,24 @@ module Hanami
|
|
|
138
217
|
# @since 2.0.0
|
|
139
218
|
# @api public
|
|
140
219
|
def clear
|
|
141
|
-
@
|
|
142
|
-
@
|
|
220
|
+
@accepted = []
|
|
221
|
+
@default = nil
|
|
222
|
+
@mapping = {}
|
|
143
223
|
|
|
144
224
|
self
|
|
145
225
|
end
|
|
146
226
|
|
|
147
|
-
#
|
|
227
|
+
# Returns an array of all accepted media types.
|
|
228
|
+
#
|
|
229
|
+
# @since 2.3.0
|
|
230
|
+
# @api public
|
|
231
|
+
def accept_types
|
|
232
|
+
accepted.map { |format| mapping[format]&.accept_types }.flatten(1).compact
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Retrieve the format name associated with the given media type
|
|
148
236
|
#
|
|
149
|
-
# @param
|
|
237
|
+
# @param media_type [String] the media Type
|
|
150
238
|
#
|
|
151
239
|
# @return [Symbol,NilClass] the associated format name, if any
|
|
152
240
|
#
|
|
@@ -157,59 +245,46 @@ module Hanami
|
|
|
157
245
|
#
|
|
158
246
|
# @since 2.0.0
|
|
159
247
|
# @api public
|
|
160
|
-
def format_for(
|
|
161
|
-
|
|
248
|
+
def format_for(media_type)
|
|
249
|
+
mapping.values.reverse.find { |format| format.media_type == media_type }&.name
|
|
162
250
|
end
|
|
163
251
|
|
|
164
|
-
# Returns the
|
|
252
|
+
# Returns the media type associated with the given format.
|
|
165
253
|
#
|
|
166
254
|
# @param format [Symbol] the format name
|
|
167
255
|
#
|
|
168
|
-
# @return [String, nil] the associated
|
|
256
|
+
# @return [String, nil] the associated media type, if any
|
|
169
257
|
#
|
|
170
258
|
# @example
|
|
171
|
-
# @config.formats.
|
|
259
|
+
# @config.formats.media_type_for(:json) # => "application/json"
|
|
172
260
|
#
|
|
173
261
|
# @see #format_for
|
|
174
262
|
#
|
|
175
|
-
# @since 2.
|
|
263
|
+
# @since 2.3.0
|
|
176
264
|
# @api public
|
|
177
|
-
def
|
|
178
|
-
|
|
265
|
+
def media_type_for(format)
|
|
266
|
+
mapping[format]&.media_type
|
|
179
267
|
end
|
|
180
268
|
|
|
181
|
-
#
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
#
|
|
185
|
-
# @param format [Symbol] the format name
|
|
186
|
-
#
|
|
187
|
-
# @return [Array<String>] the associated MIME types
|
|
188
|
-
#
|
|
189
|
-
# @since 2.0.0
|
|
190
|
-
# @api public
|
|
191
|
-
def mime_types_for(format)
|
|
192
|
-
@mapping.each_with_object([]) { |(mime_type, f), arr| arr << mime_type if format == f }
|
|
269
|
+
# @api private
|
|
270
|
+
def accept_types_for(format)
|
|
271
|
+
mapping[format]&.accept_types || []
|
|
193
272
|
end
|
|
194
273
|
|
|
195
|
-
#
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
#
|
|
201
|
-
#
|
|
274
|
+
# @api private
|
|
275
|
+
def content_types_for(format)
|
|
276
|
+
mapping[format]&.content_types || []
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @see #media_type_for
|
|
202
280
|
# @since 2.0.0
|
|
203
281
|
# @api public
|
|
204
|
-
|
|
205
|
-
@values.first
|
|
206
|
-
end
|
|
282
|
+
alias_method :mime_type_for, :media_type_for
|
|
207
283
|
|
|
284
|
+
# @see #media_type_for
|
|
208
285
|
# @since 2.0.0
|
|
209
|
-
# @api
|
|
210
|
-
|
|
211
|
-
@mapping.keys
|
|
212
|
-
end
|
|
286
|
+
# @api public
|
|
287
|
+
alias_method :mime_types_for, :accept_types_for
|
|
213
288
|
end
|
|
214
289
|
end
|
|
215
290
|
end
|
data/lib/hanami/action/config.rb
CHANGED
|
@@ -68,7 +68,8 @@ module Hanami
|
|
|
68
68
|
|
|
69
69
|
# Sets the format (or formats) for the action.
|
|
70
70
|
#
|
|
71
|
-
# To configure custom formats and MIME type mappings, call {Formats#
|
|
71
|
+
# To configure custom formats and MIME type mappings, call {Formats#register formats.register}
|
|
72
|
+
# first.
|
|
72
73
|
#
|
|
73
74
|
# @example
|
|
74
75
|
# config.format :html, :json
|
|
@@ -82,10 +83,20 @@ module Hanami
|
|
|
82
83
|
# @since 2.0.0
|
|
83
84
|
# @api public
|
|
84
85
|
def format(*formats)
|
|
86
|
+
msg = <<~TEXT
|
|
87
|
+
Hanami::Action `config.format` is deprecated and will be removed in Hanami 2.4.
|
|
88
|
+
|
|
89
|
+
Please use `config.formats.register` and/or `config.formats.accept` instead.
|
|
90
|
+
|
|
91
|
+
See https://guides.hanamirb.org/v2.3/actions/formats-and-mime-types/ for details.
|
|
92
|
+
TEXT
|
|
93
|
+
warn(msg, category: :deprecated)
|
|
94
|
+
|
|
85
95
|
if formats.empty?
|
|
86
96
|
self.formats.values
|
|
87
97
|
else
|
|
88
98
|
self.formats.values = formats
|
|
99
|
+
self.formats.default = formats.first
|
|
89
100
|
end
|
|
90
101
|
end
|
|
91
102
|
|
|
@@ -117,6 +128,24 @@ module Hanami
|
|
|
117
128
|
#
|
|
118
129
|
# @since 0.4.0
|
|
119
130
|
|
|
131
|
+
# @!attribute [rw] default_tld_length
|
|
132
|
+
#
|
|
133
|
+
# Sets the default TLD length for host names. It is used to extract the
|
|
134
|
+
# subdomain(s) in `Request#subdomains`.
|
|
135
|
+
#
|
|
136
|
+
# Defaults to 1.
|
|
137
|
+
#
|
|
138
|
+
# @example
|
|
139
|
+
# # For *.example.com
|
|
140
|
+
# config.default_tld_length = 1
|
|
141
|
+
#
|
|
142
|
+
# # Or for *.example.co.uk
|
|
143
|
+
# config.default_tld_length = 2
|
|
144
|
+
#
|
|
145
|
+
# @return [Integer] the number of subdomains
|
|
146
|
+
#
|
|
147
|
+
# @since 2.3.0
|
|
148
|
+
|
|
120
149
|
# @!attribute [rw] cookies
|
|
121
150
|
#
|
|
122
151
|
# Sets default cookie options for all responses.
|
|
@@ -50,14 +50,14 @@ module Hanami
|
|
|
50
50
|
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
|
|
51
51
|
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
|
|
52
52
|
ENTITY_HEADERS = {
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
53
|
+
"allow" => true,
|
|
54
|
+
"content-encoding" => true,
|
|
55
|
+
"content-language" => true,
|
|
56
|
+
"content-location" => true,
|
|
57
|
+
"content-md5" => true,
|
|
58
|
+
"content-range" => true,
|
|
59
|
+
"expires" => true,
|
|
60
|
+
"last-modified" => true,
|
|
61
61
|
"extension-header" => true
|
|
62
62
|
}.freeze
|
|
63
63
|
|
data/lib/hanami/action/errors.rb
CHANGED