hanami-router 1.3.1 → 2.0.0.alpha4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +97 -443
  5. data/hanami-router.gemspec +23 -19
  6. data/lib/hanami/middleware/body_parser.rb +21 -15
  7. data/lib/hanami/middleware/body_parser/class_interface.rb +62 -56
  8. data/lib/hanami/middleware/body_parser/errors.rb +7 -4
  9. data/lib/hanami/middleware/body_parser/json_parser.rb +9 -7
  10. data/lib/hanami/middleware/body_parser/parser.rb +58 -0
  11. data/lib/hanami/middleware/error.rb +16 -0
  12. data/lib/hanami/router.rb +548 -957
  13. data/lib/hanami/router/block.rb +88 -0
  14. data/lib/hanami/router/error.rb +67 -0
  15. data/lib/hanami/router/node.rb +91 -0
  16. data/lib/hanami/router/params.rb +35 -0
  17. data/lib/hanami/router/prefix.rb +67 -0
  18. data/lib/hanami/router/recognized_route.rb +92 -0
  19. data/lib/hanami/router/redirect.rb +28 -0
  20. data/lib/hanami/router/segment.rb +19 -0
  21. data/lib/hanami/router/trie.rb +63 -0
  22. data/lib/hanami/router/url_helpers.rb +40 -0
  23. data/lib/hanami/router/version.rb +4 -1
  24. metadata +61 -41
  25. data/lib/hanami-router.rb +0 -1
  26. data/lib/hanami/routing/endpoint.rb +0 -195
  27. data/lib/hanami/routing/endpoint_resolver.rb +0 -238
  28. data/lib/hanami/routing/error.rb +0 -7
  29. data/lib/hanami/routing/force_ssl.rb +0 -212
  30. data/lib/hanami/routing/http_router.rb +0 -220
  31. data/lib/hanami/routing/http_router_monkey_patch.rb +0 -38
  32. data/lib/hanami/routing/namespace.rb +0 -98
  33. data/lib/hanami/routing/parsers.rb +0 -113
  34. data/lib/hanami/routing/parsing/json_parser.rb +0 -33
  35. data/lib/hanami/routing/parsing/parser.rb +0 -61
  36. data/lib/hanami/routing/recognized_route.rb +0 -219
  37. data/lib/hanami/routing/resource.rb +0 -119
  38. data/lib/hanami/routing/resource/action.rb +0 -402
  39. data/lib/hanami/routing/resource/nested.rb +0 -41
  40. data/lib/hanami/routing/resource/options.rb +0 -74
  41. data/lib/hanami/routing/resources.rb +0 -48
  42. data/lib/hanami/routing/resources/action.rb +0 -156
  43. data/lib/hanami/routing/route.rb +0 -71
  44. data/lib/hanami/routing/routes_inspector.rb +0 -221
@@ -1,41 +0,0 @@
1
- module Hanami
2
- module Routing
3
- class Resource
4
- # Helper class to calculate nested path
5
- #
6
- # @api private
7
- # @since 0.4.0
8
- class Nested
9
- # @api private
10
- # @since 0.4.0
11
- SEPARATOR = '/'.freeze
12
-
13
- # @api private
14
- # @since 0.4.0
15
- def initialize(resource_name, resource)
16
- @resource_name = resource_name.to_s.split(SEPARATOR)
17
- @resource = resource
18
- @path = []
19
- _calculate(@resource_name.dup, @resource)
20
- end
21
-
22
- # @api private
23
- # @since 0.4.0
24
- def to_path
25
- @path.reverse!.pop
26
- @resource_name.zip(@path).flatten.join
27
- end
28
-
29
- private
30
-
31
- # @api private
32
- # @since 0.4.0
33
- def _calculate(param_wildcard, resource = nil)
34
- return if resource.nil?
35
- @path << resource.wildcard_param(param_wildcard.pop)
36
- _calculate(param_wildcard, resource.parent)
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,74 +0,0 @@
1
- module Hanami
2
- module Routing
3
- class Resource
4
- # Options for RESTFul resource(s)
5
- #
6
- # @api private
7
- # @since 0.1.0
8
- #
9
- # @see Hanami::Router#resource
10
- # @see Hanami::Router#resources
11
- class Options
12
- # @api private
13
- # @since 0.1.0
14
- attr_reader :actions
15
-
16
- # Initialize the options for:
17
- # * Hanami::Router#resource
18
- # * Hanami::Router#resources
19
- #
20
- # @param actions [Array<Symbol>] the name of the actions
21
- # @param options [Hash]
22
- # @option options [Hash] :only white list of the default actions
23
- # @option options [Hash] :except black list of the default actions
24
- # @option options [String] :controller namespace for an actions
25
- #
26
- # @api private
27
- # @since 0.1.0
28
- #
29
- # @see Hanami::Routing::Resource
30
- # @see Hanami::Routing::Resources
31
- #
32
- # @example
33
- # require 'hanami/router'
34
- #
35
- # Hanami::Router.new do
36
- # resources 'articles', only: [:index]
37
- # resource 'profile', except: [:new, :create, :destroy]
38
- # end
39
- def initialize(actions, options = {})
40
- only = Array(options.delete(:only) || actions)
41
- except = Array(options.delete(:except))
42
- @actions = ( actions & only ) - except
43
-
44
- @options = options
45
- end
46
-
47
- # Return the option for the given key
48
- #
49
- # @param key [Symbol] the key that should be searched
50
- #
51
- # @return [Object,nil] returns the object associated to the given key
52
- # or nil, if missing.
53
- #
54
- # @api private
55
- # @since 0.1.1
56
- def [](key)
57
- @options[key]
58
- end
59
-
60
- # Merge the current options with the given hash, without mutating self.
61
- #
62
- # @param hash [Hash] the hash to be merged
63
- #
64
- # @return [Hash] the result of the merging operation
65
- #
66
- # @api private
67
- # @since 0.1.1
68
- def merge(hash)
69
- @options.merge(hash)
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,48 +0,0 @@
1
- require 'hanami/routing/resource'
2
- require 'hanami/routing/resources/action'
3
-
4
- module Hanami
5
- module Routing
6
- # Set of RESTful resources routes
7
- # Implementation of Hanami::Router#resources
8
- #
9
- # @since 0.1.0
10
- #
11
- # @api private
12
- #
13
- # @see Hanami::Router#resources
14
- class Resources < Resource
15
- # Set of default routes
16
- #
17
- # @api private
18
- # @since 0.1.0
19
- self.actions = [:index, :new, :create, :show, :edit, :update, :destroy]
20
-
21
- # Action class
22
- #
23
- # @api private
24
- # @since 0.1.0
25
- self.action = Resources::Action
26
-
27
- # Member action class
28
- #
29
- # @api private
30
- # @since 0.1.0
31
- self.member = Resources::MemberAction
32
-
33
- # Collection action class
34
- #
35
- # @api private
36
- # @since 0.1.0
37
- self.collection = Resources::CollectionAction
38
-
39
- # Return wildcard param between separators
40
- #
41
- # @api private
42
- # @since 0.4.0
43
- def wildcard_param(route_param = nil)
44
- "/:#{ Hanami::Utils::String.singularize(route_param) }_id/"
45
- end
46
- end
47
- end
48
- end
@@ -1,156 +0,0 @@
1
- require 'hanami/utils/string'
2
- require 'hanami/utils/path_prefix'
3
- require 'hanami/routing/resource'
4
-
5
- module Hanami
6
- module Routing
7
- class Resources < Resource
8
- # Action for RESTful resources
9
- #
10
- # @since 0.1.0
11
- #
12
- # @api private
13
- #
14
- # @see Hanami::Router#resources
15
- class Action < Resource::Action
16
- # Ruby namespace where lookup for default subclasses.
17
- #
18
- # @api private
19
- # @since 0.1.0
20
- self.namespace = Resources
21
-
22
- # Id route variable
23
- #
24
- # @since 0.2.0
25
- # @api private
26
- class_attribute :identifier
27
- self.identifier = ':id'.freeze
28
- end
29
-
30
- # Pluralize concrete actions
31
- #
32
- # @api private
33
- # @since 0.4.0
34
- module PluralizedAction
35
- private
36
- # The name of the RESTful action.
37
- #
38
- # @api private
39
- # @since 0.4.0
40
- def as
41
- Hanami::Utils::String.pluralize(super)
42
- end
43
- end
44
-
45
- # Collection action
46
- # It implements #collection within a #resources block.
47
- #
48
- # @api private
49
- # @since 0.1.0
50
- # @see Hanami::Router#resources
51
- class CollectionAction < Resource::CollectionAction
52
- def as(action_name)
53
- Hanami::Utils::String.pluralize(super(action_name))
54
- end
55
- end
56
-
57
- # Member action
58
- # It implements #member within a #resources block.
59
- #
60
- # @api private
61
- # @since 0.1.0
62
- # @see Hanami::Router#resources
63
- class MemberAction < Resource::MemberAction
64
- private
65
- # @since 0.1.0
66
- # @api private
67
- def path(action_name)
68
- rest_path.join(Action.identifier, action_name)
69
- end
70
- end
71
-
72
- # Implementation of common methods for concrete member actions
73
- #
74
- # @api private
75
- # @since 0.1.0
76
- module DefaultMemberAction
77
- private
78
- # @since 0.1.0
79
- # @api private
80
- def path
81
- rest_path.join(Action.identifier)
82
- end
83
- end
84
-
85
- # Index action
86
- #
87
- # @api private
88
- # @since 0.1.0
89
- # @see Hanami::Router#resources
90
- class Index < Action
91
- include PluralizedAction
92
- self.verb = :get
93
- end
94
-
95
- # New action
96
- #
97
- # @api private
98
- # @since 0.1.0
99
- # @see Hanami::Router#resources
100
- class New < Resource::New
101
- end
102
-
103
- # Create action
104
- #
105
- # @api private
106
- # @since 0.1.0
107
- # @see Hanami::Router#resources
108
- class Create < Resource::Create
109
- include PluralizedAction
110
- end
111
-
112
- # Show action
113
- #
114
- # @api private
115
- # @since 0.1.0
116
- # @see Hanami::Router#resources
117
- class Show < Resource::Show
118
- include DefaultMemberAction
119
- end
120
-
121
- # Edit action
122
- #
123
- # @api private
124
- # @since 0.1.0
125
- # @see Hanami::Router#resources
126
- class Edit < Resource::Edit
127
- include DefaultMemberAction
128
-
129
- private
130
- # @since 0.1.0
131
- # @api private
132
- def path
133
- super.join(action_name)
134
- end
135
- end
136
-
137
- # Update action
138
- #
139
- # @api private
140
- # @since 0.1.0
141
- # @see Hanami::Router#resources
142
- class Update < Resource::Update
143
- include DefaultMemberAction
144
- end
145
-
146
- # Destroy action
147
- #
148
- # @api private
149
- # @since 0.1.0
150
- # @see Hanami::Router#resources
151
- class Destroy < Resource::Destroy
152
- include DefaultMemberAction
153
- end
154
- end
155
- end
156
- end
@@ -1,71 +0,0 @@
1
- require 'http_router/route'
2
-
3
- module Hanami
4
- module Routing
5
- # Entry of the routing system
6
- #
7
- # @api private
8
- #
9
- # @since 0.1.0
10
- # @api private
11
- #
12
- # @see http://rdoc.info/gems/http_router/HttpRouter/Route
13
- #
14
- # @example
15
- # require 'hanami/router'
16
- #
17
- # router = Hanami::Router.new
18
- # router.get('/', to: endpoint) # => #<Hanami::Routing::Route:0x007f83083ba028 ...>
19
- class Route < HttpRouter::Route
20
- # @since 0.7.0
21
- # @api private
22
- def initialize(*)
23
- super
24
- @name = nil
25
- end
26
-
27
- # Asks the given resolver to return an endpoint that will be associated
28
- # with the other options.
29
- #
30
- # @param resolver [Hanami::Routing::EndpointResolver, #resolve] this may change
31
- # according to the :resolve option passed to Hanami::Router#initialize.
32
- #
33
- # @param options [Hash] options to customize the route
34
- # @option options [Symbol] :as the name we want to use for the route
35
- #
36
- # @since 0.1.0
37
- #
38
- # @api private
39
- #
40
- # @see Hanami::Router#initialize
41
- #
42
- # @example
43
- # require 'hanami/router'
44
- #
45
- # router = Hanami::Router.new
46
- # router.get('/', to: endpoint, as: :home_page).name # => :home_page
47
- #
48
- # router.path(:home_page) # => '/'
49
- def generate(resolver, options = {}, &endpoint)
50
- self.to = resolver.resolve(options, &endpoint)
51
- self.name = options[:as].to_sym if options[:as]
52
- self
53
- end
54
-
55
- # Introspect the given route to understand if there is a wrapped
56
- # router that has an inspector
57
- #
58
- # @since 0.2.0
59
- # @api private
60
- def nested_router
61
- dest.routes if dest.respond_to?(:routes) && dest.routes.respond_to?(:inspector)
62
- end
63
-
64
- private
65
- # @api private
66
- def to=(dest = nil, &blk)
67
- self.to dest, &blk
68
- end
69
- end
70
- end
71
- end
@@ -1,221 +0,0 @@
1
- require 'hanami/utils/path_prefix'
2
-
3
- module Hanami
4
- module Routing
5
- # Routes inspector
6
- #
7
- # @since 0.2.0
8
- class RoutesInspector
9
- # Default route formatter
10
- #
11
- # @since 0.2.0
12
- # @api private
13
- FORMATTER = "%<name>20s %<methods>-10s %<path>-30s %<endpoint>-30s\n".freeze
14
-
15
- # Default HTTP methods separator
16
- #
17
- # @since 0.2.0
18
- # @api private
19
- HTTP_METHODS_SEPARATOR = ', '.freeze
20
-
21
- # Default inspector header hash values
22
- #
23
- # @since 0.5.0
24
- # @api private
25
- INSPECTOR_HEADER_HASH = Hash[
26
- name: 'Name',
27
- methods: 'Method',
28
- path: 'Path',
29
- endpoint: 'Action'
30
- ].freeze
31
-
32
- # Default inspector header name values
33
- #
34
- # @since 0.5.0
35
- # @api private
36
- INSPECTOR_HEADER_NAME = 'Name'.freeze
37
-
38
- # Empty line string
39
- #
40
- # @since 0.5.0
41
- # @api private
42
- EMPTY_LINE = "\n".freeze
43
-
44
- # Instantiate a new inspector
45
- #
46
- # @return [Hanami::Routing::RoutesInspector] the new instance
47
- #
48
- # @since 0.2.0
49
- # @api private
50
- def initialize(routes, prefix)
51
- @routes = routes
52
- @prefix = prefix
53
- end
54
-
55
- # Return a formatted string that describes all the routes
56
- #
57
- # @param formatter [String] the optional formatter for a route
58
- # @param base_path [String] the base path of a nested route
59
- #
60
- # @return [String] routes pretty print
61
- #
62
- # @since 0.2.0
63
- # @api private
64
- #
65
- # @see Hanami::Routing::RoutesInspector::FORMATTER
66
- #
67
- # @example Default formatter
68
- # require 'hanami/router'
69
- #
70
- # router = Hanami::Router.new do
71
- # get '/', to: 'home#index'
72
- # get '/login', to: 'sessions#new', as: :login
73
- # post '/login', to: 'sessions#create'
74
- # delete '/logout', to: 'sessions#destroy', as: :logout
75
- # end
76
- #
77
- # puts router.inspector.to_s
78
- # # => Name Method Path Action
79
- #
80
- # GET, HEAD / Home::Index
81
- # login GET, HEAD /login Sessions::New
82
- # POST /login Sessions::Create
83
- # logout GET, HEAD /logout Sessions::Destroy
84
- #
85
- # @example Custom formatter
86
- # require 'hanami/router'
87
- #
88
- # router = Hanami::Router.new do
89
- # get '/', to: 'home#index'
90
- # get '/login', to: 'sessions#new', as: :login
91
- # post '/login', to: 'sessions#create'
92
- # delete '/logout', to: 'sessions#destroy', as: :logout
93
- # end
94
- #
95
- # formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
96
- #
97
- # puts router.inspector.to_s(formatter)
98
- # # => | Method | Name | Path | Action |
99
- #
100
- # | GET, HEAD | | / | Home::Index |
101
- # | GET, HEAD | login | /login | Sessions::New |
102
- # | POST | | /login | Sessions::Create |
103
- # | GET, HEAD | logout | /logout | Sessions::Destroy |
104
- #
105
- # @example Nested routes
106
- # require 'hanami/router'
107
- #
108
- # class AdminHanamiApp
109
- # def call(env)
110
- # end
111
- # def routes
112
- # Hanami::Router.new {
113
- # get '/home', to: 'home#index'
114
- # }
115
- # end
116
- # end
117
- #
118
- # router = Hanami::Router.new {
119
- # get '/fakeroute', to: 'fake#index'
120
- # mount AdminHanamiApp, at: '/admin'
121
- # mount Hanami::Router.new {
122
- # get '/posts', to: 'posts#index'
123
- # mount Hanami::Router.new {
124
- # get '/comments', to: 'comments#index'
125
- # }, at: '/second_mount'
126
- # }, at: '/api'
127
- # }
128
- #
129
- # formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
130
- #
131
- # puts router.inspector.to_s(formatter)
132
- # # => | Method | Name | Path | Action |
133
- #
134
- # | GET, HEAD | | /fakeroute | Fake::Index |
135
- # | GET, HEAD | | /admin/home | Home::Index |
136
- # | GET, HEAD | | /api/posts | Posts::Index |
137
- # | GET, HEAD | | /api/second_mount/comments | Comments::Index |
138
- def to_s(formatter = FORMATTER, base_path = prefix)
139
- base_path = Utils::PathPrefix.new(base_path)
140
-
141
- inspect_routes(formatter, base_path)
142
- .insert(0, formatter % INSPECTOR_HEADER_HASH + EMPTY_LINE)
143
- end
144
-
145
- # Returns a string representation of routes
146
- #
147
- # @param formatter [String] the template for the output
148
- # @param base_path [Hanami::Utils::PathPrefix] the base path
149
- #
150
- # @return [String] serialized routes from router
151
- #
152
- # @since 0.5.1
153
- # @api private
154
- #
155
- # @see Hanami::Routing::RoutesInspector#FORMATTER
156
- # @see Hanami::Routing::RoutesInspector#to_s
157
- def inspect_routes(formatter, base_path)
158
- result = ''
159
-
160
- # TODO refactoring: replace conditional with polymorphism
161
- # We're exposing too much knowledge from Routing::Route:
162
- # #path_for_generation and #base_path
163
- @routes.each do |route|
164
- result << if router = route.nested_router
165
- inspect_router(formatter, router, route, base_path)
166
- else
167
- inspect_route(formatter, route, base_path)
168
- end
169
- end
170
-
171
- result
172
- end
173
-
174
- private
175
-
176
- # @since 0.8.0
177
- # @api private
178
- attr_reader :prefix
179
-
180
- # Returns a string representation of the given route
181
- #
182
- # @param formatter [String] the template for the output
183
- # @param route [Hanami::Routing::Route] a route
184
- # @param base_path [Hanami::Utils::PathPrefix] the base path
185
- #
186
- # @return [String] serialized route
187
- #
188
- # @since 0.2.0
189
- # @api private
190
- #
191
- # @see Hanami::Routing::RoutesInspector#FORMATTER
192
- # @see Hanami::Routing::RoutesInspector#to_s
193
- def inspect_route(formatter, route, base_path)
194
- formatter % Hash[
195
- name: route.name,
196
- methods: route.request_methods.to_a.join(HTTP_METHODS_SEPARATOR),
197
- path: base_path.join(route.path_for_generation),
198
- endpoint: route.dest.inspect
199
- ]
200
- end
201
-
202
- # Returns a string representation of the given router
203
- #
204
- # @param formatter [String] the template for the output
205
- # @param router [Hanami::Router] a router
206
- # @param route [Hanami::Routing::Route] a route
207
- # @param base_path [Hanami::Utils::PathPrefix] the base path
208
- #
209
- # @return [String] serialized routes from router
210
- #
211
- # @since 0.2.0
212
- # @api private
213
- #
214
- # @see Hanami::Routing::RoutesInspector#FORMATTER
215
- # @see Hanami::Routing::RoutesInspector#to_s
216
- def inspect_router(formatter, router, route, base_path)
217
- router.inspector.inspect_routes(formatter, base_path.join(route.path_for_generation))
218
- end
219
- end
220
- end
221
- end