hanami-controller 2.0.0.alpha8 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,6 @@
1
- require 'hanami/action/cache/directives'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/action/cache/directives"
2
4
 
3
5
  module Hanami
4
6
  class Action
@@ -8,12 +10,6 @@ module Hanami
8
10
  # @since 0.3.0
9
11
  # @api private
10
12
  module CacheControl
11
- # The HTTP header for Cache-Control
12
- #
13
- # @since 0.3.0
14
- # @api private
15
- HEADER = 'Cache-Control'.freeze
16
-
17
13
  # @since 0.3.0
18
14
  # @api private
19
15
  def self.included(base)
@@ -37,7 +33,7 @@ module Hanami
37
33
  def cache_control_directives
38
34
  @cache_control_directives || Object.new.tap do |null_object|
39
35
  def null_object.headers
40
- ::Hash.new
36
+ {}
41
37
  end
42
38
  end
43
39
  end
@@ -50,7 +46,10 @@ module Hanami
50
46
  #
51
47
  # @see Hanami::Action#finish
52
48
  def finish(_, res, _)
53
- res.headers.merge!(self.class.cache_control_directives.headers) unless res.headers.include? HEADER
49
+ unless res.headers.include?(Action::CACHE_CONTROL)
50
+ res.headers.merge!(self.class.cache_control_directives.headers)
51
+ end
52
+
54
53
  super
55
54
  end
56
55
 
@@ -59,6 +58,11 @@ module Hanami
59
58
  # @since 0.3.0
60
59
  # @api private
61
60
  class Directives
61
+ # @since 2.0.0
62
+ # @api private
63
+ SEPARATOR = ", "
64
+ private_constant :SEPARATOR
65
+
62
66
  # @since 0.3.0
63
67
  # @api private
64
68
  def initialize(*values)
@@ -69,7 +73,7 @@ module Hanami
69
73
  # @api private
70
74
  def headers
71
75
  if @directives.any?
72
- { HEADER => @directives.join(', ') }
76
+ {Action::CACHE_CONTROL => @directives.join(SEPARATOR)}
73
77
  else
74
78
  {}
75
79
  end
@@ -1,28 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "hanami/utils/blank"
2
4
 
3
5
  module Hanami
4
6
  class Action
5
7
  module Cache
6
- # @since 0.3.0
7
- # @api private
8
- IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
9
-
10
- # The HTTP header for ETag
11
- #
12
- # @since 0.3.0
13
- # @api private
14
- ETAG = 'ETag'.freeze
15
-
16
- # @since 0.3.0
17
- # @api private
18
- IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
19
-
20
- # The HTTP header for Last-Modified
21
- #
22
- # @since 0.3.0
23
- # @api private
24
- LAST_MODIFIED = 'Last-Modified'.freeze
25
-
26
8
  # ETag value object
27
9
  #
28
10
  # @since 0.3.0
@@ -43,7 +25,7 @@ module Hanami
43
25
  # @since 0.3.0
44
26
  # @api private
45
27
  def header
46
- { ETAG => @value } if @value
28
+ {Action::ETAG => @value} if @value
47
29
  end
48
30
 
49
31
  private
@@ -51,7 +33,7 @@ module Hanami
51
33
  # @since 0.3.0
52
34
  # @api private
53
35
  def none_match
54
- @env[IF_NONE_MATCH]
36
+ @env[Action::IF_NONE_MATCH]
55
37
  end
56
38
  end
57
39
 
@@ -78,7 +60,7 @@ module Hanami
78
60
  # @since 0.3.0
79
61
  # @api private
80
62
  def header
81
- { LAST_MODIFIED => @value.httpdate } if @value && @value.respond_to?(:httpdate)
63
+ {Action::LAST_MODIFIED => @value.httpdate} if @value.respond_to?(:httpdate)
82
64
  end
83
65
 
84
66
  private
@@ -86,7 +68,7 @@ module Hanami
86
68
  # @since 0.3.0
87
69
  # @api private
88
70
  def modified_since
89
- @env[IF_MODIFIED_SINCE]
71
+ @env[Action::IF_MODIFIED_SINCE]
90
72
  end
91
73
  end
92
74
 
@@ -99,7 +81,7 @@ module Hanami
99
81
  # @since 0.3.0
100
82
  # @api private
101
83
  def initialize(env, options)
102
- @validations = [ ETag.new(env, options[:etag]), LastModified.new(env, options[:last_modified]) ]
84
+ @validations = [ETag.new(env, options[:etag]), LastModified.new(env, options[:last_modified])]
103
85
  end
104
86
 
105
87
  # @since 0.3.0
@@ -111,7 +93,7 @@ module Hanami
111
93
  # @since 0.3.0
112
94
  # @api private
113
95
  def headers
114
- @validations.map(&:header).compact.reduce Hash.new, :merge
96
+ @validations.map(&:header).compact.reduce({}, :merge)
115
97
  end
116
98
  end
117
99
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  class Action
3
5
  module Cache
@@ -5,13 +7,13 @@ module Hanami
5
7
  #
6
8
  # @since 0.3.0
7
9
  # @api private
8
- VALUE_DIRECTIVES = %i(max_age s_maxage min_fresh max_stale).freeze
10
+ VALUE_DIRECTIVES = %i[max_age s_maxage min_fresh max_stale].freeze
9
11
 
10
12
  # Cache-Control directives which are implicitly true
11
13
  #
12
14
  # @since 0.3.0
13
15
  # @api private
14
- NON_VALUE_DIRECTIVES = %i(public private no_cache no_store no_transform must_revalidate proxy_revalidate).freeze
16
+ NON_VALUE_DIRECTIVES = %i[public private no_cache no_store no_transform must_revalidate proxy_revalidate].freeze
15
17
 
16
18
  # Class representing value directives
17
19
  #
@@ -63,7 +65,7 @@ module Hanami
63
65
  # @since 0.3.0
64
66
  # @api private
65
67
  def to_str
66
- @name.to_s.tr('_', '-')
68
+ @name.to_s.tr("_", "-")
67
69
  end
68
70
 
69
71
  # @since 0.3.0
@@ -85,7 +87,7 @@ module Hanami
85
87
  def initialize(*values)
86
88
  @directives = []
87
89
  values.each do |directive_key|
88
- if directive_key.kind_of? Hash
90
+ if directive_key.is_a? Hash
89
91
  directive_key.each { |name, value| self.<< ValueDirective.new(name, value) }
90
92
  else
91
93
  self.<< NonValueDirective.new(directive_key)
@@ -95,8 +97,8 @@ module Hanami
95
97
 
96
98
  # @since 0.3.0
97
99
  # @api private
98
- def each
99
- @directives.each { |d| yield d }
100
+ def each(&block)
101
+ @directives.each(&block)
100
102
  end
101
103
 
102
104
  # @since 0.3.0
@@ -1,4 +1,6 @@
1
- require 'hanami/action/cache/cache_control'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/action/cache/cache_control"
2
4
 
3
5
  module Hanami
4
6
  class Action
@@ -8,12 +10,6 @@ module Hanami
8
10
  # @since 0.3.0
9
11
  # @api private
10
12
  module Expires
11
- # The HTTP header for Expires
12
- #
13
- # @since 0.3.0
14
- # @api private
15
- HEADER = 'Expires'.freeze
16
-
17
13
  # @since 0.3.0
18
14
  # @api private
19
15
  def self.included(base)
@@ -37,7 +33,7 @@ module Hanami
37
33
  def expires_directives
38
34
  @expires_directives || Object.new.tap do |null_object|
39
35
  def null_object.headers
40
- Hash.new
36
+ {}
41
37
  end
42
38
  end
43
39
  end
@@ -50,7 +46,10 @@ module Hanami
50
46
  #
51
47
  # @see Hanami::Action#finish
52
48
  def finish(_, res, _)
53
- res.headers.merge!(self.class.expires_directives.headers) unless res.headers.include? HEADER
49
+ unless res.headers.include?(Action::EXPIRES)
50
+ res.headers.merge!(self.class.expires_directives.headers)
51
+ end
52
+
54
53
  super
55
54
  end
56
55
 
@@ -63,13 +62,13 @@ module Hanami
63
62
  # @api private
64
63
  def initialize(amount, *values)
65
64
  @amount = amount
66
- @cache_control = Hanami::Action::Cache::CacheControl::Directives.new(*(values << { max_age: amount }))
65
+ @cache_control = Hanami::Action::Cache::CacheControl::Directives.new(*(values << {max_age: amount}))
67
66
  end
68
67
 
69
68
  # @since 0.3.0
70
69
  # @api private
71
70
  def headers
72
- { HEADER => time.httpdate }.merge(@cache_control.headers)
71
+ {Action::EXPIRES => time.httpdate}.merge(@cache_control.headers)
73
72
  end
74
73
 
75
74
  private
@@ -1,6 +1,8 @@
1
- require 'hanami/action/cache/cache_control'
2
- require 'hanami/action/cache/expires'
3
- require 'hanami/action/cache/conditional_get'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/action/cache/cache_control"
4
+ require "hanami/action/cache/expires"
5
+ require "hanami/action/cache/conditional_get"
4
6
 
5
7
  module Hanami
6
8
  class Action
@@ -90,9 +90,9 @@ module Hanami
90
90
  # @since 0.2.0
91
91
  # @api private
92
92
  DEFAULT_FORMATS = {
93
- 'application/octet-stream' => :all,
94
- '*/*' => :all,
95
- 'text/html' => :html
93
+ "application/octet-stream" => :all,
94
+ "*/*" => :all,
95
+ "text/html" => :html
96
96
  }.freeze
97
97
 
98
98
  # @!method formats=(formats)
@@ -211,7 +211,7 @@ module Hanami
211
211
  # @see default_request_format=
212
212
  #
213
213
  # @since 0.5.0
214
- setting :default_request_format, constructor: -> format {
214
+ setting :default_request_format, constructor: -> (format) {
215
215
  Utils::Kernel.Symbol(format) unless format.nil?
216
216
  }
217
217
 
@@ -243,7 +243,7 @@ module Hanami
243
243
  # @see default_request_format=
244
244
  #
245
245
  # @since 0.5.0
246
- setting :default_response_format, constructor: -> format {
246
+ setting :default_response_format, constructor: -> (format) {
247
247
  Utils::Kernel.Symbol(format) unless format.nil?
248
248
  }
249
249
 
@@ -288,7 +288,7 @@ module Hanami
288
288
  # @see default_headers
289
289
  #
290
290
  # @example
291
- # configuration.default_headers = {'X-Frame-Options' => 'DENY'}
291
+ # configuration.default_headers = {"X-Frame-Options" => "DENY"}
292
292
  #
293
293
  # @!method default_headers
294
294
  #
@@ -299,7 +299,7 @@ module Hanami
299
299
  # @since 0.4.0
300
300
  #
301
301
  # @see default_headers=
302
- setting :default_headers, default: {}, constructor: -> headers { headers.compact }
302
+ setting :default_headers, default: {}, constructor: -> (headers) { headers.compact }
303
303
 
304
304
  # @!method cookies=(cookie_options)
305
305
  #
@@ -315,8 +315,8 @@ module Hanami
315
315
  #
316
316
  # @example
317
317
  # configuration.cookies = {
318
- # domain: 'hanamirb.org',
319
- # path: '/controller',
318
+ # domain: "hanamirb.org",
319
+ # path: "/controller",
320
320
  # secure: true,
321
321
  # httponly: true
322
322
  # }
@@ -330,7 +330,7 @@ module Hanami
330
330
  # @since 0.4.0
331
331
  #
332
332
  # @see cookies=
333
- setting :cookies, default: {}, constructor: -> cookie_options {
333
+ setting :cookies, default: {}, constructor: -> (cookie_options) {
334
334
  # Call `to_h` here to permit `ApplicationConfiguration::Cookies` object to be
335
335
  # provided when application actions are configured
336
336
  cookie_options.to_h.compact
@@ -362,7 +362,7 @@ module Hanami
362
362
  # @since 1.0.0
363
363
  #
364
364
  # @api private
365
- setting :root_directory, constructor: -> dir {
365
+ setting :root_directory, constructor: -> (dir) {
366
366
  dir ||= Dir.pwd
367
367
 
368
368
  Pathname(dir).realpath
@@ -375,7 +375,7 @@ module Hanami
375
375
  # @since 1.0.0
376
376
  #
377
377
  # @api private
378
- DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
378
+ DEFAULT_PUBLIC_DIRECTORY = "public"
379
379
 
380
380
  # @!method public_directory=(directory)
381
381
  #
@@ -389,6 +389,8 @@ module Hanami
389
389
  #
390
390
  # @return [void]
391
391
  #
392
+ # @since 2.0.0
393
+ #
392
394
  # @see root_directory
393
395
  # @see public_directory
394
396
  setting :public_directory, default: DEFAULT_PUBLIC_DIRECTORY
@@ -403,6 +405,8 @@ module Hanami
403
405
  # configuration.public_directory
404
406
  # # => "/path/to/root/public"
405
407
  #
408
+ # @since 2.0.0
409
+ #
406
410
  # @see public_directory=
407
411
  # @see root_directory=
408
412
  def public_directory
@@ -412,6 +416,8 @@ module Hanami
412
416
 
413
417
  private
414
418
 
419
+ # @since 2.0.0
420
+ # @api private
415
421
  def method_missing(name, *args, &block)
416
422
  if config.respond_to?(name)
417
423
  config.public_send(name, *args, &block)
@@ -420,6 +426,8 @@ module Hanami
420
426
  end
421
427
  end
422
428
 
429
+ # @since 2.0.0
430
+ # @api private
423
431
  def respond_to_missing?(name, _incude_all = false)
424
432
  config.respond_to?(name) || super
425
433
  end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+
5
+ module Hanami
6
+ class Action
7
+ # Rack SPEC response code
8
+ #
9
+ # @since 1.0.0
10
+ # @api private
11
+ RESPONSE_CODE = 0
12
+
13
+ # Rack SPEC response headers
14
+ #
15
+ # @since 1.0.0
16
+ # @api private
17
+ RESPONSE_HEADERS = 1
18
+
19
+ # Rack SPEC response body
20
+ #
21
+ # @since 1.0.0
22
+ # @api private
23
+ RESPONSE_BODY = 2
24
+
25
+ # @since 1.0.0
26
+ # @api private
27
+ DEFAULT_ERROR_CODE = 500
28
+
29
+ # Status codes that by RFC must not include a message body
30
+ #
31
+ # @since 0.3.2
32
+ # @api private
33
+ HTTP_STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 304).freeze
34
+
35
+ # Not Found
36
+ #
37
+ # @since 1.0.0
38
+ # @api private
39
+ NOT_FOUND = 404
40
+
41
+ # Entity headers allowed in blank body responses, according to
42
+ # RFC 2616 - Section 10 (HTTP 1.1).
43
+ #
44
+ # "The response MAY include new or updated metainformation in the form
45
+ # of entity-headers".
46
+ #
47
+ # @since 0.4.0
48
+ # @api private
49
+ #
50
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
51
+ # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
52
+ ENTITY_HEADERS = {
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
+ "extension-header" => true
62
+ }.freeze
63
+
64
+ # The request relative path
65
+ #
66
+ # @since 2.0.0
67
+ # @api private
68
+ PATH_INFO = ::Rack::PATH_INFO
69
+
70
+ # The request method
71
+ #
72
+ # @since 0.3.2
73
+ # @api private
74
+ REQUEST_METHOD = ::Rack::REQUEST_METHOD
75
+
76
+ # The Content-Length HTTP header
77
+ #
78
+ # @since 1.0.0
79
+ # @api private
80
+ CONTENT_LENGTH = ::Rack::CONTENT_LENGTH
81
+
82
+ # The non-standard HTTP header to pass the control over when a resource
83
+ # cannot be found by the current endpoint
84
+ #
85
+ # @since 1.0.0
86
+ # @api private
87
+ X_CASCADE = "X-Cascade"
88
+
89
+ # HEAD request
90
+ #
91
+ # @since 0.3.2
92
+ # @api private
93
+ HEAD = ::Rack::HEAD
94
+
95
+ # GET request
96
+ #
97
+ # @since 2.0.0
98
+ # @api private
99
+ GET = ::Rack::GET
100
+
101
+ # TRACE request
102
+ #
103
+ # @since 2.0.0
104
+ # @api private
105
+ TRACE = ::Rack::TRACE
106
+
107
+ # OPTIONS request
108
+ #
109
+ # @since 2.0.0
110
+ # @api private
111
+ OPTIONS = ::Rack::OPTIONS
112
+
113
+ # The key that returns accepted mime types from the Rack env
114
+ #
115
+ # @since 0.1.0
116
+ # @api private
117
+ HTTP_ACCEPT = "HTTP_ACCEPT"
118
+
119
+ # The header key to set the mime type of the response
120
+ #
121
+ # @since 0.1.0
122
+ # @api private
123
+ CONTENT_TYPE = ::Rack::CONTENT_TYPE
124
+
125
+ # The default mime type for an incoming HTTP request
126
+ #
127
+ # @since 0.1.0
128
+ # @api private
129
+ DEFAULT_ACCEPT = "*/*"
130
+
131
+ # The default mime type that is returned in the response
132
+ #
133
+ # @since 0.1.0
134
+ # @api private
135
+ DEFAULT_CONTENT_TYPE = "application/octet-stream"
136
+
137
+ # @since 0.2.0
138
+ # @api private
139
+ RACK_ERRORS = ::Rack::RACK_ERRORS
140
+
141
+ # The HTTP header for Cache-Control
142
+ #
143
+ # @since 2.0.0
144
+ # @api private
145
+ CACHE_CONTROL = ::Rack::CACHE_CONTROL
146
+
147
+ # @since 2.0.0
148
+ # @api private
149
+ IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
150
+
151
+ # The HTTP header for ETag
152
+ #
153
+ # @since 2.0.0
154
+ # @api private
155
+ ETAG = ::Rack::ETAG
156
+
157
+ # @since 2.0.0
158
+ # @api private
159
+ IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
160
+
161
+ # The HTTP header for Expires
162
+ #
163
+ # @since 2.0.0
164
+ # @api private
165
+ EXPIRES = ::Rack::EXPIRES
166
+
167
+ # The HTTP header for Last-Modified
168
+ #
169
+ # @since 0.3.0
170
+ # @api private
171
+ LAST_MODIFIED = "Last-Modified"
172
+
173
+ # This isn't part of Rack SPEC
174
+ #
175
+ # Exception notifiers use <tt>rack.exception</tt> instead of
176
+ # <tt>rack.errors</tt>, so we need to support it.
177
+ #
178
+ # @since 0.5.0
179
+ # @api private
180
+ #
181
+ # @see Hanami::Action::Throwable::RACK_ERRORS
182
+ # @see http://www.rubydoc.info/github/rack/rack/file/SPEC#The_Error_Stream
183
+ # @see https://github.com/hanami/controller/issues/133
184
+ RACK_EXCEPTION = "rack.exception"
185
+
186
+ # The HTTP header for redirects
187
+ #
188
+ # @since 0.2.0
189
+ # @api private
190
+ LOCATION = "Location"
191
+
192
+ # The key that returns Rack session params from the Rack env
193
+ # Please note that this is used only when an action is unit tested.
194
+ #
195
+ # @since 2.0.0
196
+ # @api private
197
+ #
198
+ # @example
199
+ # # action unit test
200
+ # action.call("rack.session" => { "foo" => "bar" })
201
+ # action.session[:foo] # => "bar"
202
+ #
203
+ # @api private
204
+ RACK_SESSION = ::Rack::RACK_SESSION
205
+
206
+ # @since 2.0.0
207
+ # @api private
208
+ REQUEST_ID = "hanami.request_id"
209
+
210
+ # @since 2.0.0
211
+ # @api private
212
+ DEFAULT_ID_LENGTH = 16
213
+
214
+ # The key that returns raw cookies from the Rack env
215
+ #
216
+ # @since 2.0.0
217
+ # @api private
218
+ HTTP_COOKIE = ::Rack::HTTP_COOKIE
219
+
220
+ # The key used by Rack to set the cookies as an Hash in the env
221
+ #
222
+ # @since 2.0.0
223
+ # @api private
224
+ COOKIE_HASH_KEY = ::Rack::RACK_REQUEST_COOKIE_HASH
225
+
226
+ # The key used by Rack to set the cookies as a String in the env
227
+ #
228
+ # @since 2.0.0
229
+ # @api private
230
+ COOKIE_STRING_KEY = ::Rack::RACK_REQUEST_COOKIE_STRING
231
+
232
+ # The key that returns raw input from the Rack env
233
+ #
234
+ # @since 2.0.0
235
+ # @api private
236
+ RACK_INPUT = ::Rack::RACK_INPUT
237
+
238
+ # The key that returns router params from the Rack env
239
+ # This is a builtin integration for Hanami::Router
240
+ #
241
+ # @since 2.0.0
242
+ # @api private
243
+ ROUTER_PARAMS = "router.params"
244
+
245
+ # Default HTTP request method for Rack env
246
+ #
247
+ # @since 2.0.0
248
+ # @api private
249
+ DEFAULT_REQUEST_METHOD = GET
250
+
251
+ # @since 2.0.0
252
+ # @api private
253
+ DEFAULT_CHARSET = "utf-8"
254
+
255
+ # The key that returns content mime type from the Rack env
256
+ #
257
+ # @since 2.0.0
258
+ # @api private
259
+ HTTP_CONTENT_TYPE = "CONTENT_TYPE"
260
+ end
261
+ end