hanami-router 1.3.1 → 2.0.0.alpha4

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.
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