hanami-controller 2.0.1 → 2.1.0.beta1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19de4a7e13f8845b766110c62f3fafef0d600cdc7e2ae12c0083f73f91fa0224
4
- data.tar.gz: fe8adf8eaff82024d6dcdfaff5e7e0a41c210e138419807af89a74babc10a6d4
3
+ metadata.gz: 58299df4276e04c035c82a7afcf6c012bd5059213d5fcc375ecc2e001900aa9b
4
+ data.tar.gz: 9c7d4d3a80766da72364f2eee2d6909785a70ef9c63f6e1739d46af11bd9e49b
5
5
  SHA512:
6
- metadata.gz: 85493e28f9f323982bffd69c89e2ffeceaed9d284f21776f118e36cfc6b52ce7355e450c37d67212fc2bc135d60925a2bb7287f123892fabc81148fba076e1ec
7
- data.tar.gz: 37a1e25fd2ea272ef88f203f001830729c40102462be05681a3669c38ece703827948f08d901f2ad93092739b546a23b8714dd79452466be49619e72bf3e9fe3
6
+ metadata.gz: 63d21bbd06003cac35e8b12d94fb829bdaf9a95164b948a7059aab745cb49ca8b9f100b7ac27a244a9cd9c4e9c1db6a1c7cb0c279859e6bf56eb75aa846bfd1c
7
+ data.tar.gz: a04360570cf34f82caff342a04a2d46ca55c951c3aa718c1c15d0ff723f79b9b87b56e8e8ec57489a9f4d06a10ec35ad7f1681b9e6695aa393943a97c191fc99
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  Complete, fast and testable actions for Rack
4
4
 
5
+ ## v2.1.0.beta1 - 2023-06-29
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley] Add `Request#session_enabled?` and `Response#session_enabled?` (#423)
10
+
11
+ ## v2.0.2 - 2023-02-01
12
+
13
+ ### Added
14
+
15
+ - [Adam Lassek] Params Pattern Matching
16
+ - [Adam Lassek, Luca Guidi] Allow to `halt` using a `Symbol`: `halt :unauthorized`
17
+ - [Adam Lassek, Luca Guidi] Introduce `Hanami::Action::Response#status=` to accept an `Integer` or a `Symbol`
18
+
19
+ ### Fixed
20
+
21
+ - [Pat Allan] Ensure action accepting the request with a custom MIME Type
22
+ - [Luca Guidi] Halting with an unknown HTTP code will raise a `Hanami::Action::UnknownHttpStatusError`
23
+ - [Luca Guidi] Fix error message for missing format (MIME Type)
24
+
5
25
  ## v2.0.1 - 2022-12-25
6
26
 
7
27
  ### Added
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2021 Luca Guidi
1
+ Copyright © 2014 Hanami Team
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -961,4 +961,4 @@ __Hanami::Controller__ uses [Semantic Versioning 2.0.0](http://semver.org)
961
961
 
962
962
  ## Copyright
963
963
 
964
- Copyright © 2014-2022 Hanami Team – Released under MIT License
964
+ Copyright © 2014 Hanami Team – Released under MIT License
@@ -88,9 +88,9 @@ module Hanami
88
88
  @directives = []
89
89
  values.each do |directive_key|
90
90
  if directive_key.is_a? Hash
91
- directive_key.each { |name, value| self.<< ValueDirective.new(name, value) }
91
+ directive_key.each { |name, value| self << ValueDirective.new(name, value) }
92
92
  else
93
- self.<< NonValueDirective.new(directive_key)
93
+ self << NonValueDirective.new(directive_key)
94
94
  end
95
95
  end
96
96
  end
@@ -9,6 +9,20 @@ module Hanami
9
9
  class Error < ::StandardError
10
10
  end
11
11
 
12
+ # Unknown status HTTP Status error
13
+ #
14
+ # @since 2.0.2
15
+ #
16
+ # @see Hanami::Action::Response#status=
17
+ # @see https://guides.hanamirb.org/v2.0/actions/status-codes/
18
+ class UnknownHttpStatusError < Error
19
+ # @since 2.0.2
20
+ # @api private
21
+ def initialize(code)
22
+ super("unknown HTTP status: `#{code.inspect}'")
23
+ end
24
+ end
25
+
12
26
  # Unknown format error
13
27
  #
14
28
  # This error is raised when a action sets a format that it isn't recognized
@@ -21,14 +35,26 @@ module Hanami
21
35
  # @since 2.0.0
22
36
  # @api private
23
37
  def initialize(format)
24
- msg =
25
- if format.to_s != "" # rubocop:disable Style/NegatedIfElseCondition
26
- "Cannot find a corresponding MIME type for format #{format.inspect}. Configure one via `config.formats.add(#{format}: \"MIME_TYPE_HERE\")`." # rubocop:disable Layout/LineLength
27
- else
28
- "Cannot find a corresponding MIME type for `nil` format."
29
- end
38
+ message = <<~MSG
39
+ Cannot find a corresponding MIME type for format `#{format.inspect}'.
40
+ MSG
41
+
42
+ unless blank?(format)
43
+ message += <<~MSG
44
+
45
+ Configure one via: `config.actions.formats.add(:#{format}, "MIME_TYPE_HERE")' in `config/app.rb' to share between actions of a Hanami app.
46
+
47
+ Or make it available only in the current action: `config.formats.add(:#{format}, "MIME_TYPE_HERE")'.
48
+ MSG
49
+ end
50
+
51
+ super(message)
52
+ end
53
+
54
+ private
30
55
 
31
- super(msg)
56
+ def blank?(format)
57
+ format.to_s.match(/\A[[:space:]]*\z/)
32
58
  end
33
59
  end
34
60
 
@@ -10,8 +10,8 @@ module Hanami
10
10
  # @api private
11
11
  # @since 2.0.0
12
12
  def self.call(status, body = nil)
13
- body ||= Http::Status.message_for(status)
14
- throw :halt, [status, body]
13
+ code, message = Http::Status.for_code(status)
14
+ throw :halt, [code, body || message]
15
15
  end
16
16
  end
17
17
  end
@@ -237,7 +237,7 @@ module Hanami
237
237
  # @api private
238
238
  def accepted_mime_type?(mime_type, config)
239
239
  accepted_mime_types(config).any? { |accepted_mime_type|
240
- ::Rack::Mime.match?(accepted_mime_type, mime_type)
240
+ ::Rack::Mime.match?(mime_type, accepted_mime_type)
241
241
  }
242
242
  end
243
243
 
@@ -243,6 +243,15 @@ module Hanami
243
243
  @params
244
244
  end
245
245
  alias_method :to_hash, :to_h
246
+
247
+ # Pattern-matching support
248
+ #
249
+ # @return [::Hash]
250
+ #
251
+ # @since 2.0.2
252
+ def deconstruct_keys(*)
253
+ to_hash
254
+ end
246
255
  end
247
256
  end
248
257
  end
@@ -29,11 +29,11 @@ module Hanami
29
29
 
30
30
  # @since 2.0.0
31
31
  # @api private
32
- def initialize(env:, params:, sessions_enabled: false)
32
+ def initialize(env:, params:, session_enabled: false)
33
33
  super(env)
34
34
 
35
35
  @params = params
36
- @sessions_enabled = sessions_enabled
36
+ @session_enabled = session_enabled
37
37
  end
38
38
 
39
39
  # Returns the request's ID
@@ -47,18 +47,29 @@ module Hanami
47
47
  @id ||= @env[Action::REQUEST_ID] = SecureRandom.hex(Action::DEFAULT_ID_LENGTH)
48
48
  end
49
49
 
50
+ # Returns true if the session is enabled for the request.
51
+ #
52
+ # @return [Boolean]
53
+ #
54
+ # @api public
55
+ # @since 2.1.0
56
+ def session_enabled?
57
+ @session_enabled
58
+ end
59
+
50
60
  # Returns the session for the request.
51
61
  #
52
62
  # @return [Hash] the session object
53
63
  #
54
- # @raise [MissingSessionError] if sessions are not enabled
64
+ # @raise [MissingSessionError] if the session is not enabled
55
65
  #
66
+ # @see #session_enabled?
56
67
  # @see Response#session
57
68
  #
58
69
  # @since 2.0.0
59
70
  # @api public
60
71
  def session
61
- unless @sessions_enabled
72
+ unless session_enabled?
62
73
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#session")
63
74
  end
64
75
 
@@ -76,7 +87,7 @@ module Hanami
76
87
  # @since 2.0.0
77
88
  # @api public
78
89
  def flash
79
- unless @sessions_enabled
90
+ unless session_enabled?
80
91
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#flash")
81
92
  end
82
93
 
@@ -48,7 +48,7 @@ module Hanami
48
48
 
49
49
  # @since 2.0.0
50
50
  # @api private
51
- def initialize(request:, config:, content_type: nil, env: {}, headers: {}, view_options: nil, sessions_enabled: false) # rubocop:disable Layout/LineLength, Metrics/ParameterLists
51
+ def initialize(request:, config:, content_type: nil, env: {}, headers: {}, view_options: nil, session_enabled: false) # rubocop:disable Layout/LineLength, Metrics/ParameterLists
52
52
  super([], 200, headers.dup)
53
53
  self.content_type = content_type if content_type
54
54
 
@@ -59,7 +59,7 @@ module Hanami
59
59
  @env = env
60
60
  @view_options = view_options || DEFAULT_VIEW_OPTIONS
61
61
 
62
- @sessions_enabled = sessions_enabled
62
+ @session_enabled = session_enabled
63
63
  @sending_file = false
64
64
  end
65
65
 
@@ -81,6 +81,27 @@ module Hanami
81
81
  end
82
82
  end
83
83
 
84
+ # Set the response status
85
+ #
86
+ # @param code [Integer, Symbol] the status code
87
+ #
88
+ # @since 2.0.2
89
+ # @api public
90
+ #
91
+ # @raise [Hanami::Action::UnknownHttpStatusError] if the given code
92
+ # cannot be associated to a known HTTP status
93
+ #
94
+ # @example
95
+ # response.status = :unprocessable_entity
96
+ #
97
+ # @example
98
+ # response.status = 422
99
+ #
100
+ # @see https://guides.hanamirb.org/v2.0/actions/status-codes/
101
+ def status=(code)
102
+ super(Http::Status.lookup(code))
103
+ end
104
+
84
105
  # This is NOT RELEASED with 2.0.0
85
106
  #
86
107
  # @api private
@@ -166,6 +187,16 @@ module Hanami
166
187
  @exposures[key] = value
167
188
  end
168
189
 
190
+ # Returns true if the session is enabled for the request.
191
+ #
192
+ # @return [Boolean]
193
+ #
194
+ # @api public
195
+ # @since 2.1.0
196
+ def session_enabled?
197
+ @session_enabled
198
+ end
199
+
169
200
  # Returns the session for the response.
170
201
  #
171
202
  # This is the same session object as the {Request}.
@@ -179,7 +210,7 @@ module Hanami
179
210
  # @since 2.0.0
180
211
  # @api public
181
212
  def session
182
- unless @sessions_enabled
213
+ unless session_enabled?
183
214
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Response#session")
184
215
  end
185
216
 
@@ -199,7 +230,7 @@ module Hanami
199
230
  # @since 2.0.0
200
231
  # @api public
201
232
  def flash
202
- unless @sessions_enabled
233
+ unless session_enabled?
203
234
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Response#flash")
204
235
  end
205
236
 
@@ -21,7 +21,7 @@ module Hanami
21
21
 
22
22
  private
23
23
 
24
- def sessions_enabled?
24
+ def session_enabled?
25
25
  true
26
26
  end
27
27
 
data/lib/hanami/action.rb CHANGED
@@ -309,7 +309,7 @@ module Hanami
309
309
  request = build_request(
310
310
  env: env,
311
311
  params: params,
312
- sessions_enabled: sessions_enabled?
312
+ session_enabled: session_enabled?
313
313
  )
314
314
  response = build_response(
315
315
  request: request,
@@ -317,7 +317,7 @@ module Hanami
317
317
  content_type: Mime.response_content_type_with_charset(request, config),
318
318
  env: env,
319
319
  headers: config.default_headers,
320
- sessions_enabled: sessions_enabled?
320
+ session_enabled: session_enabled?
321
321
  )
322
322
 
323
323
  enforce_accepted_mime_types(request)
@@ -424,10 +424,10 @@ module Hanami
424
424
  nil
425
425
  end
426
426
 
427
- # @see Session#sessions_enabled?
427
+ # @see Session#session_enabled?
428
428
  # @since 2.0.0
429
429
  # @api private
430
- def sessions_enabled?
430
+ def session_enabled?
431
431
  false
432
432
  end
433
433
 
@@ -8,6 +8,6 @@ module Hanami
8
8
  #
9
9
  # @since 0.1.0
10
10
  # @api public
11
- VERSION = "2.0.1"
11
+ VERSION = "2.1.0.beta1"
12
12
  end
13
13
  end
@@ -17,31 +17,127 @@ module Hanami
17
17
  # @api private
18
18
  ALL = ::Rack::Utils::HTTP_STATUS_CODES
19
19
 
20
+ # Symbolic names for status codes
21
+ #
22
+ # @since 2.0.2
23
+ # @api private
24
+ SYMBOLS = ::Rack::Utils::SYMBOL_TO_STATUS_CODE
25
+
20
26
  # Return a status for the given code
21
27
  #
22
- # @param code [Integer] a valid HTTP code
28
+ # @param code [Integer, Symbol] a valid HTTP code
23
29
  #
24
30
  # @return [Array] a pair of code and message for an HTTP status
25
31
  #
32
+ # @raise [Hanami::Action::UnknownHttpStatusError] if the given code
33
+ # cannot be associated to a known HTTP status
34
+ #
26
35
  # @since 0.1.0
27
36
  # @api private
28
37
  #
29
- # @example
30
- # require 'hanami/http/status'
38
+ # @see https://guides.hanamirb.org/v2.0/actions/status-codes/
39
+ #
40
+ # @example Integer HTTP Status
41
+ # require "hanami/http/status"
42
+ #
43
+ # Hanami::Http::Status.for_code(401)
44
+ # # => [401, "Unauthorized"]
45
+ #
46
+ # @example Symbol HTTP Status
47
+ # require "hanami/http/status"
48
+ #
49
+ # Hanami::Http::Status.for_code(:unauthorized)
50
+ # # => [401, "Unauthorized"]
51
+ #
52
+ # @example Unknown HTTP Status
53
+ # require "hanami/http/status"
31
54
  #
32
- # Hanami::Http::Status.for_code(418) # => [418, "I'm a teapot"]
55
+ # Hanami::Http::Status.for_code(999)
56
+ # # => raise Hanami::Action::UnknownHttpStatusError
57
+ #
58
+ # Hanami::Http::Status.for_code(:foo)
59
+ # # => raise Hanami::Action::UnknownHttpStatusError
33
60
  def self.for_code(code)
34
- ALL.assoc(code)
61
+ case code
62
+ when Integer
63
+ ALL.assoc(code)
64
+ when Symbol
65
+ ALL.assoc(SYMBOLS[code])
66
+ end or raise ::Hanami::Action::UnknownHttpStatusError.new(code)
67
+ end
68
+
69
+ # Return a status code for the given code
70
+ #
71
+ # @param code [Integer,Symbol] a valid HTTP code
72
+ #
73
+ # @return [Integer] a message for the given status code
74
+ #
75
+ # @raise [Hanami::Action::UnknownHttpStatusError] if the given code
76
+ # cannot be associated to a known HTTP status
77
+ #
78
+ # @see https://guides.hanamirb.org/v2.0/actions/status-codes/
79
+ #
80
+ # @since 2.0.2
81
+ # @api private
82
+ #
83
+ # @example Integer HTTP Status
84
+ # require "hanami/http/status"
85
+ #
86
+ # Hanami::Http::Status.lookup(401)
87
+ # # => 401
88
+ #
89
+ # @example Symbol HTTP Status
90
+ # require "hanami/http/status"
91
+ #
92
+ # Hanami::Http::Status.lookup(:unauthorized)
93
+ # # => 401
94
+ #
95
+ # @example Unknown HTTP Status
96
+ # require "hanami/http/status"
97
+ #
98
+ # Hanami::Http::Status.lookup(999)
99
+ # # => raise Hanami::Action::UnknownHttpStatusError
100
+ #
101
+ # Hanami::Http::Status.lookup(:foo)
102
+ # # => raise Hanami::Action::UnknownHttpStatusError
103
+ def self.lookup(code)
104
+ for_code(code)[0]
35
105
  end
36
106
 
37
107
  # Return a message for the given status code
38
108
  #
39
- # @param code [Integer] a valid HTTP code
109
+ # @param code [Integer,Symbol] a valid HTTP code
40
110
  #
41
111
  # @return [String] a message for the given status code
42
112
  #
113
+ # @raise [Hanami::Action::UnknownHttpStatusError] if the given code
114
+ # cannot be associated to a known HTTP status
115
+ #
116
+ # @see https://guides.hanamirb.org/v2.0/actions/status-codes/
117
+ #
43
118
  # @since 0.3.2
44
119
  # @api private
120
+ #
121
+ # @example Integer HTTP Status
122
+ # require "hanami/http/status"
123
+ #
124
+ # Hanami::Http::Status.message_for(401)
125
+ # # => "Unauthorized"
126
+ #
127
+ # @example Symbol HTTP Status
128
+ # require "hanami/http/status"
129
+ #
130
+ # Hanami::Http::Status.message_for(:unauthorized)
131
+ # # => "Unauthorized"
132
+ #
133
+ # @example Unknown HTTP Status
134
+ # require "hanami/http/status"
135
+ #
136
+ # Hanami::Http::Status.message_for(999)
137
+ # # => raise Hanami::Action::UnknownHttpStatusError
138
+ #
139
+ # Hanami::Http::Status.message_for(:foo)
140
+ # # => raise Hanami::Action::UnknownHttpStatusError
45
141
  def self.message_for(code)
46
142
  for_code(code)[1]
47
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-25 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -218,11 +218,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
218
  version: '3.0'
219
219
  required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  requirements:
221
- - - ">="
221
+ - - ">"
222
222
  - !ruby/object:Gem::Version
223
- version: '0'
223
+ version: 1.3.1
224
224
  requirements: []
225
- rubygems_version: 3.4.1
225
+ rubygems_version: 3.4.13
226
226
  signing_key:
227
227
  specification_version: 4
228
228
  summary: Complete, fast and testable actions for Rack and Hanami