rack-jet_router 1.0.1 → 1.1.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/README.md +63 -27
- data/lib/rack/jet_router.rb +76 -44
- data/rack-jet_router.gemspec +1 -1
- data/test/rack/jet_router_test.rb +94 -42
- metadata +17 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da49b22574962dc8935525feba719fd735003f43
|
4
|
+
data.tar.gz: 9fa472683f55e9b366cc46b5f4f984295dffdf66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0e12966a998ba92c5c9edbeefa549ba2985650a2d4a164c5e0c0a23487b6622695cb4beab2c55af60e8269f579a97dcb84150386d1e972a1cd9b7aefaa1c75f
|
7
|
+
data.tar.gz: 6dfec9e6f75093ce20bdaefdd3ddac9dbd27fd5f5711f64d9bd44982bb7e58337d09604f552828d2ac76888cc5d545e0859701e64f3ce12d6d1eb1df820e8ef1
|
data/README.md
CHANGED
@@ -1,32 +1,59 @@
|
|
1
1
|
# Rack::JetRouter
|
2
2
|
|
3
|
+
($Release: 0.0.0 $)
|
4
|
+
|
3
5
|
Rack::JetRouter is crazy-fast router library for Rack application,
|
4
6
|
derived from [Keight.rb](https://github.com/kwatch/keight/tree/ruby).
|
5
7
|
|
8
|
+
Rack::JetRouter requires Ruby >= 2.0.
|
9
|
+
|
6
10
|
|
7
11
|
## Benchmark
|
8
12
|
|
9
13
|
Benchmark script is [here](https://github.com/kwatch/rack-jet_router/blob/dev/bench/bench.rb).
|
10
14
|
|
15
|
+
### JetRouter vs. Rack vs. Sinatra vs. Keight.rb:
|
16
|
+
|
11
17
|
```
|
12
|
-
## Ranking
|
13
|
-
(Rack plain) /api/
|
14
|
-
(
|
15
|
-
(
|
16
|
-
(R::Req+Res) /api/
|
17
|
-
(
|
18
|
-
(
|
18
|
+
## Ranking usec/req Graph (longer=faster)
|
19
|
+
(Rack plain) /api/aaa01 1.0619 ***************
|
20
|
+
(Rack plain) /api/aaa01/123 0.8729 ******************
|
21
|
+
(R::Req+Res) /api/aaa01 9.5361 **
|
22
|
+
(R::Req+Res) /api/aaa01/123 9.5321 **
|
23
|
+
(JetRouter) /api/aaa01 1.3231 ************
|
24
|
+
(JetRouter) /api/aaa01/123 5.9796 ***
|
25
|
+
(Keight.rb) /api/aaa01 6.4314 **
|
26
|
+
(Keight.rb) /api/aaa01/123 10.2339 **
|
27
|
+
(Sinatra) /api/aaa01 104.7575
|
28
|
+
(Sinatra) /api/aaa01/123 115.8220
|
19
29
|
```
|
20
30
|
|
21
31
|
* If URL path has no path parameter (such as `/api/hello`),
|
22
|
-
Rack::JetRouter is
|
32
|
+
Rack::JetRouter is a litte shower than plain Rack application.
|
23
33
|
* If URL path contains path parameter (such as `/api/hello/:id`),
|
24
|
-
Rack::JetRouter becomes slower, but it is enough small (about
|
25
|
-
* Overhead of Rack::JetRouter is smaller than that of Rack::
|
34
|
+
Rack::JetRouter becomes slower, but it is enough small (about 6usec/req).
|
35
|
+
* Overhead of Rack::JetRouter is smaller than that of Rack::Reqeuast +
|
26
36
|
Rack::Response.
|
27
37
|
* Sinatra is too slow.
|
28
38
|
|
29
39
|
|
40
|
+
### JetRouter vs. Rack::Multiplexer:
|
41
|
+
|
42
|
+
```
|
43
|
+
## Ranking usec/req Graph (longer=faster)
|
44
|
+
(JetRouter) /api/aaa01 1.3231 ************
|
45
|
+
(JetRouter) /api/aaa01/123 5.9796 ***
|
46
|
+
(JetRouter) /api/zzz26 1.4089 ***********
|
47
|
+
(JetRouter) /api/zzz26/789 6.5142 **
|
48
|
+
(Multiplexer) /api/aaa01 5.9073 ***
|
49
|
+
(Multiplexer) /api/aaa01/123 18.2102 *
|
50
|
+
(Multiplexer) /api/zzz26 24.4013 *
|
51
|
+
(Multiplexer) /api/zzz26/789 36.1558
|
52
|
+
```
|
53
|
+
|
54
|
+
* JetRouter is about 3~5 times faster than Rack::Multiplexer.
|
55
|
+
|
56
|
+
|
30
57
|
## Examples
|
31
58
|
|
32
59
|
### #1: Depends only on Request Path
|
@@ -38,7 +65,7 @@ require 'rack'
|
|
38
65
|
require 'rack/jet_router'
|
39
66
|
|
40
67
|
## Assume that welcome_app, books_api, ... are Rack application.
|
41
|
-
|
68
|
+
mapping = [
|
42
69
|
['/' , welcome_app],
|
43
70
|
['/api', [
|
44
71
|
['/books', [
|
@@ -52,9 +79,9 @@ urlpath_mapping = [
|
|
52
79
|
]],
|
53
80
|
]
|
54
81
|
|
55
|
-
router = Rack::JetRouter.new(
|
56
|
-
p router.
|
57
|
-
#=> [book_api, {"id"=>"123", "format"=>"
|
82
|
+
router = Rack::JetRouter.new(mapping)
|
83
|
+
p router.lookup('/api/books/123.json')
|
84
|
+
#=> [book_api, {"id"=>"123", "format"=>"json"}]
|
58
85
|
|
59
86
|
status, headers, body = router.call(env)
|
60
87
|
```
|
@@ -69,7 +96,7 @@ require 'rack'
|
|
69
96
|
require 'rack/jet_router'
|
70
97
|
|
71
98
|
## Assume that welcome_app, book_list_api, ... are Rack application.
|
72
|
-
|
99
|
+
mapping = [
|
73
100
|
['/' , {GET: welcome_app}],
|
74
101
|
['/api', [
|
75
102
|
['/books', [
|
@@ -83,8 +110,8 @@ urlpath_mapping = [
|
|
83
110
|
]],
|
84
111
|
]
|
85
112
|
|
86
|
-
router = Rack::JetRouter.new(
|
87
|
-
p router.
|
113
|
+
router = Rack::JetRouter.new(mapping)
|
114
|
+
p router.lookup('/api/books/123')
|
88
115
|
#=> [{"GET"=>book_show_api, "PUT"=>book_update_api}, {"id"=>"123", "format"=>nil}]
|
89
116
|
|
90
117
|
status, headers, body = router.call(env)
|
@@ -118,7 +145,7 @@ class BooksAPI < API
|
|
118
145
|
def delete(id: nil); ....; end
|
119
146
|
end
|
120
147
|
|
121
|
-
|
148
|
+
mapping = [
|
122
149
|
['/api', [
|
123
150
|
['/books', [
|
124
151
|
['' , {GET: [BooksAPI, :index],
|
@@ -129,11 +156,10 @@ urlpath_mapping = [
|
|
129
156
|
]],
|
130
157
|
]],
|
131
158
|
]
|
132
|
-
router = Rack::JetRouter.new(
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
dict, args = router.find('/api/books/123')
|
159
|
+
router = Rack::JetRouter.new(mapping)
|
160
|
+
dict, args = router.lookup('/api/books/123')
|
161
|
+
p dict #=> {"GET"=>[BooksAPI, :show], "PUT"=>[...], "DELETE"=>[...]}
|
162
|
+
p args #=> {"id"=>"123"}
|
137
163
|
klass, action = dict["GET"]
|
138
164
|
handler = klass.new(Rack::Request.new(env), Rack::Response.new)
|
139
165
|
handler.__send__(action, args)
|
@@ -145,8 +171,8 @@ handler.__send__(action, args)
|
|
145
171
|
|
146
172
|
### URL Path Parameters
|
147
173
|
|
148
|
-
URL path parameters (such as `{"id"=>"123"}`)
|
149
|
-
`env['rack.urlpath_params']`.
|
174
|
+
In Rack application, URL path parameters (such as `{"id"=>"123"}`) are
|
175
|
+
available via `env['rack.urlpath_params']`.
|
150
176
|
|
151
177
|
```ruby
|
152
178
|
BookApp = proc {|env|
|
@@ -175,7 +201,7 @@ end
|
|
175
201
|
|
176
202
|
### Variable URL Path Cache
|
177
203
|
|
178
|
-
It is
|
204
|
+
It is useful to classify URL path patterns into two types: fixed and variable.
|
179
205
|
|
180
206
|
* **Fixed URL path pattern** doesn't contain any urlpath paramters.<br>
|
181
207
|
Example: `/`, `/login`, `/api/books`
|
@@ -189,7 +215,7 @@ as well as fixed ones. It will make routing much faster.
|
|
189
215
|
```ruby
|
190
216
|
## Enable variable urlpath cache.
|
191
217
|
router = Rack::JetRouter.new(urlpath_mapping, urlpath_cache_size: 200)
|
192
|
-
p router.
|
218
|
+
p router.lookup('/api/books/123') # caches even varaible urlpath
|
193
219
|
```
|
194
220
|
|
195
221
|
|
@@ -226,6 +252,16 @@ $License: MIT License $
|
|
226
252
|
## History
|
227
253
|
|
228
254
|
|
255
|
+
### 2015-12-28: Release 1.1.0
|
256
|
+
|
257
|
+
* **NOTICE** `Rack::JetRouter#find()` is renamed to `#lookup()`.<br>
|
258
|
+
`#find()` is also available for compatibility, but not recommended.
|
259
|
+
* Performance improved when number of URL path parameter is 1.
|
260
|
+
* Regular expression generated is improved.
|
261
|
+
* Benchmark script is improved to take some command-line options.
|
262
|
+
* Document fixed.
|
263
|
+
|
264
|
+
|
229
265
|
### 2015-12-06: Release 1.0.1
|
230
266
|
|
231
267
|
* Fix document
|
data/lib/rack/jet_router.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
###
|
4
|
-
### $Release: 1.0
|
4
|
+
### $Release: 1.1.0 $
|
5
5
|
### $Copyright: copyright(c) 2015 kuwata-lab.com all rights reserved $
|
6
6
|
### $License: MIT License $
|
7
7
|
###
|
@@ -30,7 +30,7 @@ module Rack
|
|
30
30
|
## ]],
|
31
31
|
## ]
|
32
32
|
## router = Rack::JetRouter.new(urlpath_mapping)
|
33
|
-
## router.
|
33
|
+
## router.lookup('/api/books/123.html')
|
34
34
|
## #=> [book_api, {"id"=>"123", "format"=>"html"}]
|
35
35
|
## status, headers, body = router.call(env)
|
36
36
|
##
|
@@ -49,13 +49,17 @@ module Rack
|
|
49
49
|
## ]],
|
50
50
|
## ]
|
51
51
|
## router = Rack::JetRouter.new(urlpath_mapping)
|
52
|
-
## router.
|
52
|
+
## router.lookup('/api/books/123')
|
53
53
|
## #=> [{"GET"=>book_show_api, "PUT"=>book_update_api}, {"id"=>"123", "format"=>nil}]
|
54
54
|
## status, headers, body = router.call(env)
|
55
55
|
##
|
56
56
|
class JetRouter
|
57
57
|
|
58
|
-
|
58
|
+
RELEASE = '$Release: 1.1.0 $'.split()[1]
|
59
|
+
|
60
|
+
def initialize(mapping, urlpath_cache_size: 0,
|
61
|
+
enable_urlpath_param_range: true)
|
62
|
+
@enable_urlpath_param_range = enable_urlpath_param_range
|
59
63
|
#; [!u2ff4] compiles urlpath mapping.
|
60
64
|
(@urlpath_rexp, # ex: {'/api/books'=>BooksApp}
|
61
65
|
@fixed_urlpath_dict, # ex: [[%r'\A/api/books/([^./]+)\z', ['id'], BookApp]]
|
@@ -70,12 +74,12 @@ module Rack
|
|
70
74
|
def call(env)
|
71
75
|
#; [!fpw8x] finds mapped app according to env['PATH_INFO'].
|
72
76
|
req_path = env['PATH_INFO']
|
73
|
-
app, urlpath_params =
|
77
|
+
app, urlpath_params = lookup(req_path)
|
74
78
|
#; [!wxt2g] guesses correct urlpath and redirects to it automaticaly when request path not found.
|
75
79
|
#; [!3vsua] doesn't redict automatically when request path is '/'.
|
76
80
|
unless app || req_path == '/'
|
77
81
|
location = req_path =~ /\/\z/ ? req_path[0..-2] : req_path + '/'
|
78
|
-
app, urlpath_params =
|
82
|
+
app, urlpath_params = lookup(location)
|
79
83
|
return redirect_to(location) if app
|
80
84
|
end
|
81
85
|
#; [!30x0k] returns 404 when request urlpath not found.
|
@@ -100,8 +104,8 @@ module Rack
|
|
100
104
|
## Finds app or Hash mapped to request path.
|
101
105
|
##
|
102
106
|
## ex:
|
103
|
-
##
|
104
|
-
def
|
107
|
+
## lookup('/api/books/123') #=> [BookApp, {"id"=>"123"}]
|
108
|
+
def lookup(req_path)
|
105
109
|
#; [!24khb] finds in fixed urlpaths at first.
|
106
110
|
#; [!iwyzd] urlpath param value is nil when found in fixed urlpaths.
|
107
111
|
obj = @fixed_urlpath_dict[req_path]
|
@@ -119,9 +123,15 @@ module Rack
|
|
119
123
|
index = m.captures.find_index('')
|
120
124
|
return nil unless index
|
121
125
|
#; [!ijqws] returns mapped object and urlpath parameter values when urlpath found.
|
122
|
-
full_urlpath_rexp, param_names, obj = @variable_urlpath_list[index]
|
123
|
-
|
124
|
-
|
126
|
+
full_urlpath_rexp, param_names, obj, range = @variable_urlpath_list[index]
|
127
|
+
if range
|
128
|
+
## "/books/123"[7..-1] is faster than /\A\/books\/(\d+)\z/.match("/books/123")
|
129
|
+
str = req_path[range]
|
130
|
+
param_values = [str]
|
131
|
+
else
|
132
|
+
m = full_urlpath_rexp.match(req_path)
|
133
|
+
param_values = m.captures
|
134
|
+
end
|
125
135
|
vars = build_urlpath_parameter_vars(param_names, param_values)
|
126
136
|
#; [!84inr] caches result when variable urlpath cache enabled.
|
127
137
|
if cache
|
@@ -131,6 +141,8 @@ module Rack
|
|
131
141
|
return obj, vars
|
132
142
|
end
|
133
143
|
|
144
|
+
alias find lookup # :nodoc: # for backward compatilibity
|
145
|
+
|
134
146
|
protected
|
135
147
|
|
136
148
|
## Returns [404, {...}, [...]]. Override in subclass if necessary.
|
@@ -177,10 +189,10 @@ module Rack
|
|
177
189
|
## Compiles urlpath mapping. Called from '#initialize()'.
|
178
190
|
def compile_mapping(mapping)
|
179
191
|
rexp_buf = ['\A']
|
180
|
-
prefix_pat = ''
|
181
192
|
fixed_urlpaths = {} # ex: {'/api/books'=>BooksApp}
|
182
193
|
variable_urlpaths = [] # ex: [[%r'\A/api/books/([^./]+)\z', ['id'], BookApp]]
|
183
|
-
|
194
|
+
_compile_array(mapping, rexp_buf, '', '',
|
195
|
+
fixed_urlpaths, variable_urlpaths)
|
184
196
|
## ex: %r'\A(?:/api(?:/books(?:/[^./]+(\z)|/[^./]+/edit(\z))))\z'
|
185
197
|
rexp_buf << '\z'
|
186
198
|
urlpath_rexp = Regexp.new(rexp_buf.join())
|
@@ -188,57 +200,67 @@ module Rack
|
|
188
200
|
return urlpath_rexp, fixed_urlpaths, variable_urlpaths
|
189
201
|
end
|
190
202
|
|
191
|
-
def
|
192
|
-
|
193
|
-
|
203
|
+
def _compile_array(mapping, rexp_buf, base_urlpath_pat, urlpath_pat,
|
204
|
+
fixed_dict, variable_list)
|
205
|
+
rexp_str, _ = compile_urlpath_pattern(urlpath_pat, false)
|
206
|
+
rexp_buf << rexp_str
|
194
207
|
rexp_buf << '(?:'
|
195
208
|
len = rexp_buf.length
|
196
|
-
mapping.each do |
|
209
|
+
mapping.each do |child_urlpath_pat, obj|
|
197
210
|
rexp_buf << '|' if rexp_buf.length != len
|
198
|
-
|
211
|
+
curr_urlpath_pat = "#{base_urlpath_pat}#{urlpath_pat}"
|
199
212
|
#; [!ospaf] accepts nested mapping.
|
200
213
|
if obj.is_a?(Array)
|
201
|
-
|
202
|
-
|
203
|
-
len2 = rexp_buf.length
|
204
|
-
_compile_mapping(obj, rexp_buf, full_urlpath_pat, fixed_dict, variable_list)
|
205
|
-
#; [!pv2au] deletes unnecessary urlpath regexp.
|
206
|
-
if rexp_buf.length == len2
|
207
|
-
x = rexp_buf.pop()
|
208
|
-
x == rexp_str or raise "assertion failed"
|
209
|
-
end
|
214
|
+
_compile_array(obj, rexp_buf, curr_urlpath_pat, child_urlpath_pat,
|
215
|
+
fixed_dict, variable_list)
|
210
216
|
#; [!2ktpf] handles end-point.
|
211
217
|
else
|
212
|
-
|
213
|
-
|
214
|
-
obj = normalize_mapping_keys(obj)
|
215
|
-
end
|
216
|
-
#; [!l63vu] handles urlpath pattern as fixed when no urlpath params.
|
217
|
-
full_urlpath_rexp_str, param_names = compile_urlpath_pattern(full_urlpath_pat, param_pat2)
|
218
|
-
fixed_pattern = param_names.nil?
|
219
|
-
if fixed_pattern
|
220
|
-
fixed_dict[full_urlpath_pat] = obj
|
221
|
-
#; [!vfytw] handles urlpath pattern as variable when urlpath param exists.
|
222
|
-
else
|
223
|
-
rexp_str, _ = compile_urlpath_pattern(urlpath_pat, param_pat1)
|
224
|
-
rexp_buf << rexp_str << '(\z)'
|
225
|
-
full_urlpath_rexp = Regexp.new("\\A#{full_urlpath_rexp_str}\\z")
|
226
|
-
variable_list << [full_urlpath_rexp, param_names, obj]
|
227
|
-
end
|
218
|
+
_compile_object(obj, rexp_buf, curr_urlpath_pat, child_urlpath_pat,
|
219
|
+
fixed_dict, variable_list)
|
228
220
|
end
|
229
221
|
end
|
230
222
|
#; [!gfxgr] deletes unnecessary grouping.
|
231
223
|
if rexp_buf.length == len
|
232
224
|
x = rexp_buf.pop() # delete '(?:'
|
233
225
|
x == '(?:' or raise "assertion failed"
|
226
|
+
#; [!pv2au] deletes unnecessary urlpath regexp.
|
227
|
+
x = rexp_buf.pop() # delete rexp_str
|
228
|
+
x == rexp_str or raise "assertion failed"
|
229
|
+
#; [!bh9lo] deletes unnecessary grouping which contains only an element.
|
230
|
+
elsif rexp_buf.length == len + 1
|
231
|
+
rexp_buf[-2] == '(?:' or raise "assertion failed: rexp_buf[-2]=#{rexp_buf[-2].inspect}"
|
232
|
+
rexp_buf[-2] = ''
|
234
233
|
else
|
235
234
|
rexp_buf << ')'
|
236
235
|
end
|
237
236
|
end
|
238
237
|
|
238
|
+
def _compile_object(obj, rexp_buf, base_urlpath_pat, urlpath_pat,
|
239
|
+
fixed_dict, variable_list)
|
240
|
+
#; [!guhdc] if mapping dict is specified...
|
241
|
+
if obj.is_a?(Hash)
|
242
|
+
obj = normalize_mapping_keys(obj)
|
243
|
+
end
|
244
|
+
#; [!l63vu] handles urlpath pattern as fixed when no urlpath params.
|
245
|
+
full_urlpath_pat = "#{base_urlpath_pat}#{urlpath_pat}"
|
246
|
+
full_urlpath_rexp_str, param_names = compile_urlpath_pattern(full_urlpath_pat, true)
|
247
|
+
fixed_pattern = param_names.nil?
|
248
|
+
if fixed_pattern
|
249
|
+
fixed_dict[full_urlpath_pat] = obj
|
250
|
+
#; [!vfytw] handles urlpath pattern as variable when urlpath param exists.
|
251
|
+
else
|
252
|
+
rexp_str, _ = compile_urlpath_pattern(urlpath_pat, false)
|
253
|
+
rexp_buf << (rexp_str << '(\z)')
|
254
|
+
full_urlpath_rexp = Regexp.new("\\A#{full_urlpath_rexp_str}\\z")
|
255
|
+
range = @enable_urlpath_param_range ? range_of_urlpath_param(full_urlpath_pat) : nil
|
256
|
+
variable_list << [full_urlpath_rexp, param_names, obj, range]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
239
260
|
## Compiles '/books/:id' into ['/books/([^./]+)', ["id"]].
|
240
|
-
def compile_urlpath_pattern(urlpath_pat,
|
261
|
+
def compile_urlpath_pattern(urlpath_pat, enable_capture=true)
|
241
262
|
s = "".dup()
|
263
|
+
param_pat = enable_capture ? '([^./]+)' : '[^./]+'
|
242
264
|
param_names = []
|
243
265
|
pos = 0
|
244
266
|
urlpath_pat.scan(/:(\w+)|\((.*?)\)/) do |name, optional|
|
@@ -275,6 +297,16 @@ module Rack
|
|
275
297
|
end
|
276
298
|
end
|
277
299
|
|
300
|
+
def range_of_urlpath_param(urlpath_pattern) # ex: '/books/:id/edit'
|
301
|
+
#; [!syrdh] returns Range object when urlpath_pattern contains just one param.
|
302
|
+
#; [!skh4z] returns nil when urlpath_pattern contains more than two params.
|
303
|
+
#; [!acj5b] returns nil when urlpath_pattern contains no params.
|
304
|
+
rexp = /:\w+|\(.*?\)/
|
305
|
+
arr = urlpath_pattern.split(rexp, -1) # ex: ['/books/', '/edit']
|
306
|
+
return nil unless arr.length == 2
|
307
|
+
return (arr[0].length .. -(arr[1].length+1)) # ex: 7..-6 (Range object)
|
308
|
+
end
|
309
|
+
|
278
310
|
def normalize_mapping_keys(dict)
|
279
311
|
#; [!r7cmk] converts keys into string.
|
280
312
|
#; [!z9kww] allows 'ANY' as request method.
|
data/rack-jet_router.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
###
|
4
|
-
### $Release: 1.0
|
4
|
+
### $Release: 1.1.0 $
|
5
5
|
### $Copyright: copyright(c) 2015 kuwata-lab.com all rights reserved $
|
6
6
|
### $License: MIT License $
|
7
7
|
###
|
@@ -64,6 +64,35 @@ describe Rack::JetRouter do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
|
67
|
+
describe '#range_of_urlpath_param()' do
|
68
|
+
|
69
|
+
it "[!syrdh] returns Range object when urlpath_pattern contains just one param." do
|
70
|
+
jet_router.instance_exec(self) do |_|
|
71
|
+
r1 = range_of_urlpath_param('/books/:id')
|
72
|
+
_.ok {r1} == (7..-1)
|
73
|
+
_.ok {'/books/123'[r1]} == '123'
|
74
|
+
r2 = range_of_urlpath_param('/books/:id.html')
|
75
|
+
_.ok {r2} == (7..-6)
|
76
|
+
_.ok {'/books/4567.html'[r2]} == '4567'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "[!skh4z] returns nil when urlpath_pattern contains more than two params." do
|
81
|
+
jet_router.instance_exec(self) do |_|
|
82
|
+
_.ok {range_of_urlpath_param('/books/:book_id/comments/:comment_id')} == nil
|
83
|
+
_.ok {range_of_urlpath_param('/books/:id(:format)')} == nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "[!acj5b] returns nil when urlpath_pattern contains no params." do
|
88
|
+
jet_router.instance_exec(self) do |_|
|
89
|
+
_.ok {range_of_urlpath_param('/books')} == nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
67
96
|
describe '#compile_urlpath_pattern()' do
|
68
97
|
|
69
98
|
it "[!joozm] escapes metachars with backslash in text part." do
|
@@ -110,9 +139,7 @@ describe Rack::JetRouter do
|
|
110
139
|
]
|
111
140
|
expected = '
|
112
141
|
\A
|
113
|
-
(?:
|
114
142
|
/books/[^./]+(\z)
|
115
|
-
)
|
116
143
|
\z
|
117
144
|
'.gsub(/\s+/, '')
|
118
145
|
jet_router.instance_exec(self) do |_|
|
@@ -122,7 +149,7 @@ describe Rack::JetRouter do
|
|
122
149
|
'/' => welcome_app,
|
123
150
|
}
|
124
151
|
_.ok {list} == [
|
125
|
-
[%r'\A/books/([^./]+)\z', ['id'], book_show_api],
|
152
|
+
[%r'\A/books/([^./]+)\z', ['id'], book_show_api, (7..-1)],
|
126
153
|
]
|
127
154
|
end
|
128
155
|
end
|
@@ -167,7 +194,7 @@ describe Rack::JetRouter do
|
|
167
194
|
/api
|
168
195
|
(?:
|
169
196
|
/books2
|
170
|
-
|
197
|
+
/[^./]+(\z)
|
171
198
|
)
|
172
199
|
)
|
173
200
|
\z
|
@@ -181,7 +208,36 @@ describe Rack::JetRouter do
|
|
181
208
|
'/api/books/new' => book_new_api,
|
182
209
|
}
|
183
210
|
_.ok {list} == [
|
184
|
-
[%r'\A/api/books2/([^./]+)\z', ['id'], book_show_api],
|
211
|
+
[%r'\A/api/books2/([^./]+)\z', ['id'], book_show_api, (12..-1)],
|
212
|
+
]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
it "[!bh9lo] deletes unnecessary grouping which contains only an element." do
|
217
|
+
mapping = [
|
218
|
+
['/api', [
|
219
|
+
['/books', [
|
220
|
+
['/:id' , book_show_api],
|
221
|
+
]],
|
222
|
+
]],
|
223
|
+
]
|
224
|
+
expected = '
|
225
|
+
\A
|
226
|
+
(?:
|
227
|
+
/api
|
228
|
+
(?:
|
229
|
+
/books
|
230
|
+
/[^./]+(\z)
|
231
|
+
)
|
232
|
+
)
|
233
|
+
\z
|
234
|
+
'.gsub(/\s+/, '')
|
235
|
+
jet_router.instance_exec(self) do |_|
|
236
|
+
rexp, dict, list = compile_mapping(mapping)
|
237
|
+
_.ok {rexp} == Regexp.new(expected)
|
238
|
+
_.ok {dict} == {}
|
239
|
+
_.ok {list} == [
|
240
|
+
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
|
185
241
|
]
|
186
242
|
end
|
187
243
|
end
|
@@ -211,9 +267,7 @@ describe Rack::JetRouter do
|
|
211
267
|
]
|
212
268
|
expected = '
|
213
269
|
\A
|
214
|
-
(?:
|
215
270
|
/api/books/[^./]+(\z)
|
216
|
-
)
|
217
271
|
\z
|
218
272
|
'.gsub(/\s+/, '')
|
219
273
|
jet_router.instance_exec(self) do |_|
|
@@ -222,7 +276,7 @@ describe Rack::JetRouter do
|
|
222
276
|
_.ok {dict} == {
|
223
277
|
}
|
224
278
|
_.ok {list} == [
|
225
|
-
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api],
|
279
|
+
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
|
226
280
|
]
|
227
281
|
end
|
228
282
|
end
|
@@ -235,9 +289,7 @@ describe Rack::JetRouter do
|
|
235
289
|
]
|
236
290
|
expected = '
|
237
291
|
\A
|
238
|
-
(?:
|
239
292
|
/api/books/[^./]+(\z)
|
240
|
-
)
|
241
293
|
\z
|
242
294
|
'.gsub(/\s+/, '')
|
243
295
|
jet_router.instance_exec(self) do |_|
|
@@ -248,7 +300,7 @@ describe Rack::JetRouter do
|
|
248
300
|
'/api/books' => book_list_api,
|
249
301
|
}
|
250
302
|
_.ok {list} == [
|
251
|
-
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api],
|
303
|
+
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
|
252
304
|
]
|
253
305
|
end
|
254
306
|
end
|
@@ -272,7 +324,7 @@ describe Rack::JetRouter do
|
|
272
324
|
/api
|
273
325
|
(?:
|
274
326
|
/books
|
275
|
-
|
327
|
+
/[^./]+(\z)
|
276
328
|
)
|
277
329
|
)
|
278
330
|
)
|
@@ -285,7 +337,7 @@ describe Rack::JetRouter do
|
|
285
337
|
'/admin/api/books' => book_list_api,
|
286
338
|
}
|
287
339
|
_.ok {list} == [
|
288
|
-
[%r'\A/admin/api/books/([^./]+)\z', ['id'], book_show_api],
|
340
|
+
[%r'\A/admin/api/books/([^./]+)\z', ['id'], book_show_api, (17..-1)],
|
289
341
|
]
|
290
342
|
end
|
291
343
|
end
|
@@ -371,7 +423,7 @@ describe Rack::JetRouter do
|
|
371
423
|
|
|
372
424
|
/admin
|
373
425
|
(?:/books
|
374
|
-
|
426
|
+
/[^./]+(\z)
|
375
427
|
)
|
376
428
|
)
|
377
429
|
\z
|
@@ -388,13 +440,13 @@ describe Rack::JetRouter do
|
|
388
440
|
},
|
389
441
|
}
|
390
442
|
_.ok {@variable_urlpath_list} == [
|
391
|
-
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api],
|
392
|
-
[%r'\A/api/books/([^./]+)/edit\z', ['id'], book_edit_api],
|
393
|
-
[%r'\A/api/books/([^./]+)/comments\z', ['book_id'], comment_create_api],
|
394
|
-
[%r'\A/api/books/([^./]+)/comments/([^./]+)\z', ['book_id', 'comment_id'], comment_update_api],
|
443
|
+
[%r'\A/api/books/([^./]+)\z', ['id'], book_show_api, (11..-1)],
|
444
|
+
[%r'\A/api/books/([^./]+)/edit\z', ['id'], book_edit_api, (11..-6)],
|
445
|
+
[%r'\A/api/books/([^./]+)/comments\z', ['book_id'], comment_create_api, (11..-10)],
|
446
|
+
[%r'\A/api/books/([^./]+)/comments/([^./]+)\z', ['book_id', 'comment_id'], comment_update_api, nil],
|
395
447
|
[%r'\A/admin/books/([^./]+)\z', ['id'], {'GET' => admin_book_show_app,
|
396
448
|
'PUT' => admin_book_update_app,
|
397
|
-
'DELETE' => admin_book_delete_app}],
|
449
|
+
'DELETE' => admin_book_delete_app}, (13..-1)],
|
398
450
|
]
|
399
451
|
end
|
400
452
|
end
|
@@ -402,30 +454,30 @@ describe Rack::JetRouter do
|
|
402
454
|
end
|
403
455
|
|
404
456
|
|
405
|
-
describe '#
|
457
|
+
describe '#lookup()' do
|
406
458
|
|
407
459
|
it "[!ijqws] returns mapped object and urlpath parameter values when urlpath found." do
|
408
|
-
ret = jet_router.
|
460
|
+
ret = jet_router.lookup('/api/books/123')
|
409
461
|
ok {ret} == [book_show_api, {"id"=>"123"}]
|
410
462
|
end
|
411
463
|
|
412
464
|
it "[!vpdzn] returns nil when urlpath not found." do
|
413
|
-
ok {jet_router.
|
414
|
-
ok {jet_router.
|
415
|
-
ok {jet_router.
|
465
|
+
ok {jet_router.lookup('/api')} == nil
|
466
|
+
ok {jet_router.lookup('/api/book')} == nil
|
467
|
+
ok {jet_router.lookup('/api/books/')} == nil
|
416
468
|
end
|
417
469
|
|
418
470
|
it "[!24khb] finds in fixed urlpaths at first." do
|
419
|
-
ok {jet_router.
|
420
|
-
ok {jet_router.
|
471
|
+
ok {jet_router.lookup('/')} == [welcome_app, nil]
|
472
|
+
ok {jet_router.lookup('/api/books')} == [book_list_api, nil]
|
421
473
|
dict = {'GET'=>admin_book_list_app, 'POST'=>admin_book_create_app}
|
422
|
-
ok {jet_router.
|
474
|
+
ok {jet_router.lookup('/admin/books')} == [dict, nil]
|
423
475
|
end
|
424
476
|
|
425
477
|
it "[!iwyzd] urlpath param value is nil when found in fixed urlpaths." do
|
426
|
-
obj, vars = jet_router.
|
478
|
+
obj, vars = jet_router.lookup('/')
|
427
479
|
ok {vars} == nil
|
428
|
-
obj, vars = jet_router.
|
480
|
+
obj, vars = jet_router.lookup('/api/books')
|
429
481
|
ok {vars} == nil
|
430
482
|
end
|
431
483
|
|
@@ -434,14 +486,14 @@ describe Rack::JetRouter do
|
|
434
486
|
['/api/books/:id', book_show_api],
|
435
487
|
]
|
436
488
|
r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
|
437
|
-
pair = r.
|
489
|
+
pair = r.lookup('/api/books/123')
|
438
490
|
ok {pair} == [book_show_api, {"id"=>"123"}]
|
439
491
|
r.instance_exec(self) do |_|
|
440
492
|
_.ok {@variable_urlpath_cache} == {'/api/books/123'=>pair}
|
441
493
|
#
|
442
494
|
@variable_urlpath_cache['/api/books/999'] = [book_list_api, {"ID"=>"111"}]
|
443
495
|
end
|
444
|
-
pair = r.
|
496
|
+
pair = r.lookup('/api/books/999')
|
445
497
|
ok {pair} == [book_list_api, {"ID"=>"111"}]
|
446
498
|
end
|
447
499
|
|
@@ -451,9 +503,9 @@ describe Rack::JetRouter do
|
|
451
503
|
]
|
452
504
|
r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
|
453
505
|
#
|
454
|
-
pair1 = r.
|
455
|
-
pair2 = r.
|
456
|
-
pair3 = r.
|
506
|
+
pair1 = r.lookup('/books/1'); ok {pair1} == [book_show_api, {"id"=>"1"}]
|
507
|
+
pair2 = r.lookup('/books/2'); ok {pair2} == [book_show_api, {"id"=>"2"}]
|
508
|
+
pair3 = r.lookup('/books/3'); ok {pair3} == [book_show_api, {"id"=>"3"}]
|
457
509
|
r.instance_exec(self) do |_|
|
458
510
|
_.ok {@variable_urlpath_cache} == {
|
459
511
|
'/books/1'=>pair1,
|
@@ -462,7 +514,7 @@ describe Rack::JetRouter do
|
|
462
514
|
}
|
463
515
|
end
|
464
516
|
#
|
465
|
-
pair4 = r.
|
517
|
+
pair4 = r.lookup('/books/4'); ok {pair4} == [book_show_api, {"id"=>"4"}]
|
466
518
|
r.instance_exec(self) do |_|
|
467
519
|
_.ok {@variable_urlpath_cache} == {
|
468
520
|
'/books/2'=>pair2,
|
@@ -478,10 +530,10 @@ describe Rack::JetRouter do
|
|
478
530
|
]
|
479
531
|
r = Rack::JetRouter.new(mapping, urlpath_cache_size: 3)
|
480
532
|
#
|
481
|
-
pair1 = r.
|
482
|
-
pair2 = r.
|
483
|
-
pair3 = r.
|
484
|
-
pair4 = r.
|
533
|
+
pair1 = r.lookup('/books/1')
|
534
|
+
pair2 = r.lookup('/books/2')
|
535
|
+
pair3 = r.lookup('/books/3')
|
536
|
+
pair4 = r.lookup('/books/4')
|
485
537
|
r.instance_exec(self) do |_|
|
486
538
|
_.ok {@variable_urlpath_cache} == {
|
487
539
|
'/books/2'=>pair2,
|
@@ -490,7 +542,7 @@ describe Rack::JetRouter do
|
|
490
542
|
}
|
491
543
|
end
|
492
544
|
#
|
493
|
-
ok {r.
|
545
|
+
ok {r.lookup('/books/3')} == pair3
|
494
546
|
r.instance_exec(self) do |_|
|
495
547
|
_.ok {@variable_urlpath_cache} == {
|
496
548
|
'/books/2'=>pair2,
|
@@ -499,7 +551,7 @@ describe Rack::JetRouter do
|
|
499
551
|
}
|
500
552
|
end
|
501
553
|
#
|
502
|
-
ok {r.
|
554
|
+
ok {r.lookup('/books/1')} == pair1
|
503
555
|
r.instance_exec(self) do |_|
|
504
556
|
_.ok {@variable_urlpath_cache} == {
|
505
557
|
'/books/4'=>pair4,
|
metadata
CHANGED
@@ -1,72 +1,73 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-jet_router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- makoto kuwata
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest-ok
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description:
|
56
|
-
|
55
|
+
description: 'Super-fast router class for Rack application, derived from Keight.rb.
|
56
|
+
|
57
|
+
'
|
57
58
|
email:
|
58
59
|
- kwa(at)kuwata-lab.com
|
59
60
|
executables: []
|
60
61
|
extensions: []
|
61
62
|
extra_rdoc_files: []
|
62
63
|
files:
|
63
|
-
- README.md
|
64
64
|
- MIT-LICENSE
|
65
|
+
- README.md
|
65
66
|
- Rakefile
|
66
|
-
- rack-jet_router.gemspec
|
67
67
|
- lib/rack/jet_router.rb
|
68
|
-
-
|
68
|
+
- rack-jet_router.gemspec
|
69
69
|
- test/rack/jet_router_test.rb
|
70
|
+
- test/test_helper.rb
|
70
71
|
homepage: https://github.com/kwatch/rack-jet_router
|
71
72
|
licenses:
|
72
73
|
- MIT-License
|
@@ -77,17 +78,17 @@ require_paths:
|
|
77
78
|
- lib
|
78
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
79
80
|
requirements:
|
80
|
-
- -
|
81
|
+
- - ">="
|
81
82
|
- !ruby/object:Gem::Version
|
82
83
|
version: '2.0'
|
83
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
85
|
requirements:
|
85
|
-
- -
|
86
|
+
- - ">="
|
86
87
|
- !ruby/object:Gem::Version
|
87
88
|
version: '0'
|
88
89
|
requirements: []
|
89
90
|
rubyforge_project:
|
90
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.5.1
|
91
92
|
signing_key:
|
92
93
|
specification_version: 4
|
93
94
|
summary: Super-fast router class for Rack
|