hanami 2.3.0.beta2 → 2.3.1

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: d2b1e7bd746a82ee41c5240dff465f74f79c783ebd9ed73c21b41144dff2a641
4
- data.tar.gz: d0b26e86ba4736cdd2841abf353ad58d3064f381a6e45adb615c4d8c28ca7c95
3
+ metadata.gz: 862a6568aecd91ac9c08383fd35826f21d4aba18d149d10f386b4c9513f7a3d4
4
+ data.tar.gz: 0d37ae7c307c1b75e57492f7b5da6ca5e64cadf58bfb6018523dc98659d5fb50
5
5
  SHA512:
6
- metadata.gz: 35f0d90cf493960b018734f68aa210b362195d1efbca45308efa8c877f9ec6220b37a1cd8a753034d3a4e27a623de7d40bd8d02b0786b140b5dd0fda631de246
7
- data.tar.gz: 735d731e95a0edc4858e8d1930e10540664f25ed3f9069bda184570e9056800f83cc6f2b3ac0703e45e261d33e163e9cb55c80c76b1dc95be074901b691a261a
6
+ metadata.gz: 54539db976334d21d79d64c7f7bd48f033f28c438bf62414aa7061bb9cc17a1d6836d581668aab53b2e8d39256037a78dd92a5e3c1c75f2c0a0fe342516ae575
7
+ data.tar.gz: 03a1a49ccd827c564b542bc20c816b89d785dfb93a4a0274786449df3d8a3696913bc27e54ea66d49aeccbd659dac742adf2367d89e0dd90a0be804c36e022fa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Hanami
2
2
 
3
+ A flexible framework for maintainable Ruby apps.
4
+
5
+ A complete Hanami app is composed of multiple gems. For a complete overview of changes, see also these CHANGELOGs:
6
+
7
+ [Assets][assets], [Assets JS][assets-js], [CLI][cli],
8
+ [Controller][controller], [DB][db], [RSpec][rspec],
9
+ [Reloader][reloader], [Router][router], [Utils][utils],
10
+ [Validations][validations], [View][view], [Webconsole][webconsole]
11
+
12
+ [assets]: https://github.com/hanami/hanami-assets/blob/main/CHANGELOG.md
13
+ [assets-js]: https://github.com/hanami/hanami-assets-js/blob/main/CHANGELOG.md
14
+ [cli]: https://github.com/hanami/hanami-cli/blob/main/CHANGELOG.md
15
+ [controller]: https://github.com/hanami/hanami-controller/blob/main/CHANGELOG.md
16
+ [db]: https://github.com/hanami/hanami-db/blob/main/CHANGELOG.md
17
+ [rspec]: https://github.com/hanami/hanami-rspec/blob/main/CHANGELOG.md
18
+ [reloader]: https://github.com/hanami/hanami-reloader/blob/main/CHANGELOG.md
19
+ [router]: https://github.com/hanami/hanami-router/blob/main/CHANGELOG.md
20
+ [utils]: https://github.com/hanami/hanami-utils/blob/main/CHANGELOG.md
21
+ [validations]: https://github.com/hanami/hanami-validations/blob/main/CHANGELOG.md
22
+ [view]: https://github.com/hanami/hanami-view/blob/main/CHANGELOG.md
23
+ [webconsole]: https://github.com/hanami/hanami-webconsole/blob/main/CHANGELOG.md
24
+
3
25
  ## [Unreleased]
4
26
 
5
27
  ### Added
@@ -14,6 +36,52 @@
14
36
 
15
37
  ### Security
16
38
 
39
+ ## [v2.3.1] - 2025-11-14
40
+
41
+ ### Fixed
42
+
43
+ - Fix a circular require warning when loading router extensions. (@timriley in #1556)
44
+
45
+ ## [v2.3.0] - 2025-11-12
46
+
47
+ ### Added
48
+
49
+ - Add `resources` and `resource` methods to the routes DSL. (@afomera and @timriley in #1542 and #1548)
50
+
51
+ ```ruby
52
+ resources :users
53
+ # Generates:
54
+ # GET /users users.index
55
+ # GET /users/new users.new
56
+ # POST /users users.create
57
+ # GET /users/:id users.show
58
+ # GET /users/:id/edit users.edit
59
+ # PATCH /users/:id users.update
60
+ # DELETE /users/:id users.destroy
61
+
62
+ resource :profile
63
+ # Generates (singular, no index):
64
+ # GET /profile/new profile.new
65
+ # POST /profile profile.create
66
+ # GET /profile profile.show
67
+ # GET /profile/edit profile.edit
68
+ # PATCH /profile profile.update
69
+ # DELETE /profile profile.destroy
70
+ ```
71
+
72
+ ### Changed
73
+
74
+ - Enable body parsing middleware by default. (@timriley in #1549)
75
+
76
+ This will parse multipart form upload bodies in requests with content type of `multipart/form-data`, and JSON bodies in requests with content types of `application/json` or `application/vnd.api+json`.
77
+ - For standard logging, use block-based API to provide log payloads, so that log payloads are not generated if the log severity is less than the configured log level. (@p8 in #1550)
78
+
79
+ ### Fixed
80
+
81
+ - Avoid errors when eagerloading Zeitwerk (or when running `bin/rails zeitwerk:check` if your Hanami app is embedded within Rails) by skipping autoloading for extension files that may depend on non-installed gems. (@timriley in #1498)
82
+ - Only extend `Dry::Operation` for Hanami’s database layer when the hanami-db gem is bundled. (@timriley in #1490)
83
+ - Address deprecation warnings from previous usage of `JSON.fast_generate`. (@krzykamil in #1546)
84
+
17
85
  ## [v2.3.0.beta1] - 2025-10-17
18
86
 
19
87
  ### Changed
@@ -1523,6 +1591,8 @@ end
1523
1591
  - [Luca Guidi] Official support for MRI 2.0
1524
1592
 
1525
1593
 
1526
- [unreleased]: https://github.com/hanami/hanami/compare/v2.3.0.beta2...HEAD
1527
- [v2.3.0.beta2] https://github.com/hanami/hanami/compare/v2.3.0.beta1...v2.3.0.beta2
1528
- [v2.3.0.beta1] https://github.com/hanami/hanami/compare/v2.2.1...v2.3.0.beta1
1594
+ [unreleased]: https://github.com/hanami/hanami/compare/v2.3.1...HEAD
1595
+ [v2.3.1]: https://github.com/hanami/hanami/compare/v2.3.0...v2.3.1
1596
+ [v2.3.0]: https://github.com/hanami/hanami/compare/v2.3.0.beta2...v2.3.0
1597
+ [v2.3.0.beta2]: https://github.com/hanami/hanami/compare/v2.3.0.beta1...v2.3.0.beta2
1598
+ [v2.3.0.beta1]: https://github.com/hanami/hanami/compare/v2.2.1...v2.3.0.beta1
data/README.md CHANGED
@@ -21,8 +21,6 @@ These components are designed to be used independently or together in a Hanami a
21
21
 
22
22
  ## Installation
23
23
 
24
- Hanami supports Ruby (MRI) 3.1+.
25
-
26
24
  ```shell
27
25
  gem install hanami
28
26
  ```
@@ -95,7 +93,7 @@ $ bundle exec rspec path/to/spec.rb
95
93
 
96
94
  ### Development Requirements
97
95
 
98
- * Ruby >= 3.1
96
+ * Ruby >= 3.2
99
97
  * Bundler
100
98
  * Node.js
101
99
 
data/hanami.gemspec CHANGED
@@ -37,9 +37,9 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency "dry-inflector", "~> 1.0", ">= 1.1.0", "< 2"
38
38
  spec.add_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
39
39
  spec.add_dependency "dry-system", "~> 1.1"
40
- spec.add_dependency "dry-logger", "~> 1.0", "< 2"
41
- spec.add_dependency "hanami-cli", "~> 2.3.0.beta2"
42
- spec.add_dependency "hanami-utils", "~> 2.3.0.beta2"
40
+ spec.add_dependency "dry-logger", "~> 1.2", "< 2"
41
+ spec.add_dependency "hanami-cli", ">= 2.3.1"
42
+ spec.add_dependency "hanami-utils", ">= 2.3.0"
43
43
  spec.add_dependency "json", ">= 2.7.2"
44
44
  spec.add_dependency "zeitwerk", "~> 2.6"
45
45
  spec.add_dependency "rack-session"
@@ -101,7 +101,7 @@ module Hanami
101
101
  # @return [Boolean]
102
102
  #
103
103
  # @api public
104
- # @since x.x.x
104
+ # @since 2.3.0
105
105
  def nonce?
106
106
  @policy.any? { _2.match?(/'nonce'/) }
107
107
  end
@@ -112,7 +112,7 @@ module Hanami
112
112
  # @return [Array<(Symbol, Array)>]
113
113
  #
114
114
  # @api public
115
- # @since x.x.x
115
+ # @since 2.3.0
116
116
  def middleware
117
117
  return [] unless nonce?
118
118
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/configurable"
4
+ require "hanami/action"
4
5
 
5
6
  module Hanami
6
7
  class Config
@@ -88,7 +89,7 @@ module Hanami
88
89
  # @return [Proc]
89
90
  #
90
91
  # @api public
91
- # @since x.x.x
92
+ # @since 2.3.0
92
93
  setting :content_security_policy_nonce_generator, default: -> { SecureRandom.urlsafe_base64(16) }
93
94
 
94
95
  # @!attribute [rw] method_override
@@ -156,7 +157,7 @@ module Hanami
156
157
  end
157
158
 
158
159
  # @api public
159
- # @since x.x.x
160
+ # @since 2.3.0
160
161
  def content_security_policy? = !!@content_security_policy
161
162
 
162
163
  private
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/configurable"
4
+ require_relative "../slice/routing/resolver"
4
5
 
5
6
  module Hanami
6
7
  class Config
data/lib/hanami/config.rb CHANGED
@@ -320,7 +320,6 @@ module Hanami
320
320
  self.render_detailed_errors = (env == :development)
321
321
  load_from_env
322
322
 
323
-
324
323
  @actions = load_dependent_config("hanami-controller") {
325
324
  require_relative "config/actions"
326
325
  Actions.new
@@ -336,6 +335,7 @@ module Hanami
336
335
  @logger = Config::Logger.new(env: env, app_name: app_name)
337
336
 
338
337
  @middleware = load_dependent_config("hanami-router") {
338
+ require_relative "slice/routing/middleware/stack"
339
339
  Slice::Routing::Middleware::Stack.new
340
340
  }
341
341
 
@@ -484,24 +484,16 @@ module Hanami
484
484
  self.slices = ENV["HANAMI_SLICES"]&.split(",")&.map(&:strip)
485
485
  end
486
486
 
487
- SUPPORTED_MIDDLEWARE_PARSERS = %i[json].freeze
488
- private_constant :SUPPORTED_MIDDLEWARE_PARSERS
487
+ DEFAULT_MIDDLEWARE_PARSERS = {
488
+ form: ["multipart/form-data"],
489
+ json: ["application/json", "application/vnd.api+json"]
490
+ }.freeze
491
+ private_constant :DEFAULT_MIDDLEWARE_PARSERS
489
492
 
490
493
  def use_body_parser_middleware
491
- return unless Hanami.bundled?("hanami-controller")
492
-
493
- return if actions.formats.empty?
494
- return if middleware.stack["/"].map(&:first).any? { |klass| klass == "Hanami::Middleware::BodyParser" }
495
-
496
- parsers = SUPPORTED_MIDDLEWARE_PARSERS & actions.formats.accepted
497
- return if parsers.empty?
494
+ return unless Hanami.bundled?("hanami-router") && Hanami.bundled?("hanami-controller")
498
495
 
499
- middleware.use(
500
- :body_parser,
501
- [parsers.to_h { |parser_format|
502
- [parser_format, actions.formats.mime_types_for(parser_format)]
503
- }]
504
- )
496
+ middleware.use(:body_parser, [DEFAULT_MIDDLEWARE_PARSERS])
505
497
  end
506
498
 
507
499
  def load_dependent_config(gem_name)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "hanami/action"
4
+ require_relative "action/slice_configured_action"
4
5
 
5
6
  module Hanami
6
7
  # @api private
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Extensions
5
+ module Operation
6
+ # Extends operations to support the database.
7
+ #
8
+ # Add an initializer accepting a `rom:` dependency, which is supplied automatically from the
9
+ # `"db.rom"` component in the operation's slice.
10
+ #
11
+ # @api private
12
+ class SliceConfiguredDBOperation < Module
13
+ attr_reader :slice
14
+
15
+ def initialize(slice)
16
+ super()
17
+ @slice = slice
18
+ end
19
+
20
+ def extended(operation_class)
21
+ require "dry/operation/extensions/rom"
22
+ operation_class.include Dry::Operation::Extensions::ROM
23
+
24
+ operation_class.include InstanceMethods
25
+ operation_class.include SliceInstanceMethods.new(slice)
26
+ define_new
27
+ end
28
+
29
+ def inspect
30
+ "#<#{self.class.name}[#{slice.name}>"
31
+ end
32
+
33
+ private
34
+
35
+ def define_new
36
+ resolve_rom = method(:resolve_rom)
37
+
38
+ define_method(:new) do |**kwargs|
39
+ super(
40
+ **kwargs,
41
+ rom: kwargs.fetch(:rom) { resolve_rom.() },
42
+ )
43
+ end
44
+ end
45
+
46
+ def resolve_rom
47
+ slice["db.rom"] if slice.key?("db.rom")
48
+ end
49
+
50
+ module InstanceMethods
51
+ attr_reader :rom
52
+
53
+ def initialize(rom:, **)
54
+ @rom = rom
55
+ end
56
+ end
57
+
58
+ class SliceInstanceMethods < Module
59
+ attr_reader :slice
60
+
61
+ def initialize(slice)
62
+ @slice = slice
63
+ end
64
+
65
+ def included(operation_class)
66
+ define_transaction
67
+ end
68
+
69
+ private
70
+
71
+ def define_transaction
72
+ slice = self.slice
73
+ define_method(:transaction) do |**kwargs, &block|
74
+ unless rom
75
+ msg = <<~TEXT.strip
76
+ A configured db for #{slice} is required to run transactions.
77
+ TEXT
78
+ raise Hanami::ComponentLoadError, msg
79
+ end
80
+
81
+ super(**kwargs, &block)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -11,38 +11,23 @@ module Hanami
11
11
  # @api public
12
12
  # @since 2.2.0
13
13
  module Operation
14
+ require_relative "operation/slice_configured_db_operation"
15
+
14
16
  # @api private
15
- # @since 2.2.0
16
- def self.included(operation_class)
17
+ def self.extended(operation_class)
17
18
  super
18
19
 
19
20
  operation_class.extend(Hanami::SliceConfigurable)
20
- operation_class.extend(ClassMethods)
21
21
  end
22
22
 
23
- # @api private
24
- # @since 2.2.0
25
- module ClassMethods
26
- # @api private
27
- # @since 2.2.0
28
- def configure_for_slice(slice)
29
- include slice.namespace::Deps["db.rom"]
30
- end
31
-
32
- # @api private
33
- # @since 2.2.0
34
- def inherited(subclass)
35
- super
23
+ # private
36
24
 
37
- return unless subclass.superclass == self
38
- return unless Hanami.bundled?("hanami-db")
39
-
40
- require "dry/operation/extensions/rom"
41
- subclass.include Dry::Operation::Extensions::ROM
42
- end
25
+ # @api private
26
+ def configure_for_slice(slice)
27
+ extend SliceConfiguredDBOperation.new(slice) if Hanami.bundled?("hanami-db")
43
28
  end
44
29
  end
45
30
  end
46
31
  end
47
32
 
48
- Dry::Operation.include(Hanami::Extensions::Operation)
33
+ Dry::Operation.extend(Hanami::Extensions::Operation)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../../errors"
4
+ require_relative "slice_configured_context"
4
5
 
5
6
  module Hanami
6
7
  module Extensions
@@ -167,7 +168,7 @@ module Hanami
167
168
  # @return [Boolean]
168
169
  #
169
170
  # @api public
170
- # @since x.x.x
171
+ # @since 2.3.0
171
172
  def request?
172
173
  !!@request
173
174
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "standard_helpers"
4
+ require_relative "slice_configured_part"
5
+
3
6
  module Hanami
4
7
  module Extensions
5
8
  module View
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "slice_configured_helpers"
4
+ require_relative "standard_helpers"
5
+
3
6
  module Hanami
4
7
  module Extensions
5
8
  module View
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "hanami/view"
4
+ require_relative "view/slice_configured_view"
4
5
 
5
6
  module Hanami
6
7
  # @api private
@@ -710,7 +710,7 @@ module Hanami
710
710
  #
711
711
  # @return [String, nil] nonce value of the current request
712
712
  #
713
- # @since x.x.x
713
+ # @since 2.3.0
714
714
  #
715
715
  # @example App configuration
716
716
  #
@@ -766,7 +766,7 @@ module Hanami
766
766
  _context.assets.crossorigin?(source)
767
767
  end
768
768
 
769
- # @since x.x.x
769
+ # @since 2.3.0
770
770
  # @api private
771
771
  def _nonce(source, nonce_option)
772
772
  if nonce_option == false
@@ -14,16 +14,16 @@ module Hanami
14
14
  # @see Hanami::Middleware::ContentSecurityPolicyNonce
15
15
  #
16
16
  # @api private
17
- # @since x.x.x
17
+ # @since 2.3.0
18
18
  class ContentSecurityPolicyNonce
19
19
  # @api private
20
- # @since x.x.x
20
+ # @since 2.3.0
21
21
  def initialize(app)
22
22
  @app = app
23
23
  end
24
24
 
25
25
  # @api private
26
- # @since x.x.x
26
+ # @since 2.3.0
27
27
  def call(env)
28
28
  return @app.call(env) unless Hanami.app.config.actions.content_security_policy?
29
29
 
data/lib/hanami/routes.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "constants"
4
4
  require_relative "errors"
5
+ require_relative "slice/router"
5
6
 
6
7
  module Hanami
7
8
  # App routes