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 +4 -4
- data/CHANGELOG.md +43 -3
- data/LICENSE +20 -0
- data/README.md +26 -25
- data/hanami-router.gemspec +21 -19
- data/lib/hanami/middleware/body_parser/class_interface.rb +1 -1
- data/lib/hanami/middleware/body_parser/parser.rb +1 -1
- data/lib/hanami/router/constants.rb +3 -1
- data/lib/hanami/router/route.rb +1 -1
- data/lib/hanami/router/url_helpers.rb +19 -7
- data/lib/hanami/router/version.rb +1 -2
- data/lib/hanami/router.rb +97 -19
- metadata +16 -108
- data/LICENSE.md +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30cf4c77a2d61c1f8c8817c19db6bd5089627a6639dbda3f6b44441433516a67
|
|
4
|
+
data.tar.gz: a79a9f499cbd4746adc14e70dd9aeff68aad669cbdb3109bab7501264e5930ab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d08ff095875e2e7a24d4b3663344e6aa0cb3de17bd41ed22c809588a361f28bc9f1f1ffd0ccd1933bb35c88b78a330bbfc9a4aa178cd661202657cae56ce6d13
|
|
7
|
+
data.tar.gz: e6ca075b83151a66a015ba99c2120ee45bd35fe338cb4f7feb6d82e772eab60a8116ea4ee4fa90629c8e6e79cd2b17c867630916b9a5c3a0ac3154eabed1be77
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
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/
|
|
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
|
-
|
|
1
|
+
<!--- This file is synced from hanakai-rb/repo-sync -->
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
[](https://badge.fury.io/rb/hanami-router)
|
|
8
|
-
[](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 [][rubygem] [][actions]
|
|
17
9
|
|
|
10
|
+
[][forum]
|
|
11
|
+
[][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
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
363
|
+
See `LICENSE` file.
|
|
362
364
|
|
|
363
|
-
Copyright © 2014–2025 Hanami Team – Released under MIT License
|
data/hanami-router.gemspec
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
|
18
|
-
spec.
|
|
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.
|
|
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.
|
|
29
|
-
spec.
|
|
30
|
-
spec.
|
|
31
|
-
spec.
|
|
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.
|
|
34
|
-
|
|
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)
|
|
@@ -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
|
data/lib/hanami/router/route.rb
CHANGED
|
@@ -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)
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
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]
|
|
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 #
|
|
394
|
-
# @see #
|
|
395
|
-
def redirect(path, to: nil, as: nil
|
|
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,
|
|
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
|
|
796
|
+
# @since 3.0.0
|
|
749
797
|
# @api private
|
|
750
|
-
|
|
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), &
|
|
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
|
|
1047
|
+
def _env_with_params(env, params)
|
|
988
1048
|
params ||= {}
|
|
989
1049
|
env[PARAMS] ||= {}
|
|
990
1050
|
|
|
991
|
-
|
|
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:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hanakai team
|
|
8
|
-
bindir:
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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:
|
|
99
|
+
homepage: https://hanamirb.org
|
|
195
100
|
licenses:
|
|
196
101
|
- MIT
|
|
197
102
|
metadata:
|
|
198
|
-
|
|
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.
|
|
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.
|