hanami-router 2.3.1 → 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: c9a6b9498cdc6f09a3792b52accbe0fda997f5de907fb0e523408a0a8437465c
4
- data.tar.gz: 40fc3193dcd6e471f1464852844456748f1ef8deb53ad630290e1343abdfbbbd
3
+ metadata.gz: 30cf4c77a2d61c1f8c8817c19db6bd5089627a6639dbda3f6b44441433516a67
4
+ data.tar.gz: a79a9f499cbd4746adc14e70dd9aeff68aad669cbdb3109bab7501264e5930ab
5
5
  SHA512:
6
- metadata.gz: b514e367ea3eb3b3be40f89d19b5a00388365b1a39fd0dc5bc98c1f971ff2831a4fcc80c3c463079d4a61773e0375504cfd9afa198aae7d1c42d762fb2e56def
7
- data.tar.gz: ef993a463b78db8deba2a6b6304aeb408961ee6ae89e92e62f8b79e52f662a6c0d7155921aee78c1ddce67055fa218294b09afefb19674d27aa1edb32622c0e8
6
+ metadata.gz: d08ff095875e2e7a24d4b3663344e6aa0cb3de17bd41ed22c809588a361f28bc9f1f1ffd0ccd1933bb35c88b78a330bbfc9a4aa178cd661202657cae56ce6d13
7
+ data.tar.gz: e6ca075b83151a66a015ba99c2120ee45bd35fe338cb4f7feb6d82e772eab60a8116ea4ee4fa90629c8e6e79cd2b17c867630916b9a5c3a0ac3154eabed1be77
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
- # Hanami::Router
1
+ # Changelog
2
2
 
3
- Rack compatible HTTP router for Ruby.
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
4
7
 
5
8
  ## [Unreleased]
6
9
 
@@ -16,7 +19,44 @@ Rack compatible HTTP router for Ruby.
16
19
 
17
20
  ### Security
18
21
 
19
- [Unreleased]: http://github.com/hanami/hanami-router/compare/v2.3.1...main
22
+ [Unreleased]: http://github.com/hanami/hanami-router/compare/v3.0.0...HEAD
23
+
24
+ ## [3.0.0] - 2026-06-30
25
+
26
+ ### Added
27
+
28
+ - Add `#permanent_redirect` and `#temporary_redirect` helpers for 301 and 302 responses. (@cllns in #302)
29
+
30
+ ### Changed
31
+
32
+ - **BREAKING:** `#redirect` now requires an explicit `code:` argument. Use `#permanent_redirect` or `#temporary_redirect` for the common cases, and pass `code:` to `#redirect` for less common codes (e.g. `303`, `307`, `308`). (@cllns in #302)
33
+ - Upgrade mustermann to 3.1 and remove mustermann-contrib dependency. (@rkh in #300)
34
+ - Require Ruby 3.3 or newer.
35
+
36
+ ### Fixed
37
+
38
+ - Only parse the request body into params when the content type is `application/x-www-form-urlencoded`. Previously, with no body parser middleware in use, posting a multipart upload (or other non-form body) could raise `Rack::QueryParser::InvalidParameterError`. (@cllns and @timriley in #305)
39
+ - Allow URL generation (via `#path`) to work with array variables. (@inouire in #304)
40
+
41
+ [3.0.0]: http://github.com/hanami/hanami-router/compare/v2.3.1...v3.0.0
42
+
43
+ ## [3.0.0.rc1] - 2026-06-16
44
+
45
+ ### Added
46
+
47
+ - Add `#permanent_redirect` and `#temporary_redirect` helpers for 301 and 302 responses. (@cllns in #302)
48
+
49
+ ### Changed
50
+
51
+ - **BREAKING:** `#redirect` now requires an explicit `code:` argument. Use `#permanent_redirect` or `#temporary_redirect` for the common cases, and pass `code:` to `#redirect` for less common codes (e.g. `303`, `307`, `308`). (@cllns in #302)
52
+ - Upgrade mustermann to 3.1 and remove mustermann-contrib dependency. (@rkh in #300)
53
+ - Require Ruby 3.3 or newer.
54
+
55
+ ### Fixed
56
+
57
+ - Allow URL generation (via `#path`) to work with array variables. (@inouire in #304)
58
+
59
+ [3.0.0.rc1]: http://github.com/hanami/hanami-router/compare/v2.3.1...v3.0.0.rc1
20
60
 
21
61
  ## [2.3.1] - 2025-12-17
22
62
 
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2026 Hanakai team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,20 +1,14 @@
1
- # Hanami::Router
1
+ <!--- This file is synced from hanakai-rb/repo-sync -->
2
2
 
3
- Rack compatible, lightweight, and fast HTTP Router for Ruby and [Hanami](http://hanamirb.org).
3
+ [actions]: https://github.com/hanami/hanami-router/actions
4
+ [chat]: https://discord.gg/naQApPAsZB
5
+ [forum]: https://discourse.hanamirb.org
6
+ [rubygem]: https://rubygems.org/gems/hanami-router
4
7
 
5
- ## Status
6
-
7
- [![Gem Version](https://badge.fury.io/rb/hanami-router.svg)](https://badge.fury.io/rb/hanami-router)
8
- [![CI](https://github.com/hanami/router/actions/workflows/ci.yml/badge.svg)](https://github.com/hanami/router/actions?query=workflow%3Aci+branch%3Amain)
9
-
10
- ## Contact
11
-
12
- * Home page: http://hanamirb.org
13
- * Mailing List: http://hanamirb.org/mailing-list
14
- * API Doc: http://rubydoc.info/gems/hanami-router
15
- * Bugs/Issues: https://github.com/hanami/router/issues
16
- * Chat: http://chat.hanamirb.org
8
+ # Hanami Router [![Gem Version](https://badge.fury.io/rb/hanami-router.svg)][rubygem] [![CI Status](https://github.com/hanami/hanami-router/workflows/CI/badge.svg)][actions]
17
9
 
10
+ [![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]
11
+ [![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]
18
12
 
19
13
  ## Installation
20
14
 
@@ -73,7 +67,7 @@ Hanami::Router.new do
73
67
  get "/dashboard", to: Dashboard::Index
74
68
  get "/rack-app", to: RackApp.new
75
69
 
76
- redirect "/legacy", to: "/"
70
+ permanent_redirect "/legacy", to: "/"
77
71
 
78
72
  mount Api::App, at: "/api"
79
73
 
@@ -152,9 +146,13 @@ end
152
146
  ```ruby
153
147
  Hanami::Router.new do
154
148
  get "/redirect_destination", to: ->(env) { [200, {}, ["Redirect destination!"]] }
155
- redirect "/legacy", to: "/redirect_destination"
156
- redirect "/learn-more", to: "https://hanamirb.org/"
157
- redirect "/chat", to: URI("xmpp://myapp.net/")
149
+ permanent_redirect "/legacy", to: "/redirect_destination"
150
+ temporary_redirect "/today", to: "/redirect_destination"
151
+ permanent_redirect "/learn-more", to: "https://hanamirb.org/"
152
+ permanent_redirect "/chat", to: URI("xmpp://myapp.net/")
153
+
154
+ # For less common codes (303, 307, 308), use redirect with an explicit code:
155
+ redirect "/submit", to: "/result", code: 303
158
156
  end
159
157
  ```
160
158
 
@@ -341,10 +339,6 @@ route.verb # "POST"
341
339
  route.routable? # => false
342
340
  ```
343
341
 
344
- ## Versioning
345
-
346
- __Hanami::Router__ uses [Semantic Versioning 2.0.0](http://semver.org)
347
-
348
342
  ## Contributing
349
343
 
350
344
  1. Fork this repo to your account and clone it locally (`git clone git@github.com:your-pseudo/your-cloned-repo.git`)
@@ -356,8 +350,15 @@ __Hanami::Router__ uses [Semantic Versioning 2.0.0](http://semver.org)
356
350
  7. Push to the branch (`git push origin my-new-feature`)
357
351
  8. Create new Pull Request on Github with some context on what you're trying to fix or to improve with this contribution
358
352
 
359
- Thank you for contributing!
353
+ Thank you for contributing!
354
+
355
+ ## Links
356
+
357
+ - [User documentation](https://hanamirb.org)
358
+ - [API documentation](http://rubydoc.info/gems/hanami-router)
359
+
360
+
361
+ ## License
360
362
 
361
- ## Copyright
363
+ See `LICENSE` file.
362
364
 
363
- Copyright © 2014–2025 Hanami Team – Released under MIT License
@@ -1,35 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ # This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.
4
+
5
+ lib = File.expand_path("lib", __dir__)
4
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
7
  require "hanami/router/version"
6
8
 
7
9
  Gem::Specification.new do |spec|
8
10
  spec.name = "hanami-router"
9
- spec.version = Hanami::Router::VERSION
10
11
  spec.authors = ["Hanakai team"]
11
12
  spec.email = ["info@hanakai.org"]
12
- spec.description = "Rack compatible HTTP router for Ruby"
13
- spec.summary = "Rack compatible HTTP router for Ruby and Hanami"
14
- spec.homepage = "http://hanamirb.org"
15
13
  spec.license = "MIT"
14
+ spec.version = Hanami::Router::VERSION.dup
16
15
 
17
- spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-router.gemspec`.split($/)
18
- spec.executables = []
16
+ spec.summary = "Rack compatible HTTP router for Ruby and Hanami"
17
+ spec.description = spec.summary
18
+ spec.homepage = "https://hanamirb.org"
19
+ spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "hanami-router.gemspec", "lib/**/*"]
20
+ spec.bindir = "exe"
21
+ spec.executables = Dir["exe/*"].map { |f| File.basename(f) }
19
22
  spec.require_paths = ["lib"]
20
- spec.metadata["rubygems_mfa_required"] = "true"
21
- spec.required_ruby_version = ">= 3.2"
22
23
 
23
- spec.add_dependency "rack", ">= 2.2.16"
24
- spec.add_dependency "mustermann", "~> 3.0"
25
- spec.add_dependency "mustermann-contrib", "~> 3.0"
26
- spec.add_dependency "csv", "~> 3.3"
24
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
27
25
 
28
- spec.add_development_dependency "rake", "~> 13"
29
- spec.add_development_dependency "rack-test", "~> 2.0"
30
- spec.add_development_dependency "rspec", "~> 3.8"
31
- spec.add_development_dependency "ostruct" # Remove once we drop support for Rack 2
26
+ spec.metadata["changelog_uri"] = "https://github.com/hanami/hanami-router/blob/main/CHANGELOG.md"
27
+ spec.metadata["source_code_uri"] = "https://github.com/hanami/hanami-router"
28
+ spec.metadata["bug_tracker_uri"] = "https://github.com/hanami/hanami-router/issues"
29
+ spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
32
30
 
33
- spec.add_development_dependency "rubocop", "~> 1.0"
34
- spec.add_development_dependency "rubocop-performance", "~> 1.0"
31
+ spec.required_ruby_version = ">= 3.3"
32
+
33
+ spec.add_runtime_dependency "rack", ">= 2.2.16"
34
+ spec.add_runtime_dependency "mustermann", "~> 3.1"
35
+ spec.add_runtime_dependency "csv", "~> 3.3"
35
36
  end
37
+
@@ -60,7 +60,7 @@ module Hanami
60
60
  parsers.each_with_object(registry) do |spec, memo|
61
61
  if spec.is_a?(Hash) && spec.size > 1
62
62
  spec.each do |key, value|
63
- build_parsers([key => [value]], memo)
63
+ build_parsers([{key => [value]}], memo)
64
64
  end
65
65
  else
66
66
  name, *media_types = Array(*spec).flatten(0)
@@ -59,7 +59,7 @@ module Hanami
59
59
  # raise Hanami::Middleware::BodyParser::BodyParsingError.new(exception.message)
60
60
  # end
61
61
  # end
62
- def parse(body, env = {}) # rubocop:disable Lint/UnusedMethodArgument
62
+ def parse(body, env = {})
63
63
  raise NoMethodError
64
64
  end
65
65
  end
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Hanami
4
4
  class Router
5
+ # Rack env key containing the request body as parsed by the body parser middleware. Signals that
6
+ # the body has already been parsed, so the router should not attempt to parse it again.
7
+ #
5
8
  # @api private
6
- # @since 2.0.0
7
9
  ROUTER_PARSED_BODY = "router.parsed_body"
8
10
  end
9
11
  end
@@ -63,7 +63,7 @@ module Hanami
63
63
 
64
64
  # @api private
65
65
  # @since 2.0.0
66
- def initialize(http_method:, path:, to:, as: nil, constraints: {}, blk: nil) # rubocop:disable Metrics/ParameterLists
66
+ def initialize(http_method:, path:, to:, as: nil, constraints: {}, blk: nil)
67
67
  @http_method = http_method
68
68
  @path = path
69
69
  @to = to
@@ -6,7 +6,6 @@ require_relative "prefix"
6
6
 
7
7
  module Hanami
8
8
  class Router
9
- # @since 2.0.0
10
9
  # @api private
11
10
  class UrlHelpers
12
11
  # @since 2.0.0
@@ -19,27 +18,40 @@ module Hanami
19
18
  @prefix = Prefix.new(prefix)
20
19
  end
21
20
 
22
- # @since 2.0.0
23
21
  # @api private
24
22
  def add(name, segment)
25
23
  @named[name] = segment
26
24
  end
27
25
 
28
- # @since 2.0.0
29
26
  # @api private
30
27
  def path(name, variables = {})
31
- @named.fetch(name.to_sym) do
32
- raise MissingRouteError.new(name)
33
- end.expand(:append, variables)
28
+ scalar_vars = variables.reject { |_, value| value.is_a?(Array) }
29
+ array_vars = array_query_vars(variables)
30
+
31
+ expanded_path = @named
32
+ .fetch(name.to_sym) { raise MissingRouteError.new(name) }
33
+ .expand(:append, scalar_vars)
34
+
35
+ return expanded_path if array_vars.empty?
36
+
37
+ join_char = expanded_path.include?("?") ? "&" : "?"
38
+ "#{expanded_path}#{join_char}#{Rack::Utils.build_query(array_vars)}"
34
39
  rescue Mustermann::ExpandError => exception
35
40
  raise InvalidRouteExpansionError.new(name, exception.message)
36
41
  end
37
42
 
38
- # @since 2.0.0
39
43
  # @api private
40
44
  def url(name, variables = {})
41
45
  @base_url + @prefix.join(path(name, variables)).to_s
42
46
  end
47
+
48
+ private
49
+
50
+ def array_query_vars(variables = {})
51
+ variables
52
+ .select { |_, value| value.is_a?(Array) }
53
+ .to_h { |key, value| ["#{key}[]", value] }
54
+ end
43
55
  end
44
56
  end
45
57
  end
@@ -6,8 +6,7 @@ module Hanami
6
6
  #
7
7
  # @return [String]
8
8
  #
9
- # @since 0.1.0
10
9
  # @api public
11
- VERSION = "2.3.1"
10
+ VERSION = "3.0.0"
12
11
  end
13
12
  end
data/lib/hanami/router.rb CHANGED
@@ -113,9 +113,7 @@ module Hanami
113
113
  env[::Rack::RACK_INPUT] = Rack::RewindableInput.new(input)
114
114
  end
115
115
 
116
- endpoint.call(
117
- _params(env, params)
118
- ).to_a
116
+ endpoint.call(_env_with_params(env, params)).to_a
119
117
  end
120
118
 
121
119
  # Defines a named root route (a GET route for "/")
@@ -380,22 +378,70 @@ module Hanami
380
378
 
381
379
  # Defines a route that redirects the incoming request to another path.
382
380
  #
381
+ # `code:` is required. For the common cases, prefer {#permanent_redirect} (301)
382
+ # or {#temporary_redirect} (302). Use this method when you need a less common
383
+ # redirect code such as 303 See Other, 307 Temporary Redirect, or 308 Permanent Redirect.
384
+ #
383
385
  # @param path [String] the relative URL to be matched
384
386
  # @param to [#call] the Rack endpoint
385
387
  # @param as [Symbol, Array<Symbol>] a unique name for the route, or a ["prefix", "name"] array,
386
388
  # to add a prefix to the name when nested within scopes.
387
- # @param code [Integer] a HTTP status code to use for the redirect
389
+ # @param code [Integer] the HTTP status code to use for the redirect (e.g. 303, 307, 308)
388
390
  #
389
391
  # @raise [Hanami::Router::UnknownHTTPStatusCodeError] when an unknown redirect code is given
390
392
  #
391
393
  # @since 0.1.0
392
394
  #
393
- # @see #get
394
- # @see #initialize
395
- def redirect(path, to: nil, as: nil, code: DEFAULT_REDIRECT_CODE)
395
+ # @see #redirect_permanent
396
+ # @see #redirect_temporary
397
+ def redirect(path, code:, to: nil, as: nil)
396
398
  get(path, to: _redirect(to, code), as: as)
397
399
  end
398
400
 
401
+ # Defines a route that permanently redirects the incoming request to another path.
402
+ #
403
+ # Issues a 301 Moved Permanently response, indicating that the resource has moved to
404
+ # a new location and all future requests should use the new URL.
405
+ #
406
+ # NOTE: Browsers cache permanent redirects aggressively. Once a client has followed
407
+ # a 301, it may not re-request the original URL, making the redirect hard to undo
408
+ # without clearing the browser cache. Prefer {#redirect_temporary} when in doubt.
409
+ #
410
+ # @param path [String] the relative URL to be matched
411
+ # @param to [#call] the Rack endpoint
412
+ # @param as [Symbol, Array<Symbol>] a unique name for the route, or a ["prefix", "name"] array,
413
+ # to add a prefix to the name when nested within scopes.
414
+ #
415
+ # @raise [Hanami::Router::UnknownHTTPStatusCodeError] when an unknown redirect code is given
416
+ #
417
+ # @since 3.0.0
418
+ #
419
+ # @see #redirect
420
+ # @see #redirect_temporary
421
+ def redirect_permanent(path, to: nil, as: nil)
422
+ get(path, to: _redirect(to, PERMANENT_REDIRECT_CODE), as: as)
423
+ end
424
+
425
+ # Defines a route that temporarily redirects the incoming request to another path.
426
+ #
427
+ # Issues a 302 Found response, indicating that the resource is temporarily available
428
+ # at a different URL and future requests should continue to use the original URL.
429
+ #
430
+ # @param path [String] the relative URL to be matched
431
+ # @param to [#call] the Rack endpoint
432
+ # @param as [Symbol, Array<Symbol>] a unique name for the route, or a ["prefix", "name"] array,
433
+ # to add a prefix to the name when nested within scopes.
434
+ #
435
+ # @raise [Hanami::Router::UnknownHTTPStatusCodeError] when an unknown redirect code is given
436
+ #
437
+ # @since 3.0.0
438
+ #
439
+ # @see #redirect
440
+ # @see #redirect_permanent
441
+ def redirect_temporary(path, to: nil, as: nil)
442
+ get(path, to: _redirect(to, TEMPORARY_REDIRECT_CODE), as: as)
443
+ end
444
+
399
445
  # Defines a routing scope. Routes defined in the context of a scope,
400
446
  # inherit the given path as path prefix and as a named routes prefix.
401
447
  #
@@ -636,7 +682,7 @@ module Hanami
636
682
  env = env_for(env, params, options)
637
683
  endpoint, params = lookup(env)
638
684
 
639
- RecognizedRoute.new(endpoint, _params(env, params))
685
+ RecognizedRoute.new(endpoint, _env_with_params(env, params))
640
686
  end
641
687
 
642
688
  # @since 2.0.0
@@ -729,7 +775,6 @@ module Hanami
729
775
  # @api private
730
776
  PREFIXED_NAME_SEPARATOR = "_"
731
777
 
732
- # @since x.x.x
733
778
  # @api private
734
779
  UNDERSCORED_NAME_REGEXP = /[-+~.]/
735
780
 
@@ -741,13 +786,20 @@ module Hanami
741
786
  # @api private
742
787
  EMPTY_STRING = ""
743
788
 
789
+ # @api private
790
+ EMPTY_HASH = {}.freeze
791
+
744
792
  # @since 2.0.0
745
793
  # @api private
746
794
  DEFAULT_RESOLVER = ->(_, to) { to }
747
795
 
748
- # @since 2.0.0
796
+ # @since 3.0.0
749
797
  # @api private
750
- DEFAULT_REDIRECT_CODE = 301
798
+ PERMANENT_REDIRECT_CODE = 301
799
+
800
+ # @since 3.0.0
801
+ # @api private
802
+ TEMPORARY_REDIRECT_CODE = 302
751
803
 
752
804
  # @since 2.0.0
753
805
  # @api private
@@ -789,6 +841,15 @@ module Hanami
789
841
  # @api private
790
842
  PARAMS = "router.params"
791
843
 
844
+ # @api private
845
+ CONTENT_TYPE = "CONTENT_TYPE"
846
+
847
+ # @api private
848
+ FORM_URLENCODED_MEDIA_TYPE = "application/x-www-form-urlencoded"
849
+
850
+ # @api private
851
+ FORM_URLENCODED_MEDIA_TYPE_PREFIX = "#{FORM_URLENCODED_MEDIA_TYPE};".freeze
852
+
792
853
  # @since 2.0.0
793
854
  # @api private
794
855
  ROUTE_VARIABLE_MATCHER = /:/
@@ -962,7 +1023,7 @@ module Hanami
962
1023
  inspector: @inspector
963
1024
  }
964
1025
 
965
- self.class.new(**options.merge(new_options), &(blk || @blk))
1026
+ self.class.new(**options.merge(new_options), &blk || @blk)
966
1027
  end
967
1028
 
968
1029
  # @since 2.0.0
@@ -982,17 +1043,12 @@ module Hanami
982
1043
  Redirect.new(destination, code, ->(*) { [code, {HTTP_HEADER_LOCATION => destination}, [body]] })
983
1044
  end
984
1045
 
985
- # @since 2.0.0
986
1046
  # @api private
987
- def _params(env, params)
1047
+ def _env_with_params(env, params)
988
1048
  params ||= {}
989
1049
  env[PARAMS] ||= {}
990
1050
 
991
- if !env.key?(ROUTER_PARSED_BODY) && (input = env[::Rack::RACK_INPUT]) and input.rewind
992
- env[PARAMS].merge!(::Rack::Utils.parse_nested_query(input.read))
993
- input.rewind
994
- end
995
-
1051
+ env[PARAMS].merge!(_form_urlencoded_body(env))
996
1052
  env[PARAMS].merge!(::Rack::Utils.parse_nested_query(env[::Rack::QUERY_STRING]))
997
1053
  env[PARAMS].merge!(params)
998
1054
  env[PARAMS] = Params.deep_symbolize(env[PARAMS])
@@ -1000,6 +1056,28 @@ module Hanami
1000
1056
  env
1001
1057
  end
1002
1058
 
1059
+ # @api private
1060
+ def _form_urlencoded_body(env)
1061
+ return EMPTY_HASH if env.key?(ROUTER_PARSED_BODY)
1062
+ return EMPTY_HASH unless _form_urlencoded?(env)
1063
+ return EMPTY_HASH unless (input = env[::Rack::RACK_INPUT])
1064
+
1065
+ input.rewind
1066
+ body = ::Rack::Utils.parse_nested_query(input.read)
1067
+ input.rewind # leave the stream readable for downstream consumers
1068
+ body
1069
+ end
1070
+
1071
+ # @api private
1072
+ def _form_urlencoded?(env)
1073
+ content_type = env[CONTENT_TYPE]
1074
+ return false unless content_type
1075
+
1076
+ content_type = content_type.downcase
1077
+ content_type == FORM_URLENCODED_MEDIA_TYPE ||
1078
+ content_type.start_with?(FORM_URLENCODED_MEDIA_TYPE_PREFIX)
1079
+ end
1080
+
1003
1081
  # @since 2.0.0
1004
1082
  # @api private
1005
1083
  def _not_allowed_fixed(env)
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-router
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team
8
- bindir: bin
8
+ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -29,28 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '3.0'
32
+ version: '3.1'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '3.0'
40
- - !ruby/object:Gem::Dependency
41
- name: mustermann-contrib
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '3.0'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '3.0'
39
+ version: '3.1'
54
40
  - !ruby/object:Gem::Dependency
55
41
  name: csv
56
42
  requirement: !ruby/object:Gem::Requirement
@@ -65,99 +51,18 @@ dependencies:
65
51
  - - "~>"
66
52
  - !ruby/object:Gem::Version
67
53
  version: '3.3'
68
- - !ruby/object:Gem::Dependency
69
- name: rake
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '13'
75
- type: :development
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '13'
82
- - !ruby/object:Gem::Dependency
83
- name: rack-test
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '2.0'
89
- type: :development
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '2.0'
96
- - !ruby/object:Gem::Dependency
97
- name: rspec
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '3.8'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '3.8'
110
- - !ruby/object:Gem::Dependency
111
- name: ostruct
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- version: '0'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: '0'
124
- - !ruby/object:Gem::Dependency
125
- name: rubocop
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: '1.0'
131
- type: :development
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: '1.0'
138
- - !ruby/object:Gem::Dependency
139
- name: rubocop-performance
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - "~>"
143
- - !ruby/object:Gem::Version
144
- version: '1.0'
145
- type: :development
146
- prerelease: false
147
- version_requirements: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - "~>"
150
- - !ruby/object:Gem::Version
151
- version: '1.0'
152
- description: Rack compatible HTTP router for Ruby
54
+ description: Rack compatible HTTP router for Ruby and Hanami
153
55
  email:
154
56
  - info@hanakai.org
155
57
  executables: []
156
58
  extensions: []
157
- extra_rdoc_files: []
59
+ extra_rdoc_files:
60
+ - CHANGELOG.md
61
+ - LICENSE
62
+ - README.md
158
63
  files:
159
64
  - CHANGELOG.md
160
- - LICENSE.md
65
+ - LICENSE
161
66
  - README.md
162
67
  - hanami-router.gemspec
163
68
  - lib/hanami/middleware/app.rb
@@ -191,11 +96,14 @@ files:
191
96
  - lib/hanami/router/trie.rb
192
97
  - lib/hanami/router/url_helpers.rb
193
98
  - lib/hanami/router/version.rb
194
- homepage: http://hanamirb.org
99
+ homepage: https://hanamirb.org
195
100
  licenses:
196
101
  - MIT
197
102
  metadata:
198
- rubygems_mfa_required: 'true'
103
+ changelog_uri: https://github.com/hanami/hanami-router/blob/main/CHANGELOG.md
104
+ source_code_uri: https://github.com/hanami/hanami-router
105
+ bug_tracker_uri: https://github.com/hanami/hanami-router/issues
106
+ funding_uri: https://github.com/sponsors/hanami
199
107
  rdoc_options: []
200
108
  require_paths:
201
109
  - lib
@@ -203,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
203
111
  requirements:
204
112
  - - ">="
205
113
  - !ruby/object:Gem::Version
206
- version: '3.2'
114
+ version: '3.3'
207
115
  required_rubygems_version: !ruby/object:Gem::Requirement
208
116
  requirements:
209
117
  - - ">="
data/LICENSE.md DELETED
@@ -1,22 +0,0 @@
1
- Copyright © 2014 Hanami Team
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.