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
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mustermann/rails"
4
+
5
+ module Hanami
6
+ class Router
7
+ # Route path
8
+ #
9
+ # @since 2.0.0
10
+ # @api private
11
+ class Segment
12
+ # @since 2.0.0
13
+ # @api private
14
+ def self.fabricate(segment, **constraints)
15
+ Mustermann.new(segment, type: :rails, version: "5.0", capture: constraints)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/router/node"
4
+
5
+ module Hanami
6
+ class Router
7
+ # Trie data structure to store routes
8
+ #
9
+ # @api private
10
+ # @since 2.0.0
11
+ class Trie
12
+ # @api private
13
+ # @since 2.0.0
14
+ attr_reader :root
15
+
16
+ # @api private
17
+ # @since 2.0.0
18
+ def initialize
19
+ @root = Node.new
20
+ end
21
+
22
+ # @api private
23
+ # @since 2.0.0
24
+ def add(path, to, constraints)
25
+ node = @root
26
+ for_each_segment(path) do |segment|
27
+ node = node.put(segment, constraints)
28
+ end
29
+
30
+ node.leaf!(to)
31
+ end
32
+
33
+ # @api private
34
+ # @since 2.0.0
35
+ def find(path)
36
+ node = @root
37
+ params = {}
38
+
39
+ for_each_segment(path) do |segment|
40
+ break unless node
41
+
42
+ child, captures = node.get(segment)
43
+ params.merge!(captures) if captures
44
+
45
+ node = child
46
+ end
47
+
48
+ return [node.to, params] if node&.leaf?
49
+
50
+ nil
51
+ end
52
+
53
+ private
54
+
55
+ # @api private
56
+ # @since 2.0.0
57
+ def for_each_segment(path, &blk)
58
+ _, *segments = path.split(/\//)
59
+ segments.each(&blk)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/router/error"
4
+ require "mustermann/error"
5
+
6
+ module Hanami
7
+ class Router
8
+ # URL Helpers
9
+ class UrlHelpers
10
+ # @since 2.0.0
11
+ # @api private
12
+ def initialize(base_url)
13
+ @base_url = base_url
14
+ @named = {}
15
+ end
16
+
17
+ # @since 2.0.0
18
+ # @api private
19
+ def add(name, segment)
20
+ @named[name] = segment
21
+ end
22
+
23
+ # @since 2.0.0
24
+ # @api public
25
+ def path(name, variables = {})
26
+ @named.fetch(name.to_sym) do
27
+ raise InvalidRouteException.new(name)
28
+ end.expand(:append, variables)
29
+ rescue Mustermann::ExpandError => exception
30
+ raise InvalidRouteExpansionException.new(name, exception.message)
31
+ end
32
+
33
+ # @since 2.0.0
34
+ # @api public
35
+ def url(name, variables = {})
36
+ @base_url + path(name, variables)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  class Router
3
5
  # @since 0.1.0
4
- VERSION = '1.3.1'.freeze
6
+ # @api public
7
+ VERSION = "2.0.0.alpha4"
5
8
  end
6
9
  end
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: 1.3.1
4
+ version: 2.0.0.alpha4
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: 2019-01-18 00:00:00.000000000 Z
11
+ date: 2021-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -25,33 +25,33 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: http_router
28
+ name: mustermann
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.11.2
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.11.2
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: hanami-utils
42
+ name: mustermann-contrib
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.3'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.3'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '12'
81
+ version: '13'
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '12'
88
+ version: '13'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rack-test
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +106,42 @@ dependencies:
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '3.7'
109
+ version: '3.8'
110
110
  type: :development
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '3.7'
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: '0.91'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '='
129
+ - !ruby/object:Gem::Version
130
+ version: '0.91'
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.8.1
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '='
143
+ - !ruby/object:Gem::Version
144
+ version: 1.8.1
117
145
  description: Rack compatible HTTP router for Ruby
118
146
  email:
119
147
  - me@lucaguidi.com
@@ -125,37 +153,29 @@ files:
125
153
  - LICENSE.md
126
154
  - README.md
127
155
  - hanami-router.gemspec
128
- - lib/hanami-router.rb
129
156
  - lib/hanami/middleware/body_parser.rb
130
157
  - lib/hanami/middleware/body_parser/class_interface.rb
131
158
  - lib/hanami/middleware/body_parser/errors.rb
132
159
  - lib/hanami/middleware/body_parser/json_parser.rb
160
+ - lib/hanami/middleware/body_parser/parser.rb
161
+ - lib/hanami/middleware/error.rb
133
162
  - lib/hanami/router.rb
163
+ - lib/hanami/router/block.rb
164
+ - lib/hanami/router/error.rb
165
+ - lib/hanami/router/node.rb
166
+ - lib/hanami/router/params.rb
167
+ - lib/hanami/router/prefix.rb
168
+ - lib/hanami/router/recognized_route.rb
169
+ - lib/hanami/router/redirect.rb
170
+ - lib/hanami/router/segment.rb
171
+ - lib/hanami/router/trie.rb
172
+ - lib/hanami/router/url_helpers.rb
134
173
  - lib/hanami/router/version.rb
135
- - lib/hanami/routing/endpoint.rb
136
- - lib/hanami/routing/endpoint_resolver.rb
137
- - lib/hanami/routing/error.rb
138
- - lib/hanami/routing/force_ssl.rb
139
- - lib/hanami/routing/http_router.rb
140
- - lib/hanami/routing/http_router_monkey_patch.rb
141
- - lib/hanami/routing/namespace.rb
142
- - lib/hanami/routing/parsers.rb
143
- - lib/hanami/routing/parsing/json_parser.rb
144
- - lib/hanami/routing/parsing/parser.rb
145
- - lib/hanami/routing/recognized_route.rb
146
- - lib/hanami/routing/resource.rb
147
- - lib/hanami/routing/resource/action.rb
148
- - lib/hanami/routing/resource/nested.rb
149
- - lib/hanami/routing/resource/options.rb
150
- - lib/hanami/routing/resources.rb
151
- - lib/hanami/routing/resources/action.rb
152
- - lib/hanami/routing/route.rb
153
- - lib/hanami/routing/routes_inspector.rb
154
174
  homepage: http://hanamirb.org
155
175
  licenses:
156
176
  - MIT
157
177
  metadata: {}
158
- post_install_message:
178
+ post_install_message:
159
179
  rdoc_options: []
160
180
  require_paths:
161
181
  - lib
@@ -163,15 +183,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
183
  requirements:
164
184
  - - ">="
165
185
  - !ruby/object:Gem::Version
166
- version: 2.3.0
186
+ version: 2.6.0
167
187
  required_rubygems_version: !ruby/object:Gem::Requirement
168
188
  requirements:
169
- - - ">="
189
+ - - ">"
170
190
  - !ruby/object:Gem::Version
171
- version: '0'
191
+ version: 1.3.1
172
192
  requirements: []
173
- rubygems_version: 3.0.2
174
- signing_key:
193
+ rubygems_version: 3.2.4
194
+ signing_key:
175
195
  specification_version: 4
176
196
  summary: Rack compatible HTTP router for Ruby and Hanami
177
197
  test_files: []
@@ -1 +0,0 @@
1
- require 'hanami/router'
@@ -1,195 +0,0 @@
1
- require 'delegate'
2
- require 'hanami/routing/error'
3
- require 'hanami/utils/class'
4
-
5
- module Hanami
6
- module Routing
7
- # Endpoint not found
8
- # This is raised when the router fails to load an endpoint at the runtime.
9
- #
10
- # @since 0.1.0
11
- class EndpointNotFound < Hanami::Routing::Error
12
- end
13
-
14
- # Routing endpoint
15
- # This is the object that responds to an HTTP request made against a certain
16
- # path.
17
- #
18
- # The router will use this class for:
19
- #
20
- # * Procs and any Rack compatible object (respond to #call)
21
- #
22
- # @since 0.1.0
23
- #
24
- # @api private
25
- #
26
- # @example
27
- # require 'hanami/router'
28
- #
29
- # Hanami::Router.new do
30
- # get '/proc', to: ->(env) { [200, {}, ['This will use Hanami::Routing::Endpoint']] }
31
- # get '/rack-app', to: RackApp.new
32
- # end
33
- class Endpoint < SimpleDelegator
34
- # @since 0.2.0
35
- # @api private
36
- def inspect
37
- case __getobj__
38
- when Proc
39
- source, line = __getobj__.source_location
40
- lambda_inspector = " (lambda)" if __getobj__.lambda?
41
-
42
- "#<Proc@#{ ::File.expand_path(source) }:#{ line }#{ lambda_inspector }>"
43
- when Class
44
- __getobj__
45
- else
46
- "#<#{ __getobj__.class }>"
47
- end
48
- end
49
-
50
- # @since 1.0.0
51
- # @api private
52
- def routable?
53
- !__getobj__.nil?
54
- rescue ArgumentError
55
- end
56
-
57
- # @since 1.0.1
58
- # @api private
59
- def redirect?
60
- false
61
- end
62
-
63
- # @since 1.0.1
64
- # @api private
65
- def destination_path
66
- end
67
- end
68
-
69
- # Routing endpoint
70
- # This is the object that responds to an HTTP request made against a certain
71
- # path.
72
- #
73
- # The router will use this class for:
74
- #
75
- # * Classes
76
- # * Hanami::Action endpoints referenced as a class
77
- # * Hanami::Action endpoints referenced a string
78
- # * RESTful resource(s)
79
- #
80
- # @since 0.1.0
81
- #
82
- # @api private
83
- #
84
- # @example
85
- # require 'hanami/router'
86
- #
87
- # Hanami::Router.new do
88
- # get '/class', to: RackMiddleware
89
- # get '/hanami-action-class', to: Dashboard::Index
90
- # get '/hanami-action-string', to: 'dashboard#index'
91
- #
92
- # resource 'identity'
93
- # resources 'articles'
94
- # end
95
- class ClassEndpoint < Endpoint
96
- # Rack interface
97
- #
98
- # @since 0.1.0
99
- # @api private
100
- def call(env)
101
- __getobj__.new.call(env)
102
- end
103
- end
104
-
105
- # Routing endpoint
106
- # This is the object that responds to an HTTP request made against a certain
107
- # path.
108
- #
109
- # The router will use this class for the same use cases of `ClassEndpoint`,
110
- # but when the target class can't be found, instead of raise a `LoadError`
111
- # we reference in a lazy endpoint.
112
- #
113
- # For each incoming HTTP request, it will look for the referenced class,
114
- # then it will instantiate and invoke #call on the object.
115
- #
116
- # This behavior is required to solve a chicken-egg situation when we try
117
- # to load the router first and then the application with all its endpoints.
118
- #
119
- # @since 0.1.0
120
- #
121
- # @api private
122
- #
123
- # @see Hanami::Routing::ClassEndpoint
124
- class LazyEndpoint < Endpoint
125
- # Initialize the lazy endpoint
126
- #
127
- # @since 0.1.0
128
- # @api private
129
- def initialize(name, namespace)
130
- @name, @namespace = name, namespace
131
- end
132
-
133
- # Rack interface
134
- #
135
- # @raise [EndpointNotFound] when the endpoint can't be found.
136
- #
137
- # @since 0.1.0
138
- # @api private
139
- def call(env)
140
- obj.call(env)
141
- end
142
-
143
- # @since 0.2.0
144
- # @api private
145
- def inspect
146
- # TODO review this implementation once the namespace feature will be
147
- # cleaned up.
148
- result = klass rescue nil
149
-
150
- if result.nil?
151
- result = @name
152
- result = "#{ @namespace }::#{ result }" if @namespace != Object
153
- end
154
-
155
- result
156
- end
157
-
158
- private
159
- # @since 0.1.0
160
- # @api private
161
- def obj
162
- klass.new
163
- end
164
-
165
- # @since 0.2.0
166
- # @api private
167
- def klass
168
- Utils::Class.load!(@name, @namespace)
169
- rescue NameError => e
170
- raise EndpointNotFound.new(e.message)
171
- end
172
- end
173
-
174
- # @since 1.0.1
175
- # @api private
176
- class RedirectEndpoint < Endpoint
177
- # @since 1.0.1
178
- # @api private
179
- attr_reader :destination_path
180
-
181
- # @since 1.0.1
182
- # @api private
183
- def initialize(destination_path, destination)
184
- @destination_path = destination_path
185
- super(destination)
186
- end
187
-
188
- # @since 1.0.1
189
- # @api private
190
- def redirect?
191
- true
192
- end
193
- end
194
- end
195
- end