hanami-router 2.0.0.alpha1 → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -3,6 +3,7 @@
3
3
  module Hanami
4
4
  class Router
5
5
  # @since 0.1.0
6
- VERSION = "2.0.0.alpha1"
6
+ # @api public
7
+ VERSION = "2.0.0.alpha2"
7
8
  end
8
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: 2.0.0.alpha1
4
+ version: 2.0.0.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-30 00:00:00.000000000 Z
11
+ date: 2020-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -52,34 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.0'
55
- - !ruby/object:Gem::Dependency
56
- name: hanami-utils
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 2.0.alpha
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 2.0.alpha
69
- - !ruby/object:Gem::Dependency
70
- name: dry-inflector
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '0.1'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '0.1'
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: bundler
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +78,14 @@ dependencies:
106
78
  requirements:
107
79
  - - "~>"
108
80
  - !ruby/object:Gem::Version
109
- version: '12'
81
+ version: '13'
110
82
  type: :development
111
83
  prerelease: false
112
84
  version_requirements: !ruby/object:Gem::Requirement
113
85
  requirements:
114
86
  - - "~>"
115
87
  - !ruby/object:Gem::Version
116
- version: '12'
88
+ version: '13'
117
89
  - !ruby/object:Gem::Dependency
118
90
  name: rack-test
119
91
  requirement: !ruby/object:Gem::Requirement
@@ -134,14 +106,14 @@ dependencies:
134
106
  requirements:
135
107
  - - "~>"
136
108
  - !ruby/object:Gem::Version
137
- version: '3.7'
109
+ version: '3.8'
138
110
  type: :development
139
111
  prerelease: false
140
112
  version_requirements: !ruby/object:Gem::Requirement
141
113
  requirements:
142
114
  - - "~>"
143
115
  - !ruby/object:Gem::Version
144
- version: '3.7'
116
+ version: '3.8'
145
117
  description: Rack compatible HTTP router for Ruby
146
118
  email:
147
119
  - me@lucaguidi.com
@@ -159,20 +131,17 @@ files:
159
131
  - lib/hanami/middleware/body_parser/json_parser.rb
160
132
  - lib/hanami/middleware/error.rb
161
133
  - lib/hanami/router.rb
134
+ - lib/hanami/router/block.rb
135
+ - lib/hanami/router/error.rb
136
+ - lib/hanami/router/node.rb
137
+ - lib/hanami/router/params.rb
138
+ - lib/hanami/router/prefix.rb
139
+ - lib/hanami/router/recognized_route.rb
140
+ - lib/hanami/router/redirect.rb
141
+ - lib/hanami/router/segment.rb
142
+ - lib/hanami/router/trie.rb
143
+ - lib/hanami/router/url_helpers.rb
162
144
  - lib/hanami/router/version.rb
163
- - lib/hanami/routing.rb
164
- - lib/hanami/routing/endpoint.rb
165
- - lib/hanami/routing/endpoint_resolver.rb
166
- - lib/hanami/routing/prefix.rb
167
- - lib/hanami/routing/recognized_route.rb
168
- - lib/hanami/routing/resource.rb
169
- - lib/hanami/routing/resource/action.rb
170
- - lib/hanami/routing/resource/nested.rb
171
- - lib/hanami/routing/resource/options.rb
172
- - lib/hanami/routing/resources.rb
173
- - lib/hanami/routing/resources/action.rb
174
- - lib/hanami/routing/routes_inspector.rb
175
- - lib/hanami/routing/scope.rb
176
145
  homepage: http://hanamirb.org
177
146
  licenses:
178
147
  - MIT
@@ -192,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
161
  - !ruby/object:Gem::Version
193
162
  version: 1.3.1
194
163
  requirements: []
195
- rubygems_version: 3.0.2
164
+ rubygems_version: 3.1.2
196
165
  signing_key:
197
166
  specification_version: 4
198
167
  summary: Rack compatible HTTP router for Ruby and Hanami
@@ -1,193 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "uri"
4
- require "rack/utils"
5
- require "mustermann/rails"
6
-
7
- # Hanami
8
- #
9
- # @since 0.1.0
10
- module Hanami
11
- # Hanami routing
12
- #
13
- # @since 0.1.0
14
- module Routing
15
- PATH_INFO = "PATH_INFO"
16
- QUERY_STRING = "QUERY_STRING"
17
- REQUEST_METHOD = "REQUEST_METHOD"
18
-
19
- HTTP_VERBS = %w[get post delete put patch trace options link unlink].freeze
20
-
21
- PARAMS = "router.params"
22
-
23
- def self.http_verbs
24
- HTTP_VERBS
25
- end
26
-
27
- # @since 0.5.0
28
- class Error < ::StandardError
29
- end
30
-
31
- # Invalid route
32
- # This is raised when the router fails to recognize a route, because of the
33
- # given arguments.
34
- #
35
- # @since 0.1.0
36
- class InvalidRouteException < Error
37
- end
38
-
39
- # Endpoint not found
40
- # This is raised when the router fails to load an endpoint at the runtime.
41
- #
42
- # @since 0.1.0
43
- class EndpointNotFound < Error
44
- end
45
-
46
- # @since 2.0.0
47
- class NotCallableEndpointError < Error
48
- def initialize(endpoint)
49
- super("#{endpoint.inspect} isn't compatible with Rack. Please make sure it implements #call.")
50
- end
51
- end
52
-
53
- # HTTP redirect
54
- #
55
- # @since 2.0.0
56
- # @api private
57
- class Redirect
58
- # @since 2.0.0
59
- # @api private
60
- LOCATION = "Location"
61
-
62
- # @since 2.0.0
63
- # @api private
64
- STATUS_RANGE = (300..399).freeze
65
-
66
- attr_reader :path
67
- alias destination_path path
68
-
69
- # Instantiate a new redirect
70
- #
71
- # @param path [String] a relative or absolute URI
72
- # @param status [Integer] a redirect status (an integer between `300` and `399`)
73
- #
74
- # @return [Hanami::Routing::Redirect] a new instance
75
- #
76
- # @raise [ArgumentError] if path is nil, or status code isn't a redirect
77
- #
78
- # @since 2.0.0
79
- # @api private
80
- def initialize(path, status)
81
- raise ArgumentError.new("Path is nil") if path.nil?
82
- raise ArgumentError.new("Status code isn't a redirect: #{status.inspect}") unless STATUS_RANGE.include?(status)
83
-
84
- @path = path
85
- @status = status
86
- freeze
87
- end
88
-
89
- def call(*)
90
- [@status, { LOCATION => @path }, []]
91
- end
92
-
93
- def redirect?
94
- true
95
- end
96
- end
97
-
98
- # Route
99
- #
100
- # @since 0.1.0
101
- # @api private
102
- class Route
103
- # @since 0.7.0
104
- # @api private
105
- def initialize(verb, path, endpoint, constraints)
106
- @verb = verb
107
- @path = Mustermann.new(path, type: :rails, version: "5.0", capture: constraints)
108
- @endpoint = endpoint
109
- freeze
110
- end
111
-
112
- # @since 0.1.0
113
- # @api private
114
- def call(env)
115
- env[PARAMS] ||= {}
116
- env[PARAMS].merge!(Rack::Utils.parse_nested_query(env[QUERY_STRING]))
117
- env[PARAMS].merge!(@path.params(env[PATH_INFO]))
118
- env[PARAMS] = Utils::Hash.deep_symbolize(env[PARAMS])
119
-
120
- @endpoint.call(env)
121
- end
122
-
123
- # @since 0.1.0
124
- # @api private
125
- def path(args)
126
- @path.expand(:append, args)
127
- rescue Mustermann::ExpandError => e
128
- raise Hanami::Routing::InvalidRouteException.new(e.message)
129
- end
130
-
131
- # @since 2.0.0
132
- # @api private
133
- def match?(env)
134
- match_path?(env) &&
135
- @verb.include?(env[REQUEST_METHOD])
136
- end
137
-
138
- # @since 2.0.0
139
- # @api private
140
- def match_path?(env)
141
- @path =~ env[PATH_INFO]
142
- end
143
- end
144
-
145
- # @since 2.0.0
146
- # @api private
147
- module Uri
148
- # @since 2.0.0
149
- # @api private
150
- HTTP = "http"
151
-
152
- # @since 2.0.0
153
- # @api private
154
- HTTPS = "https"
155
-
156
- # @since 2.0.0
157
- # @api private
158
- DEFAULT_SCHEME = HTTP
159
-
160
- # Build a URI string from the given arguments
161
- #
162
- # @param scheme [String] the URI scheme: one of `"http"` or `"https"`
163
- # @param host [String] the URI host
164
- # @param port [String,Integer] the URI port
165
- #
166
- # @raise [ArgumentError] if one of `scheme`, `host`, `port` is `nil`, or
167
- # if `scheme` is unknown
168
- #
169
- # @since 2.0.0
170
- # @api private
171
- def self.build(scheme:, host:, port:)
172
- raise ArgumentError.new("host is nil") if host.nil?
173
- raise ArgumentError.new("port is nil") if port.nil?
174
-
175
- case scheme
176
- when HTTP
177
- URI::HTTP
178
- when HTTPS
179
- URI::HTTPS
180
- else
181
- raise ArgumentError.new("Unknown scheme: #{scheme.inspect}")
182
- end.build(scheme: scheme, host: host, port: port).to_s
183
- end
184
- end
185
-
186
- require "hanami/routing/endpoint"
187
- require "hanami/routing/prefix"
188
- require "hanami/routing/scope"
189
- require "hanami/routing/resource"
190
- require "hanami/routing/resources"
191
- require "hanami/routing/recognized_route"
192
- end
193
- end