hanami-action 3.0.0.rc1 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9b156467d57f721bbaab92d9e6382db78ab4733c2aecb02062785cd7227cd40
4
- data.tar.gz: 1a5baa55a4a80cd089ec9112068c3717584bd3c1a5bc620949409bb4b503025d
3
+ metadata.gz: cfd2248b12d546b250ad80e1c7115aa23dbcfab93eb7620dca331a4939af34f0
4
+ data.tar.gz: aa6a3f85fe8328a8e5d796be22b9d802cff6f74d643a8f1189f8cef89aafc3d8
5
5
  SHA512:
6
- metadata.gz: f6b529f0489f57aca23fb72dba975bd325f4aed512a3b5bc00584e1836af453e52b14df01f98a6b627b042682fd47b856b0228d9efc16c5c85713dd680c5e1ef
7
- data.tar.gz: f2aeb12850e6e8a87d0a7ded31936ff491692c39898c2239483a5e9bf1073dbae2efb637aa9d2cb0ac096a4083097ab56197a7bc0603a6d742c734e6ab8e494d
6
+ metadata.gz: 687db93c36b074e4015349842759091cbbb7fb35dda5f30ca1097cc629a1ee48767a2e3740ae54df491b4aee33e315b81e3e0e09a07b0fc0c37995f44c422a4f
7
+ data.tar.gz: 29676466bb1d6aba7f7724aadc8c4bdc80f04d7c02bcb11414ad507e09fb623e628b75a23892b7fc10876a8141c180e49443cd503f61c26122196b7e89731088
data/CHANGELOG.md CHANGED
@@ -9,26 +9,69 @@ and this project adheres to [Break Versioning](https://www.taoensso.com/break-ve
9
9
 
10
10
  ### Added
11
11
 
12
- - Parse request bodies based on formats config. (@timriley in #500, #503, #511, @cllns in #508)
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ [Unreleased]: https://github.com/hanami/hanami-action/compare/v3.0.0...HEAD
23
+
24
+ ## [3.0.0] - 2026-06-30
25
+
26
+ ### Added
27
+
28
+ - Parse request bodies based on formats config. (@timriley in #500, #503, #511, #519, @cllns in #508)
13
29
 
14
30
  Parsers for multipart form bodies and JSON are included by default. These require `formats.accept :html` and `formats.accept :json` respectively. When no formats are configured, multipart form bodies are parsed if found.
15
31
 
16
32
  Custom parsers may be registered via e.g. `formats.register(:custom, "application/custom", parser: ->(body, env) { ... })` or directly via `formats.body_parsers["application/custom"] = parser`.
17
33
 
18
- Parsed body keys are deeply symbolized. Non-hash bodies are wrapped in `{_: parsed_body}`.
34
+ Parsed body params are symbolized as part of becoming the `Hanami::Action::Params` instance. Non-hash bodies are wrapped in `{"_" => parsed_body}`.
35
+ - Support additional `Cache-Control` directives in `response.cache_control`: `:immutable`, `:must_understand`, `stale_while_revalidate:` and `stale_if_error:`. (@timriley in #522)
19
36
  - Full JRuby support. (@katafrakt in #498)
20
37
 
21
38
  ### Changed
22
39
 
23
- ### Deprecated
40
+ - Renamed gem from hanami-controller to hanami-action. You should now `require "hanami-action"` or `require "hanami/action"`. (@timriley in #507, @cllns in df365b5)
41
+ - Check for the dry-validation gem (instead of hanami-validations, which is now retired) before loading `Action.params` and `Action.contract` support. (@timriley in #505)
42
+ - Raise `ArgumentError` from `response.cache_control` for unknown directives, instead of silently dropping them. (@timriley in #522)
43
+ - Cache the action's resolved configuration as a frozen `Data` snapshot (via dry-configurable's `#to_data`) at initialization, avoiding repeated config lookups on the request hot path for improved memory usage and speed. Required bumping `dry-configurable` to `~> 1.4`. (@cllns in #512)
44
+
45
+ **Possibly breaking:** the action's config is now finalized (frozen) when the action is initialized, so mutating it from instance code is no longer possible. This was only ever an undocumented side-effect of implementation, not a supported pattern.
46
+ - Cut per-request allocations on the `Hanami::Action#call` hot path, roughly halving allocations and increasing throughput ~1.5–2.5x per action invocation. A minimal action drops from 51 to 16 allocations (69% fewer, 2.45x faster); an action with formats negotiating an `Accept` header drops from 95 to 61 allocations (36% fewer, 1.55x faster). (@cllns in #514)
47
+ - Require Ruby 3.3 or newer.
24
48
 
25
49
  ### Removed
26
50
 
27
- ### Fixed
51
+ - Removed deprecated format config methods: `Action.format`, `config.format`, `config.formats.add`, `config.formats.values`. (@timriley in #504)
52
+ - Removed `Hanami::Action::Params.params` and support for defining a contract by subclassing `Hanami::Action::Params`. If you are subclassing `Hanami::Action::Params`, take your params block and move it into a `Dry::Validation::Contract` subclass. Then pass this contract class to `Hanami::Action.params` or `Hanami::Action.contract`. (@timriley in #513)
28
53
 
29
- ### Security
54
+ ```ruby
55
+ # Before
56
+ # class SignupParams < Hanami::Action::Params
57
+ # params do
58
+ # required(:email).filled(:str?)
59
+ # end
60
+ # end
61
+
62
+ # After
63
+ class SignupContract < Dry::Validation::Contract
64
+ params do
65
+ required(:email).filled(:str?)
66
+ end
67
+ end
68
+
69
+ class Signup < Hanami::Action
70
+ params SignupParams
71
+ end
72
+ ```
30
73
 
31
- [Unreleased]: https://github.com/hanami/hanami-action/compare/v3.0.0.rc1...HEAD
74
+ [3.0.0]: https://github.com/hanami/hanami-action/compare/v2.3.2...v3.0.0
32
75
 
33
76
  ## [3.0.0.rc1] - 2026-06-16
34
77
 
@@ -50,7 +93,7 @@ and this project adheres to [Break Versioning](https://www.taoensso.com/break-ve
50
93
  - Cache the action's resolved configuration as a frozen `Data` snapshot (via dry-configurable's `#to_data`) at initialization, avoiding repeated config lookups on the request hot path for improved memory usage and speed. Required bumping `dry-configurable` to `~> 1.4`. (@cllns in #512)
51
94
 
52
95
  **Possibly breaking:** the action's config is now finalized (frozen) when the action is initialized, so mutating it from instance code is no longer possible. This was only ever an undocumented side-effect of implementation, not a supported pattern.
53
- - Cut per-request allocations on the `Hanami::Action#call` hot path, roughly halving allocations and increasing throughput ~1.5–2. per action invocation. A minimal action drops from 51 to 16 allocations (69% fewer, 2.45× faster); an action with formats negotiating an `Accept` header drops from 95 to 61 allocations (36% fewer, 1.55× faster). (@cllns in #514)
96
+ - Cut per-request allocations on the `Hanami::Action#call` hot path, roughly halving allocations and increasing throughput ~1.5–2.5x per action invocation. A minimal action drops from 51 to 16 allocations (69% fewer, 2.45x faster); an action with formats negotiating an `Accept` header drops from 95 to 61 allocations (36% fewer, 1.55x faster). (@cllns in #514)
54
97
  - Require Ruby 3.3 or newer.
55
98
 
56
99
  ### Removed
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rack"
4
- require "hanami/utils/hash"
5
4
 
6
5
  module Hanami
7
6
  class Action
@@ -9,7 +8,7 @@ module Hanami
9
8
  #
10
9
  # @api private
11
10
  module BodyParser
12
- FALLBACK_KEY = :_
11
+ FALLBACK_KEY = "_"
13
12
 
14
13
  class << self
15
14
  # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
@@ -25,7 +24,7 @@ module Hanami
25
24
  if env.key?(ROUTER_PARSED_BODY)
26
25
  parsed = env[ROUTER_PARSED_BODY]
27
26
  env[ACTION_PARSED_BODY] = parsed
28
- env[ACTION_BODY_PARAMS] = symbolize_body(parsed)
27
+ env[ACTION_BODY_PARAMS] = body_params(parsed)
29
28
  return
30
29
  end
31
30
 
@@ -59,7 +58,7 @@ module Hanami
59
58
  parsed = parser.call(body, env)
60
59
 
61
60
  env[ACTION_PARSED_BODY] = parsed
62
- env[ACTION_BODY_PARAMS] = symbolize_body(parsed)
61
+ env[ACTION_BODY_PARAMS] = body_params(parsed)
63
62
  end
64
63
 
65
64
  # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
@@ -83,25 +82,12 @@ module Hanami
83
82
  body
84
83
  end
85
84
 
86
- # Symbolizes the parsed body, wrapping non-hash values in a fallback key.
87
- def symbolize_body(parsed)
88
- if parsed.is_a?(::Hash)
89
- deep_symbolize(parsed)
90
- else
91
- {FALLBACK_KEY => deep_symbolize(parsed)}
92
- end
93
- end
94
-
95
- # Recursively symbolizes hash keys within any structure (arrays or hashes).
96
- def deep_symbolize(value)
97
- case value
98
- when ::Hash
99
- Utils::Hash.deep_symbolize(value)
100
- when ::Array
101
- value.map { deep_symbolize(_1) }
102
- else
103
- value
104
- end
85
+ # Wraps a parsed body into a hash suitable for merging into params.
86
+ #
87
+ # Hash bodies are returned as-is; non-hash bodies (e.g. JSON arrays) are wrapped under
88
+ # {FALLBACK_KEY}. Keys are left as strings. Symbolization happens in {Params}.
89
+ def body_params(parsed)
90
+ parsed.is_a?(::Hash) ? parsed : {FALLBACK_KEY => parsed}
105
91
  end
106
92
  end
107
93
  end
@@ -31,7 +31,7 @@ module Hanami
31
31
  #
32
32
  # @return [Hash{String => #call}]
33
33
  #
34
- # @since x.x.x
34
+ # @since 3.0.0
35
35
  # @api public
36
36
  attr_reader :body_parsers
37
37
 
@@ -235,34 +235,40 @@ module Hanami
235
235
  # @api private
236
236
  RACK_INPUT = ::Rack::RACK_INPUT
237
237
 
238
- # The key that returns a request body parsed by Hanami Action.
238
+ # The key that holds the body parser's verbatim output for the request.
239
239
  #
240
- # This is the canonical key for body parsing.
240
+ # This holds whatever the parser returned, and may be any type (a hash for most bodies, but
241
+ # possibly an array or scalar for JSON bodies). It mirrors the router's {ROUTER_PARSED_BODY} as
242
+ # the faithful representation of the parsed body.
243
+ #
244
+ # For the params-ready form (always a hash, with keys merged into the request params), see
245
+ # {ACTION_BODY_PARAMS}.
241
246
  #
242
- # @since x.x.x
243
247
  # @api private
244
248
  ACTION_PARSED_BODY = "hanami.action.parsed_body"
245
249
 
246
- # The key that returns params from a parsed body by Hanami Action.
250
+ # The key that holds the parsed body normalized into a hash for merging into the request params.
251
+ #
252
+ # Hash bodies keep the string keys sent by the client; these are symbolized later by
253
+ # {Hanami::Action::Params}.. Non-Hash bodies (such as a top-level JSON array) are wrapped under
254
+ # `"_"` so they can still be merged.
247
255
  #
248
- # This is the canonical key for parsed body params.
256
+ # For the parser's verbatim (possibly non-hash) output, see {ACTION_PARSED_BODY}.
249
257
  #
250
- # @since x.x.x
251
258
  # @api private
252
259
  ACTION_BODY_PARAMS = "hanami.action.body_params"
253
260
 
254
261
  # The key that returns a request body parsed by Hanami Router.
255
262
  #
256
- # This is maintained for backward compatibility with Hanami Router.
263
+ # This is maintained for compatibility with Hanami Router's body parser middlware.
257
264
  #
258
265
  # @api private
259
266
  ROUTER_PARSED_BODY = "router.parsed_body"
260
267
 
261
268
  # The key that returns router params from the Rack env.
262
269
  #
263
- # This is maintained for backward compatibility with Hanami Router.
270
+ # This is maintained for compatibility with Hanami Router's body parser middlware.
264
271
  #
265
- # @since 2.0.0
266
272
  # @api private
267
273
  ROUTER_PARAMS = "router.params"
268
274
 
@@ -61,7 +61,7 @@ module Hanami
61
61
  # Error raised when body parsing fails.
62
62
  #
63
63
  # @api public
64
- # @since x.x.x
64
+ # @since 3.0.0
65
65
  class BodyParsingError < Error
66
66
  end
67
67
 
@@ -8,6 +8,6 @@ module Hanami
8
8
  #
9
9
  # @since 3.0.0
10
10
  # @api public
11
- VERSION = "3.0.0.rc1"
11
+ VERSION = "3.0.0"
12
12
  end
13
13
  end
data/lib/hanami/action.rb CHANGED
@@ -288,7 +288,6 @@ module Hanami
288
288
  # exactly the same; Config-specific methods like `#handle_exception` are not available on
289
289
  # instances and must be called on the class config instead.
290
290
  #
291
- # @since x.x.x
292
291
  # @api private
293
292
  private attr_reader :config
294
293
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-action
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  - !ruby/object:Gem::Version
148
148
  version: '0'
149
149
  requirements: []
150
- rubygems_version: 4.0.14
150
+ rubygems_version: 3.6.9
151
151
  specification_version: 4
152
152
  summary: Complete, fast and testable actions for Rack and Hanami
153
153
  test_files: []