hanami-router 2.0.0.alpha2 → 2.0.0.alpha6
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 +24 -0
- data/LICENSE.md +1 -1
- data/README.md +15 -7
- data/hanami-router.gemspec +6 -2
- data/lib/hanami/middleware/body_parser/class_interface.rb +1 -1
- data/lib/hanami/middleware/body_parser/json_parser.rb +2 -2
- data/lib/hanami/middleware/body_parser/parser.rb +58 -0
- data/lib/hanami/middleware/body_parser.rb +5 -3
- data/lib/hanami/router/inspector.rb +38 -0
- data/lib/hanami/router/node.rb +1 -3
- data/lib/hanami/router/params.rb +1 -1
- data/lib/hanami/router/prefix.rb +5 -3
- data/lib/hanami/router/recognized_route.rb +1 -1
- data/lib/hanami/router/redirect.rb +6 -1
- data/lib/hanami/router/route.rb +130 -0
- data/lib/hanami/router/version.rb +1 -1
- data/lib/hanami/router.rb +87 -25
- metadata +40 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d4b765c647ddf0aa30e30b516bc8e449a9734d6de8f8466c5e9ae96051b8b2b
|
4
|
+
data.tar.gz: 6b6728d2cb184ac2924fad9b36e0d61396b9dde66c95894a694c831291e113b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2553b5cae230e21181467afce6950bd3df79e17e6351bc8f9b92bf4577ccaf4f7b773d11d67d88e3fe9fa789fcefd5211dd721ea1e723c16414e2d2670594d3
|
7
|
+
data.tar.gz: 247718a876404665267bdeb523944a73b55d9f7e846b11888e022f0fcfac39c8514f2dca60b030e8820ac3958bc666f766229793a04f992bca328cbd0c3e2919
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
# Hanami::Router
|
2
2
|
Rack compatible HTTP router for Ruby
|
3
3
|
|
4
|
+
## v2.0.0.alpha6 - 2022-02-10
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Official support for MRI 3.1
|
7
|
+
- [Luca Guidi] Parse non-GET request body and make it available in Rack env under the `router.params` key. For JSON requests, please use `Hanami:::Middleware::JsonParser`
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- [Luca Guidi] Drop support for Ruby: MRI 2.6, and 2.7.
|
11
|
+
|
12
|
+
## v2.0.0.alpha5 - 2021-05-04
|
13
|
+
### Added
|
14
|
+
- [Luca Guidi] Introduced `Hanami::Router#to_inspect` which returns a string blob with all the routes formatted for human readability
|
15
|
+
|
16
|
+
## v2.0.0.alpha4 - 2021-01-16
|
17
|
+
### Added
|
18
|
+
- [Luca Guidi] Official support for MRI 3.0
|
19
|
+
- [Luca Guidi] Introduced `Hanami::Middleware::BodyParser::Parser` as superclass for body parsers
|
20
|
+
- [Paweł Świątkowski] Added `not_found:` option to `Hanami::Router#initialize` to customize HTTP 404 status
|
21
|
+
|
22
|
+
## v2.0.0.alpha3 - 2020-05-20
|
23
|
+
### Fixed
|
24
|
+
- [Luca Guidi] `Hanami::Router#initialize` do not yield block if not given
|
25
|
+
- [Luca Guidi] Ensure to not accidentally cache response headers for HTTP 404 and 405
|
26
|
+
- [Luca Guidi] Ensure scoped root to not be added as trailing slash
|
27
|
+
|
4
28
|
## v2.0.0.alpha2 - 2020-02-19
|
5
29
|
### Added
|
6
30
|
- [Luca Guidi] Block syntax. Routes definition accept a block which returning value is the body of the Rack response.
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://hanamirb.org).
|
4
4
|
|
5
|
+
## Version
|
6
|
+
|
7
|
+
**This branch contains the code for `hanami-router` 2.x.**
|
8
|
+
|
5
9
|
## Status
|
6
10
|
|
7
11
|
[](https://badge.fury.io/rb/hanami-router)
|
8
|
-
[](https://codecov.io/gh/hanami/router)
|
12
|
+
[](https://github.com/hanami/router/actions?query=workflow%3Aci+branch%3Amain)
|
13
|
+
[](https://codecov.io/gh/hanami/router)
|
11
14
|
[](https://depfu.com/github/hanami/router?project=Bundler)
|
12
15
|
[](http://inch-ci.org/github/hanami/router)
|
13
16
|
|
@@ -22,7 +25,7 @@ Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://h
|
|
22
25
|
|
23
26
|
## Rubies
|
24
27
|
|
25
|
-
__Hanami::Router__ supports Ruby (MRI)
|
28
|
+
__Hanami::Router__ supports Ruby (MRI) 3.0+
|
26
29
|
|
27
30
|
|
28
31
|
## Installation
|
@@ -225,6 +228,13 @@ router = Hanami::Router.new
|
|
225
228
|
router.call(Rack::MockRequest.env_for("/unknown")).status # => 404
|
226
229
|
```
|
227
230
|
|
231
|
+
### Explicit Not Found:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
router = Hanami::Router.new(not_found: ->(_) { [499, {}, []]})
|
235
|
+
router.call(Rack::MockRequest.env_for("/unknown")).status # => 499
|
236
|
+
```
|
237
|
+
|
228
238
|
### Body Parsers
|
229
239
|
|
230
240
|
Rack ignores request bodies unless they come from a form submission.
|
@@ -355,6 +365,4 @@ __Hanami::Router__ uses [Semantic Versioning 2.0.0](http://semver.org)
|
|
355
365
|
|
356
366
|
## Copyright
|
357
367
|
|
358
|
-
Copyright © 2014-
|
359
|
-
|
360
|
-
This project was formerly known as Lotus (`lotus-router`).
|
368
|
+
Copyright © 2014-2022 Hanami Team – Released under MIT License
|
data/hanami-router.gemspec
CHANGED
@@ -14,11 +14,12 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "http://hanamirb.org"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-router.gemspec`.split(
|
17
|
+
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-router.gemspec`.split($/)
|
18
18
|
spec.executables = []
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
|
-
spec.
|
21
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
22
|
+
spec.required_ruby_version = ">= 3.0"
|
22
23
|
|
23
24
|
spec.add_dependency "rack", "~> 2.0"
|
24
25
|
spec.add_dependency "mustermann", "~> 1.0"
|
@@ -28,4 +29,7 @@ Gem::Specification.new do |spec|
|
|
28
29
|
spec.add_development_dependency "rake", "~> 13"
|
29
30
|
spec.add_development_dependency "rack-test", "~> 1.0"
|
30
31
|
spec.add_development_dependency "rspec", "~> 3.8"
|
32
|
+
|
33
|
+
spec.add_development_dependency "rubocop", "~> 1.0"
|
34
|
+
spec.add_development_dependency "rubocop-performance", "~> 1.0"
|
31
35
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "json"
|
4
|
-
require_relative "
|
4
|
+
require_relative "parser"
|
5
5
|
|
6
6
|
module Hanami
|
7
7
|
module Middleware
|
8
8
|
class BodyParser
|
9
9
|
# @since 1.3.0
|
10
10
|
# @api private
|
11
|
-
class JsonParser
|
11
|
+
class JsonParser < Parser
|
12
12
|
# @since 1.3.0
|
13
13
|
# @api private
|
14
14
|
def mime_types
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Middleware
|
5
|
+
class BodyParser
|
6
|
+
# Body parser abstract class
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
class Parser
|
10
|
+
# Declare supported MIME types
|
11
|
+
#
|
12
|
+
# @return [Array<String>] supported MIME types
|
13
|
+
#
|
14
|
+
# @abstract
|
15
|
+
# @since 2.0.0
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# require "hanami/middleware/body_parser"
|
19
|
+
#
|
20
|
+
# class XMLParser < Hanami::Middleware::BodyParser::Parser
|
21
|
+
# def mime_types
|
22
|
+
# ["application/xml", "text/xml"]
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
def mime_types
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
# Parse raw HTTP request body
|
30
|
+
#
|
31
|
+
# @param body [String] HTTP request body
|
32
|
+
#
|
33
|
+
# @return [Hash] the result of the parsing
|
34
|
+
#
|
35
|
+
# @raise [Hanami::Middleware::BodyParser::BodyParsingError] the error
|
36
|
+
# that must be raised if the parsing cannot be accomplished
|
37
|
+
#
|
38
|
+
# @abstract
|
39
|
+
# @since 2.0.0
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# require "hanami/middleware/body_parser"
|
43
|
+
#
|
44
|
+
# class XMLParser < Hanami::Middleware::BodyParser::Parser
|
45
|
+
# def parse(body)
|
46
|
+
# # XML parsing
|
47
|
+
# # ...
|
48
|
+
# rescue => exception
|
49
|
+
# raise Hanami::Middleware::BodyParser::BodyParsingError.new(exception.message)
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
def parse(body)
|
53
|
+
raise NotImplementedError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,20 +2,22 @@
|
|
2
2
|
|
3
3
|
require "hanami/router/params"
|
4
4
|
require "hanami/middleware/error"
|
5
|
-
require_relative "body_parser/class_interface"
|
6
5
|
|
7
6
|
module Hanami
|
8
7
|
module Middleware
|
9
8
|
# @since 1.3.0
|
10
9
|
# @api private
|
11
10
|
class BodyParser
|
11
|
+
require_relative "body_parser/class_interface"
|
12
|
+
require_relative "body_parser/parser"
|
13
|
+
|
12
14
|
# @since 1.3.0
|
13
15
|
# @api private
|
14
16
|
CONTENT_TYPE = "CONTENT_TYPE"
|
15
17
|
|
16
18
|
# @since 1.3.0
|
17
19
|
# @api private
|
18
|
-
MEDIA_TYPE_MATCHER = /\s*[;,]\s
|
20
|
+
MEDIA_TYPE_MATCHER = /\s*[;,]\s*/
|
19
21
|
|
20
22
|
# @since 1.3.0
|
21
23
|
# @api private
|
@@ -72,7 +74,7 @@ module Hanami
|
|
72
74
|
if body.is_a?(::Hash)
|
73
75
|
Router::Params.deep_symbolize(body)
|
74
76
|
else
|
75
|
-
{
|
77
|
+
{FALLBACK_KEY => body}
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Router
|
5
|
+
# Routes inspector
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
# @since 2.0.0
|
9
|
+
class Inspector
|
10
|
+
# @api private
|
11
|
+
# @since 2.0.0
|
12
|
+
def initialize(routes: [])
|
13
|
+
@routes = routes
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param route [Hash] serialized route
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
# @since 2.0.0
|
20
|
+
def add_route(route)
|
21
|
+
@routes.push(route)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] The inspected routes
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 2.0.0
|
28
|
+
def call(*)
|
29
|
+
@routes.map(&:to_inspect).join(NEW_LINE)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @api private
|
33
|
+
# @since 2.0.0
|
34
|
+
NEW_LINE = $/
|
35
|
+
private_constant :NEW_LINE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/hanami/router/node.rb
CHANGED
@@ -36,8 +36,7 @@ module Hanami
|
|
36
36
|
# @api private
|
37
37
|
# @since 2.0.0
|
38
38
|
#
|
39
|
-
# rubocop:disable Metrics/
|
40
|
-
def get(segment)
|
39
|
+
def get(segment) # rubocop:disable Metrics/PerceivedComplexity
|
41
40
|
return unless @variable || @fixed
|
42
41
|
|
43
42
|
found = nil
|
@@ -55,7 +54,6 @@ module Hanami
|
|
55
54
|
|
56
55
|
[found, captured&.named_captures]
|
57
56
|
end
|
58
|
-
# rubocop:enable Metrics/MethodLength
|
59
57
|
|
60
58
|
# @api private
|
61
59
|
# @since 2.0.0
|
data/lib/hanami/router/params.rb
CHANGED
data/lib/hanami/router/prefix.rb
CHANGED
@@ -25,7 +25,7 @@ module Hanami
|
|
25
25
|
# @api private
|
26
26
|
def relative_join(path, separator = DEFAULT_SEPARATOR)
|
27
27
|
_join(path.to_s)
|
28
|
-
.gsub(DEFAULT_SEPARATOR_REGEXP, separator)[1
|
28
|
+
.gsub(DEFAULT_SEPARATOR_REGEXP, separator)[1..]
|
29
29
|
end
|
30
30
|
|
31
31
|
# @since 2.0.0
|
@@ -48,15 +48,17 @@ module Hanami
|
|
48
48
|
|
49
49
|
# @since 2.0.0
|
50
50
|
# @api private
|
51
|
-
DEFAULT_SEPARATOR_REGEXP =
|
51
|
+
DEFAULT_SEPARATOR_REGEXP = /\//
|
52
52
|
|
53
53
|
# @since 2.0.0
|
54
54
|
# @api private
|
55
|
-
DOUBLE_DEFAULT_SEPARATOR_REGEXP =
|
55
|
+
DOUBLE_DEFAULT_SEPARATOR_REGEXP = /\/{2,}/
|
56
56
|
|
57
57
|
# @since 2.0.0
|
58
58
|
# @api private
|
59
59
|
def _join(path)
|
60
|
+
return @prefix if path == DEFAULT_SEPARATOR
|
61
|
+
|
60
62
|
(@prefix + DEFAULT_SEPARATOR + path)
|
61
63
|
.gsub(DOUBLE_DEFAULT_SEPARATOR_REGEXP, DEFAULT_SEPARATOR)
|
62
64
|
end
|
@@ -27,7 +27,7 @@ module Hanami
|
|
27
27
|
# @see Hanami::Router::RecognizedRoute#routable?
|
28
28
|
# @see Hanami::Router::NotRoutableEndpointError
|
29
29
|
def call(env)
|
30
|
-
if routable?
|
30
|
+
if routable?
|
31
31
|
@endpoint.call(env)
|
32
32
|
else
|
33
33
|
raise NotRoutableEndpointError.new(@env)
|
@@ -13,8 +13,13 @@ module Hanami
|
|
13
13
|
|
14
14
|
# @since 2.0.0
|
15
15
|
# @api private
|
16
|
-
|
16
|
+
attr_reader :code
|
17
|
+
|
18
|
+
# @since 2.0.0
|
19
|
+
# @api private
|
20
|
+
def initialize(destination, code, endpoint)
|
17
21
|
@destination = destination
|
22
|
+
@code = code
|
18
23
|
@endpoint = endpoint
|
19
24
|
end
|
20
25
|
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/router/redirect"
|
4
|
+
require "hanami/router/block"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
class Router
|
8
|
+
class Route
|
9
|
+
# @api private
|
10
|
+
# @since 2.0.0
|
11
|
+
attr_reader :http_method
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
# @since 2.0.0
|
15
|
+
attr_reader :path
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
# @since 2.0.0
|
19
|
+
attr_reader :to
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
# @since 2.0.0
|
23
|
+
attr_reader :as
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
# @since 2.0.0
|
27
|
+
attr_reader :constraints
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
# @since 2.0.0
|
31
|
+
def initialize(http_method:, path:, to:, as: nil, constraints: {}, blk: nil) # rubocop:disable Metrics/ParameterLists
|
32
|
+
@http_method = http_method
|
33
|
+
@path = path
|
34
|
+
@to = to
|
35
|
+
@as = as
|
36
|
+
@constraints = constraints
|
37
|
+
@blk = blk
|
38
|
+
freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
# @since 2.0.0
|
43
|
+
def to_inspect
|
44
|
+
return EMPTY_ROUTE if head?
|
45
|
+
|
46
|
+
result = http_method.to_s.ljust(SMALL_STRING_JUSTIFY_AMOUNT)
|
47
|
+
result += path.ljust(LARGE_STRING_JUSTIFY_AMOUNT)
|
48
|
+
result += inspect_to(to).ljust(LARGE_STRING_JUSTIFY_AMOUNT)
|
49
|
+
result += "as #{as.inspect}".ljust(MEDIUM_STRING_JUSTIFY_AMOUNT) if as
|
50
|
+
|
51
|
+
if constraints?
|
52
|
+
result += "(#{inspect_constraints(constraints)})".ljust(EXTRA_LARGE_STRING_JUSTIFY_AMOUNT)
|
53
|
+
end
|
54
|
+
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
# @since 2.0.0
|
62
|
+
EMPTY_ROUTE = ""
|
63
|
+
private_constant :EMPTY_ROUTE
|
64
|
+
|
65
|
+
# @api private
|
66
|
+
# @since 2.0.0
|
67
|
+
ROUTE_CONSTRAINT_SEPARATOR = ", "
|
68
|
+
private_constant :ROUTE_CONSTRAINT_SEPARATOR
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
# @since 2.0.0
|
72
|
+
SMALL_STRING_JUSTIFY_AMOUNT = 8
|
73
|
+
private_constant :SMALL_STRING_JUSTIFY_AMOUNT
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
# @since 2.0.0
|
77
|
+
MEDIUM_STRING_JUSTIFY_AMOUNT = 20
|
78
|
+
private_constant :MEDIUM_STRING_JUSTIFY_AMOUNT
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
# @since 2.0.0
|
82
|
+
LARGE_STRING_JUSTIFY_AMOUNT = 30
|
83
|
+
private_constant :LARGE_STRING_JUSTIFY_AMOUNT
|
84
|
+
|
85
|
+
# @api private
|
86
|
+
# @since 2.0.0
|
87
|
+
EXTRA_LARGE_STRING_JUSTIFY_AMOUNT = 40
|
88
|
+
private_constant :EXTRA_LARGE_STRING_JUSTIFY_AMOUNT
|
89
|
+
|
90
|
+
# @api private
|
91
|
+
# @since 2.0.0
|
92
|
+
def head?
|
93
|
+
http_method == "HEAD"
|
94
|
+
end
|
95
|
+
|
96
|
+
# @api private
|
97
|
+
# @since 2.0.0
|
98
|
+
def constraints?
|
99
|
+
constraints.any?
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
# @since 2.0.0
|
104
|
+
def inspect_to(to)
|
105
|
+
case to
|
106
|
+
when String
|
107
|
+
to
|
108
|
+
when Proc
|
109
|
+
"(proc)"
|
110
|
+
when Class
|
111
|
+
to.name || "(class)"
|
112
|
+
when Block
|
113
|
+
"(block)"
|
114
|
+
when Redirect
|
115
|
+
"#{to.destination} (HTTP #{to.code})"
|
116
|
+
else
|
117
|
+
inspect_to(to.class)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @api private
|
122
|
+
# @since 2.0.0
|
123
|
+
def inspect_constraints(constraints)
|
124
|
+
constraints.map do |key, value|
|
125
|
+
"#{key}: #{value.inspect}"
|
126
|
+
end.join(ROUTE_CONSTRAINT_SEPARATOR)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/hanami/router.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rack"
|
3
4
|
require "rack/utils"
|
4
5
|
|
5
6
|
module Hanami
|
6
7
|
# Rack compatible, lightweight and fast HTTP Router.
|
7
8
|
#
|
8
9
|
# @since 0.1.0
|
9
|
-
class Router
|
10
|
+
class Router
|
10
11
|
require "hanami/router/version"
|
11
12
|
require "hanami/router/error"
|
12
13
|
require "hanami/router/segment"
|
@@ -15,6 +16,7 @@ module Hanami
|
|
15
16
|
require "hanami/router/params"
|
16
17
|
require "hanami/router/trie"
|
17
18
|
require "hanami/router/block"
|
19
|
+
require "hanami/router/route"
|
18
20
|
require "hanami/router/url_helpers"
|
19
21
|
|
20
22
|
# URL helpers for other Hanami integrations
|
@@ -23,6 +25,12 @@ module Hanami
|
|
23
25
|
# @since 2.0.0
|
24
26
|
attr_reader :url_helpers
|
25
27
|
|
28
|
+
# Routes for inspection
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
# @since 2.0.0
|
32
|
+
attr_reader :routes
|
33
|
+
|
26
34
|
# Returns the given block as it is.
|
27
35
|
#
|
28
36
|
# @param blk [Proc] a set of route definitions
|
@@ -48,6 +56,7 @@ module Hanami
|
|
48
56
|
# is deployed
|
49
57
|
# @param resolver [#call(path, to)] a resolver for route entpoints
|
50
58
|
# @param block_context [Hanami::Router::Block::Context)
|
59
|
+
# @param not_found [#call(env)] default handler when route is not matched
|
51
60
|
# @param blk [Proc] the route definitions
|
52
61
|
#
|
53
62
|
# @since 0.1.0
|
@@ -60,18 +69,22 @@ module Hanami
|
|
60
69
|
# Hanami::Router.new do
|
61
70
|
# get "/", to: ->(*) { [200, {}, ["OK"]] }
|
62
71
|
# end
|
63
|
-
def initialize(base_url: DEFAULT_BASE_URL, prefix: DEFAULT_PREFIX, resolver: DEFAULT_RESOLVER, block_context: nil, &blk)
|
72
|
+
def initialize(base_url: DEFAULT_BASE_URL, prefix: DEFAULT_PREFIX, resolver: DEFAULT_RESOLVER, not_found: NOT_FOUND, block_context: nil, inspector: nil, &blk) # rubocop:disable Layout/LineLength
|
64
73
|
# TODO: verify if Prefix can handle both name and path prefix
|
65
74
|
@path_prefix = Prefix.new(prefix)
|
66
75
|
@name_prefix = Prefix.new("")
|
67
76
|
@url_helpers = UrlHelpers.new(base_url)
|
77
|
+
@base_url = base_url
|
68
78
|
@resolver = resolver
|
79
|
+
@not_found = not_found
|
69
80
|
@block_context = block_context
|
70
81
|
@fixed = {}
|
71
82
|
@variable = {}
|
72
83
|
@globbed = {}
|
73
84
|
@mounted = {}
|
74
|
-
|
85
|
+
@blk = blk
|
86
|
+
@inspector = inspector
|
87
|
+
instance_eval(&blk) if blk
|
75
88
|
end
|
76
89
|
|
77
90
|
# Resolve the given Rack env to a registered endpoint and invokes it.
|
@@ -86,7 +99,7 @@ module Hanami
|
|
86
99
|
|
87
100
|
unless endpoint
|
88
101
|
return not_allowed(env) ||
|
89
|
-
not_found
|
102
|
+
not_found(env)
|
90
103
|
end
|
91
104
|
|
92
105
|
endpoint.call(
|
@@ -405,7 +418,11 @@ module Hanami
|
|
405
418
|
def mount(app, at:, **constraints)
|
406
419
|
path = prefixed_path(at)
|
407
420
|
prefix = Segment.fabricate(path, **constraints)
|
421
|
+
|
408
422
|
@mounted[prefix] = @resolver.call(path, app)
|
423
|
+
if inspect?
|
424
|
+
@inspector.add_route(Route.new(http_method: "*", path: at, to: app, constraints: constraints))
|
425
|
+
end
|
409
426
|
end
|
410
427
|
|
411
428
|
# Generate an relative URL for a specified named route.
|
@@ -586,6 +603,21 @@ module Hanami
|
|
586
603
|
)
|
587
604
|
end
|
588
605
|
|
606
|
+
# Returns formatted routes
|
607
|
+
#
|
608
|
+
# @return [String] formatted routes
|
609
|
+
#
|
610
|
+
# @since 2.0.0
|
611
|
+
# @api private
|
612
|
+
def to_inspect
|
613
|
+
require "hanami/router/inspector"
|
614
|
+
|
615
|
+
inspector = Inspector.new
|
616
|
+
with(inspector: inspector)
|
617
|
+
|
618
|
+
inspector.call
|
619
|
+
end
|
620
|
+
|
589
621
|
# @since 2.0.0
|
590
622
|
# @api private
|
591
623
|
def fixed(env)
|
@@ -631,13 +663,14 @@ module Hanami
|
|
631
663
|
# @since 2.0.0
|
632
664
|
# @api private
|
633
665
|
def not_allowed(env)
|
634
|
-
(_not_allowed_fixed(env) ||
|
666
|
+
(_not_allowed_fixed(env) ||
|
667
|
+
_not_allowed_variable(env)) and return [405, {"Content-Length" => "11"}, ["Not Allowed"]]
|
635
668
|
end
|
636
669
|
|
637
670
|
# @since 2.0.0
|
638
671
|
# @api private
|
639
|
-
def not_found
|
640
|
-
|
672
|
+
def not_found(env)
|
673
|
+
@not_found.call(env)
|
641
674
|
end
|
642
675
|
|
643
676
|
protected
|
@@ -655,7 +688,7 @@ module Hanami
|
|
655
688
|
#
|
656
689
|
# @see Hanami::Router#recognize
|
657
690
|
# @see http://www.rubydoc.info/github/rack/rack/Rack%2FMockRequest.env_for
|
658
|
-
def env_for(env, params = {}, options = {})
|
691
|
+
def env_for(env, params = {}, options = {})
|
659
692
|
require "rack/mock"
|
660
693
|
|
661
694
|
case env
|
@@ -666,7 +699,7 @@ module Hanami
|
|
666
699
|
url = path(env, params)
|
667
700
|
return env_for(url, params, options) # rubocop:disable Style/RedundantReturn
|
668
701
|
rescue Hanami::Router::InvalidRouteException
|
669
|
-
|
702
|
+
{} # Empty Rack env
|
670
703
|
end
|
671
704
|
else
|
672
705
|
env
|
@@ -691,31 +724,21 @@ module Hanami
|
|
691
724
|
# @api private
|
692
725
|
DEFAULT_REDIRECT_CODE = 301
|
693
726
|
|
694
|
-
# @since 2.0.0
|
695
|
-
# @api private
|
696
|
-
NOT_FOUND = [404, { "Content-Length" => "9" }, ["Not Found"]].freeze
|
697
|
-
|
698
|
-
# @since 2.0.0
|
699
|
-
# @api private
|
700
|
-
NOT_ALLOWED = [405, { "Content-Length" => "11" }, ["Not Allowed"]].freeze
|
701
|
-
|
702
727
|
# @since 2.0.0
|
703
728
|
# @api private
|
704
729
|
PARAMS = "router.params"
|
705
730
|
|
706
|
-
#
|
731
|
+
# Default response when no route was matched
|
732
|
+
#
|
707
733
|
# @api private
|
708
|
-
EMPTY_PARAMS = {}.freeze
|
709
|
-
|
710
734
|
# @since 2.0.0
|
711
|
-
|
712
|
-
EMPTY_RACK_ENV = {}.freeze
|
735
|
+
NOT_FOUND = ->(*) { [404, {"Content-Length" => "9"}, ["Not Found"]] }.freeze
|
713
736
|
|
714
737
|
# @since 2.0.0
|
715
738
|
# @api private
|
716
739
|
def lookup(env)
|
717
740
|
endpoint = fixed(env)
|
718
|
-
return [endpoint,
|
741
|
+
return [endpoint, {}] if endpoint
|
719
742
|
|
720
743
|
variable(env) || globbed(env) || mounted(env)
|
721
744
|
end
|
@@ -735,6 +758,12 @@ module Hanami
|
|
735
758
|
end
|
736
759
|
|
737
760
|
add_named_route(path, as, constraints) if as
|
761
|
+
|
762
|
+
if inspect?
|
763
|
+
@inspector.add_route(
|
764
|
+
Route.new(http_method: http_method, path: path, to: to, as: as, constraints: constraints, blk: blk)
|
765
|
+
)
|
766
|
+
end
|
738
767
|
end
|
739
768
|
|
740
769
|
# @since 2.0.0
|
@@ -785,6 +814,12 @@ module Hanami
|
|
785
814
|
/\*/.match?(path)
|
786
815
|
end
|
787
816
|
|
817
|
+
# @since 2.0.0
|
818
|
+
# @api private
|
819
|
+
def inspect?
|
820
|
+
!@inspector.nil?
|
821
|
+
end
|
822
|
+
|
788
823
|
# @since 2.0.0
|
789
824
|
# @api private
|
790
825
|
def prefixed_path(path)
|
@@ -797,6 +832,27 @@ module Hanami
|
|
797
832
|
@name_prefix.relative_join(name, "_").to_sym
|
798
833
|
end
|
799
834
|
|
835
|
+
# Returns a new instance of Hanami::Router with the modified options.
|
836
|
+
#
|
837
|
+
# @return [Hanami::Route] a new instance of Hanami::Router
|
838
|
+
#
|
839
|
+
# @see Hanami::Router#initialize
|
840
|
+
#
|
841
|
+
# @since 2.0.0
|
842
|
+
# @api private
|
843
|
+
def with(**new_options, &blk)
|
844
|
+
options = {
|
845
|
+
base_url: @base_url,
|
846
|
+
prefix: @path_prefix.to_s,
|
847
|
+
resolver: @resolver,
|
848
|
+
not_found: @not_found,
|
849
|
+
block_context: @block_context,
|
850
|
+
inspector: @inspector
|
851
|
+
}
|
852
|
+
|
853
|
+
self.class.new(**options.merge(new_options), &(blk || @blk))
|
854
|
+
end
|
855
|
+
|
800
856
|
# @since 2.0.0
|
801
857
|
# @api private
|
802
858
|
def _redirect(to, code)
|
@@ -805,7 +861,7 @@ module Hanami
|
|
805
861
|
end
|
806
862
|
|
807
863
|
destination = prefixed_path(to)
|
808
|
-
Redirect.new(destination, ->(*) { [code, {
|
864
|
+
Redirect.new(destination, code, ->(*) { [code, {"Location" => destination}, [body]] })
|
809
865
|
end
|
810
866
|
|
811
867
|
# @since 2.0.0
|
@@ -813,7 +869,13 @@ module Hanami
|
|
813
869
|
def _params(env, params)
|
814
870
|
params ||= {}
|
815
871
|
env[PARAMS] ||= {}
|
816
|
-
|
872
|
+
|
873
|
+
if (input = env[Rack::RACK_INPUT]) and input.rewind
|
874
|
+
env[PARAMS].merge!(Rack::Utils.parse_nested_query(input.read))
|
875
|
+
input.rewind
|
876
|
+
end
|
877
|
+
|
878
|
+
env[PARAMS].merge!(Rack::Utils.parse_nested_query(env[Rack::QUERY_STRING]))
|
817
879
|
env[PARAMS].merge!(params)
|
818
880
|
env[PARAMS] = Params.deep_symbolize(env[PARAMS])
|
819
881
|
env
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.alpha6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -114,6 +114,34 @@ dependencies:
|
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '3.8'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rubocop
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '1.0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '1.0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rubocop-performance
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '1.0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '1.0'
|
117
145
|
description: Rack compatible HTTP router for Ruby
|
118
146
|
email:
|
119
147
|
- me@lucaguidi.com
|
@@ -129,15 +157,18 @@ files:
|
|
129
157
|
- lib/hanami/middleware/body_parser/class_interface.rb
|
130
158
|
- lib/hanami/middleware/body_parser/errors.rb
|
131
159
|
- lib/hanami/middleware/body_parser/json_parser.rb
|
160
|
+
- lib/hanami/middleware/body_parser/parser.rb
|
132
161
|
- lib/hanami/middleware/error.rb
|
133
162
|
- lib/hanami/router.rb
|
134
163
|
- lib/hanami/router/block.rb
|
135
164
|
- lib/hanami/router/error.rb
|
165
|
+
- lib/hanami/router/inspector.rb
|
136
166
|
- lib/hanami/router/node.rb
|
137
167
|
- lib/hanami/router/params.rb
|
138
168
|
- lib/hanami/router/prefix.rb
|
139
169
|
- lib/hanami/router/recognized_route.rb
|
140
170
|
- lib/hanami/router/redirect.rb
|
171
|
+
- lib/hanami/router/route.rb
|
141
172
|
- lib/hanami/router/segment.rb
|
142
173
|
- lib/hanami/router/trie.rb
|
143
174
|
- lib/hanami/router/url_helpers.rb
|
@@ -145,8 +176,9 @@ files:
|
|
145
176
|
homepage: http://hanamirb.org
|
146
177
|
licenses:
|
147
178
|
- MIT
|
148
|
-
metadata:
|
149
|
-
|
179
|
+
metadata:
|
180
|
+
rubygems_mfa_required: 'true'
|
181
|
+
post_install_message:
|
150
182
|
rdoc_options: []
|
151
183
|
require_paths:
|
152
184
|
- lib
|
@@ -154,15 +186,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
186
|
requirements:
|
155
187
|
- - ">="
|
156
188
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
189
|
+
version: '3.0'
|
158
190
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
191
|
requirements:
|
160
192
|
- - ">"
|
161
193
|
- !ruby/object:Gem::Version
|
162
194
|
version: 1.3.1
|
163
195
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
165
|
-
signing_key:
|
196
|
+
rubygems_version: 3.3.3
|
197
|
+
signing_key:
|
166
198
|
specification_version: 4
|
167
199
|
summary: Rack compatible HTTP router for Ruby and Hanami
|
168
200
|
test_files: []
|