hanami-router 2.0.0.alpha3 → 2.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 +136 -0
- data/LICENSE.md +1 -1
- data/README.md +15 -7
- data/hanami-router.gemspec +6 -3
- data/lib/hanami/middleware/app.rb +50 -0
- data/lib/hanami/middleware/body_parser/class_interface.rb +76 -9
- data/lib/hanami/middleware/body_parser/errors.rb +2 -0
- data/lib/hanami/middleware/body_parser/json_parser.rb +3 -3
- data/lib/hanami/middleware/body_parser/parser.rb +63 -0
- data/lib/hanami/middleware/body_parser.rb +9 -22
- data/lib/hanami/middleware/error.rb +1 -1
- data/lib/hanami/middleware/node.rb +59 -0
- data/lib/hanami/middleware/trie.rb +69 -0
- data/lib/hanami/router/block.rb +2 -2
- data/lib/hanami/router/constants.rb +9 -0
- data/lib/hanami/router/errors.rb +85 -0
- data/lib/hanami/router/formatter/csv.rb +62 -0
- data/lib/hanami/router/formatter/human_friendly.rb +57 -0
- data/lib/hanami/router/inspector.rb +46 -0
- data/lib/hanami/router/node.rb +2 -4
- data/lib/hanami/router/params.rb +1 -1
- data/lib/hanami/router/prefix.rb +3 -3
- data/lib/hanami/router/recognized_route.rb +31 -6
- data/lib/hanami/router/redirect.rb +6 -1
- data/lib/hanami/router/route.rb +160 -0
- data/lib/hanami/router/trie.rb +6 -1
- data/lib/hanami/router/url_helpers.rb +7 -6
- data/lib/hanami/router/version.rb +5 -2
- data/lib/hanami/router.rb +179 -51
- metadata +49 -11
- data/lib/hanami/router/error.rb +0 -67
|
@@ -4,10 +4,13 @@ module Hanami
|
|
|
4
4
|
class Router
|
|
5
5
|
# Represents a result of router path recognition.
|
|
6
6
|
#
|
|
7
|
-
# @since 0.5.0
|
|
8
|
-
#
|
|
9
7
|
# @see Hanami::Router#recognize
|
|
8
|
+
#
|
|
9
|
+
# @since 0.5.0
|
|
10
|
+
# @api public
|
|
10
11
|
class RecognizedRoute
|
|
12
|
+
# @since 0.5.0
|
|
13
|
+
# @api private
|
|
11
14
|
def initialize(endpoint, env)
|
|
12
15
|
@endpoint = endpoint
|
|
13
16
|
@env = env
|
|
@@ -27,7 +30,7 @@ module Hanami
|
|
|
27
30
|
# @see Hanami::Router::RecognizedRoute#routable?
|
|
28
31
|
# @see Hanami::Router::NotRoutableEndpointError
|
|
29
32
|
def call(env)
|
|
30
|
-
if routable?
|
|
33
|
+
if routable?
|
|
31
34
|
@endpoint.call(env)
|
|
32
35
|
else
|
|
33
36
|
raise NotRoutableEndpointError.new(@env)
|
|
@@ -41,7 +44,7 @@ module Hanami
|
|
|
41
44
|
# @since 0.5.0
|
|
42
45
|
# @api public
|
|
43
46
|
def verb
|
|
44
|
-
@env[
|
|
47
|
+
@env[::Rack::REQUEST_METHOD]
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
# Relative URL (path)
|
|
@@ -51,15 +54,25 @@ module Hanami
|
|
|
51
54
|
# @since 0.7.0
|
|
52
55
|
# @api public
|
|
53
56
|
def path
|
|
54
|
-
@env[
|
|
57
|
+
@env[::Rack::PATH_INFO]
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
# Returns the route's path params.
|
|
61
|
+
#
|
|
62
|
+
# @return [Hash]
|
|
63
|
+
#
|
|
57
64
|
# @since 0.7.0
|
|
58
65
|
# @api public
|
|
59
66
|
def params
|
|
60
|
-
@env[
|
|
67
|
+
@env[Router::PARAMS]
|
|
61
68
|
end
|
|
62
69
|
|
|
70
|
+
# Returns the route's endpoint object.
|
|
71
|
+
#
|
|
72
|
+
# Returns nil if the route is a {#redirect? redirect}.
|
|
73
|
+
#
|
|
74
|
+
# @return [Object, nil]
|
|
75
|
+
#
|
|
63
76
|
# @since 0.7.0
|
|
64
77
|
# @api public
|
|
65
78
|
def endpoint
|
|
@@ -68,18 +81,30 @@ module Hanami
|
|
|
68
81
|
@endpoint
|
|
69
82
|
end
|
|
70
83
|
|
|
84
|
+
# Returns true if the route has an {#endpoint}.
|
|
85
|
+
#
|
|
86
|
+
# @return [Boolean]
|
|
87
|
+
#
|
|
71
88
|
# @since 0.7.0
|
|
72
89
|
# @api public
|
|
73
90
|
def routable?
|
|
74
91
|
!@endpoint.nil?
|
|
75
92
|
end
|
|
76
93
|
|
|
94
|
+
# Returns true if the route is a redirect.
|
|
95
|
+
#
|
|
96
|
+
# @return [Boolean]
|
|
97
|
+
#
|
|
77
98
|
# @since 0.7.0
|
|
78
99
|
# @api public
|
|
79
100
|
def redirect?
|
|
80
101
|
@endpoint.is_a?(Redirect)
|
|
81
102
|
end
|
|
82
103
|
|
|
104
|
+
# Returns the route's redirect path, if it is a redirect, or nil otherwise.
|
|
105
|
+
#
|
|
106
|
+
# @return [String, nil]
|
|
107
|
+
#
|
|
83
108
|
# @since 0.7.0
|
|
84
109
|
# @api public
|
|
85
110
|
def redirection_path
|
|
@@ -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,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/router/redirect"
|
|
4
|
+
require "hanami/router/block"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
class Router
|
|
8
|
+
# A route from the router
|
|
9
|
+
#
|
|
10
|
+
# @since 2.0.0
|
|
11
|
+
# @api public
|
|
12
|
+
class Route
|
|
13
|
+
# @since 2.0.0
|
|
14
|
+
# @api private
|
|
15
|
+
ROUTE_CONSTRAINT_SEPARATOR = ", "
|
|
16
|
+
private_constant :ROUTE_CONSTRAINT_SEPARATOR
|
|
17
|
+
|
|
18
|
+
# Returns the route's HTTP method.
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# route.http_method # => "GET"
|
|
22
|
+
#
|
|
23
|
+
# @return [String]
|
|
24
|
+
#
|
|
25
|
+
# @since 2.0.0
|
|
26
|
+
# @api public
|
|
27
|
+
attr_reader :http_method
|
|
28
|
+
|
|
29
|
+
# Returns the route's path.
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# route.path # => "/a/b/c"
|
|
33
|
+
#
|
|
34
|
+
# @return [String]
|
|
35
|
+
#
|
|
36
|
+
# @since 2.0.0
|
|
37
|
+
# @api public
|
|
38
|
+
attr_reader :path
|
|
39
|
+
|
|
40
|
+
# Returns the route's Rack endpoint, as given to `to:` when the route was defined.
|
|
41
|
+
#
|
|
42
|
+
# @return [Object]
|
|
43
|
+
#
|
|
44
|
+
# @since 2.0.0
|
|
45
|
+
# @api public
|
|
46
|
+
attr_reader :to
|
|
47
|
+
|
|
48
|
+
# Returns the route's unique name, as given to `as:` when the route was defined.
|
|
49
|
+
#
|
|
50
|
+
# @return [Object]
|
|
51
|
+
#
|
|
52
|
+
# @since 2.0.0
|
|
53
|
+
# @api public
|
|
54
|
+
attr_reader :as
|
|
55
|
+
|
|
56
|
+
# Returns the route's contraints hash for its path variables.
|
|
57
|
+
#
|
|
58
|
+
# @return [Hash]
|
|
59
|
+
#
|
|
60
|
+
# @since 2.0.0
|
|
61
|
+
# @api public
|
|
62
|
+
attr_reader :constraints
|
|
63
|
+
|
|
64
|
+
# @api private
|
|
65
|
+
# @since 2.0.0
|
|
66
|
+
def initialize(http_method:, path:, to:, as: nil, constraints: {}, blk: nil) # rubocop:disable Metrics/ParameterLists
|
|
67
|
+
@http_method = http_method
|
|
68
|
+
@path = path
|
|
69
|
+
@to = to
|
|
70
|
+
@as = as
|
|
71
|
+
@constraints = constraints
|
|
72
|
+
@blk = blk
|
|
73
|
+
freeze
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Returns true if the route is for the HEAD HTTP method.
|
|
77
|
+
#
|
|
78
|
+
# @return [Boolean]
|
|
79
|
+
#
|
|
80
|
+
# @see #http_method
|
|
81
|
+
#
|
|
82
|
+
# @since 2.0.0
|
|
83
|
+
# @api public
|
|
84
|
+
def head?
|
|
85
|
+
http_method == ::Rack::HEAD
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns true if the route has a name.
|
|
89
|
+
#
|
|
90
|
+
# @return [Boolean]
|
|
91
|
+
#
|
|
92
|
+
# @see #as
|
|
93
|
+
#
|
|
94
|
+
# @since 2.0.0
|
|
95
|
+
# @api public
|
|
96
|
+
def as?
|
|
97
|
+
!as.nil?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns true if the route has any constraints.
|
|
101
|
+
#
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
#
|
|
104
|
+
# @see #constraints
|
|
105
|
+
#
|
|
106
|
+
# @since 2.0.0
|
|
107
|
+
# @api public
|
|
108
|
+
def constraints?
|
|
109
|
+
constraints.any?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Returns a string containing a human-readable representation of the route's {#to} endpoint.
|
|
113
|
+
#
|
|
114
|
+
# @return [String]
|
|
115
|
+
#
|
|
116
|
+
# @since 2.0.0
|
|
117
|
+
# @api public
|
|
118
|
+
def inspect_to(value = to)
|
|
119
|
+
case value
|
|
120
|
+
when String
|
|
121
|
+
value
|
|
122
|
+
when Proc
|
|
123
|
+
"(proc)"
|
|
124
|
+
when Class
|
|
125
|
+
value.name || "(class)"
|
|
126
|
+
when Block
|
|
127
|
+
"(block)"
|
|
128
|
+
when Redirect
|
|
129
|
+
"#{value.destination} (HTTP #{to.code})"
|
|
130
|
+
else
|
|
131
|
+
inspect_to(value.class)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Returns a string containing a human-readable representation of the route's {#constraints}.
|
|
136
|
+
#
|
|
137
|
+
# @return [String]
|
|
138
|
+
#
|
|
139
|
+
# @since 2.0.0
|
|
140
|
+
# @api public
|
|
141
|
+
def inspect_constraints
|
|
142
|
+
@constraints.map do |key, value|
|
|
143
|
+
"#{key}: #{value.inspect}"
|
|
144
|
+
end.join(ROUTE_CONSTRAINT_SEPARATOR)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns a string containing a human-readable representation of the route's name.
|
|
148
|
+
#
|
|
149
|
+
# @return [String]
|
|
150
|
+
#
|
|
151
|
+
# @see #as
|
|
152
|
+
#
|
|
153
|
+
# @since 2.0.0
|
|
154
|
+
# @api public
|
|
155
|
+
def inspect_as
|
|
156
|
+
as ? as.inspect : Router::EMPTY_STRING
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
data/lib/hanami/router/trie.rb
CHANGED
|
@@ -52,10 +52,15 @@ module Hanami
|
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
|
+
# @api private
|
|
56
|
+
# @since 2.0.0
|
|
57
|
+
SEGMENT_SEPARATOR = /\//
|
|
58
|
+
private_constant :SEGMENT_SEPARATOR
|
|
59
|
+
|
|
55
60
|
# @api private
|
|
56
61
|
# @since 2.0.0
|
|
57
62
|
def for_each_segment(path, &blk)
|
|
58
|
-
_, *segments = path.split(
|
|
63
|
+
_, *segments = path.split(SEGMENT_SEPARATOR)
|
|
59
64
|
segments.each(&blk)
|
|
60
65
|
end
|
|
61
66
|
end
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "hanami/router/
|
|
3
|
+
require "hanami/router/errors"
|
|
4
4
|
require "mustermann/error"
|
|
5
5
|
|
|
6
6
|
module Hanami
|
|
7
7
|
class Router
|
|
8
|
-
#
|
|
8
|
+
# @since 2.0.0
|
|
9
|
+
# @api private
|
|
9
10
|
class UrlHelpers
|
|
10
11
|
# @since 2.0.0
|
|
11
12
|
# @api private
|
|
@@ -21,17 +22,17 @@ module Hanami
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
# @since 2.0.0
|
|
24
|
-
# @api
|
|
25
|
+
# @api private
|
|
25
26
|
def path(name, variables = {})
|
|
26
27
|
@named.fetch(name.to_sym) do
|
|
27
|
-
raise
|
|
28
|
+
raise MissingRouteError.new(name)
|
|
28
29
|
end.expand(:append, variables)
|
|
29
30
|
rescue Mustermann::ExpandError => exception
|
|
30
|
-
raise
|
|
31
|
+
raise InvalidRouteExpansionError.new(name, exception.message)
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
# @since 2.0.0
|
|
34
|
-
# @api
|
|
35
|
+
# @api private
|
|
35
36
|
def url(name, variables = {})
|
|
36
37
|
@base_url + path(name, variables)
|
|
37
38
|
end
|