rack-jet_router 1.1.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGES.md +52 -0
- data/MIT-LICENSE +1 -1
- data/README.md +207 -52
- data/bench/Gemfile +13 -0
- data/bench/Rakefile.rb +11 -0
- data/bench/bench.rb +367 -0
- data/lib/rack/jet_router.rb +432 -208
- data/rack-jet_router.gemspec +21 -18
- data/test/builder_test.rb +631 -0
- data/test/misc_test.rb +23 -0
- data/test/router_test.rb +597 -0
- data/test/run_all.rb +6 -0
- data/test/{test_helper.rb → shared.rb} +8 -3
- metadata +36 -42
- data/Rakefile +0 -58
- data/test/rack/jet_router_test.rb +0 -670
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ffb2322f3ac227a3d07fa95c120d25c3dcb8763f9ea925be7a3a03df11c00ba9
|
4
|
+
data.tar.gz: 60b292dd4a1307a2fd1cbfcb474746131599fe0ba0ae93768b40f2cf0c9e5fa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d33fb4622786b549f6681f6a89fd578f631235548b7d67644431483815a71e62d0a438c22b82e2534074c52e704cd68607f02060153ea8477898e13725c3e836
|
7
|
+
data.tar.gz: 36be6953b2ed04a82f56c97e0c3eaf51022b21546116a0ead5b1a125ff82c746c1297a9c4e153012ca0a922e1a55161a1ea7a534036857d97cd91529aa4118d9
|
data/CHANGES.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
CHANGES
|
2
|
+
=======
|
3
|
+
|
4
|
+
|
5
|
+
Release 1.3.0 (2023-12-09)
|
6
|
+
--------------------------
|
7
|
+
|
8
|
+
* [enhance] Performance has improved (about 10%). This improvement was achieved by optimizing regular expressions.
|
9
|
+
* [enhance] URL path mapping can be nested Hash as well as nested Array. See the document for detail.
|
10
|
+
* [enhance] Passing the `int_param: /(?:\A|_)id\z/` keyword argument to `JetRouter.new()` changes the router to treat urlpath parameter `id` or `xxx_id` as integer type.
|
11
|
+
* [enhance] Passing the `env_key:` keyword argument to `JetRouter.new()` changes the key of environemnt to store URL path parameter values.
|
12
|
+
* [change] Keyword parameter `urlpath_cache_size:` of `JetRouter.new()` is renamed to `cache_size:`. Old parameter name is also available for backward compatibility, but it is recommended to use new parameter name.
|
13
|
+
* [change] Rename `JetRouter#build_urlpath_parameter_vars()` to `JetRouter#build_param_values()`.
|
14
|
+
* [change] Update benchmark script to require 'benchmarker' gem.
|
15
|
+
|
16
|
+
|
17
|
+
Release 1.2.0 (2016-10-16)
|
18
|
+
--------------------------
|
19
|
+
|
20
|
+
* Change auto-redirection to be occurred only on GET or HEAD methods.
|
21
|
+
* Code is rewrited, especially around `Rack::JetRouter#compile_mapping()`.
|
22
|
+
* Update benchmark script to support `Hanabi::Router`.
|
23
|
+
|
24
|
+
|
25
|
+
Release 1.1.1 (2015-12-29)
|
26
|
+
--------------------------
|
27
|
+
|
28
|
+
* Fix benchmark script.
|
29
|
+
* Fix document.
|
30
|
+
|
31
|
+
|
32
|
+
Release 1.1.0 (2015-12-28)
|
33
|
+
--------------------------
|
34
|
+
|
35
|
+
* **NOTICE** `Rack::JetRouter#find()` is renamed to `#lookup()`.
|
36
|
+
`#find()` is also available for compatibility, but not recommended.
|
37
|
+
* Performance improved when number of URL path parameter is 1.
|
38
|
+
* Regular expression generated is improved.
|
39
|
+
* Benchmark script is improved to take some command-line options.
|
40
|
+
* Document fixed.
|
41
|
+
|
42
|
+
|
43
|
+
Release 1.0.1 (2015-12-06)
|
44
|
+
--------------------------
|
45
|
+
|
46
|
+
* Fix document
|
47
|
+
|
48
|
+
|
49
|
+
Release 1.0.0 (2015-12-06)
|
50
|
+
--------------------------
|
51
|
+
|
52
|
+
* First release
|
data/MIT-LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
$Copyright: copyright(c) 2015
|
3
|
+
$Copyright: copyright(c) 2015 kwatch@gmail.com $
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,39 +1,55 @@
|
|
1
1
|
# Rack::JetRouter
|
2
2
|
|
3
|
-
($Release: 1.
|
3
|
+
($Release: 1.3.0 $)
|
4
4
|
|
5
5
|
Rack::JetRouter is crazy-fast router library for Rack application,
|
6
6
|
derived from [Keight.rb](https://github.com/kwatch/keight/tree/ruby).
|
7
7
|
|
8
|
-
Rack::JetRouter requires Ruby >= 2.
|
8
|
+
Rack::JetRouter requires Ruby >= 2.4.
|
9
9
|
|
10
10
|
|
11
11
|
## Benchmark
|
12
12
|
|
13
|
-
Benchmark script is [here](https://github.com/kwatch/rack-jet_router/blob/
|
13
|
+
Benchmark script is [here](https://github.com/kwatch/rack-jet_router/blob/release/bench/bench.rb).
|
14
14
|
|
15
|
-
|
15
|
+
| Name | Version |
|
16
|
+
| ------------------ | ------- |
|
17
|
+
| Ruby | 3.2.2 |
|
18
|
+
| Rack | 2.2.8 |
|
19
|
+
| Rack::JetRouter | 1.3.0 |
|
20
|
+
| Rack::Multiplexer | 0.0.8 |
|
21
|
+
| Sinatra | 3.1.0 |
|
22
|
+
| Keight.rb | 1.0.0 |
|
23
|
+
| Hanami::Router | 2.0.2 |
|
24
|
+
|
25
|
+
(Macbook Pro, Apple M1 Pro, macOS Ventura 13.6.2)
|
26
|
+
|
27
|
+
|
28
|
+
### JetRouter vs. Rack vs. Sinatra vs. Keight.rb vs. Hanami:
|
16
29
|
|
17
30
|
```
|
18
31
|
## Ranking usec/req Graph (longer=faster)
|
19
|
-
(
|
20
|
-
(
|
21
|
-
(
|
22
|
-
(
|
23
|
-
(
|
24
|
-
(
|
25
|
-
(Keight
|
26
|
-
(Keight
|
27
|
-
(
|
28
|
-
(
|
32
|
+
(JetRouter) /api/aaa01 0.2816 (100.0%) ********************
|
33
|
+
(Multiplexer) /api/aaa01 1.2586 ( 22.4%) ****
|
34
|
+
(Hanami::Router) /api/aaa01 1.3296 ( 21.2%) ****
|
35
|
+
(JetRouter) /api/aaa01/123 1.5861 ( 17.8%) ****
|
36
|
+
(Rack::Req+Res) /api/aaa01/123 1.7369 ( 16.2%) ***
|
37
|
+
(Rack::Req+Res) /api/aaa01 1.7438 ( 16.1%) ***
|
38
|
+
(Keight) /api/aaa01 1.8906 ( 14.9%) ***
|
39
|
+
(Keight) /api/aaa01/123 2.8998 ( 9.7%) **
|
40
|
+
(Multiplexer) /api/aaa01/123 2.9166 ( 9.7%) **
|
41
|
+
(Hanami::Router) /api/aaa01/123 4.0996 ( 6.9%) *
|
42
|
+
(Sinatra) /api/aaa01 49.6862 ( 0.6%)
|
43
|
+
(Sinatra) /api/aaa01/123 54.3448 ( 0.5%)
|
29
44
|
```
|
30
45
|
|
31
46
|
* If URL path has no path parameter (such as `/api/hello`),
|
32
|
-
|
47
|
+
JetRouter is significantly fast.
|
33
48
|
* If URL path contains path parameter (such as `/api/hello/:id`),
|
34
|
-
|
35
|
-
* Overhead of
|
49
|
+
JetRouter becomes slower, but it is enough small (about 1.3 usec/req).
|
50
|
+
* Overhead of JetRouter is smaller than that of Rack::Reqeuast +
|
36
51
|
Rack::Response.
|
52
|
+
* Hanami is slower than JetRouter, but quite enough fast.
|
37
53
|
* Sinatra is too slow.
|
38
54
|
|
39
55
|
|
@@ -41,17 +57,35 @@ Benchmark script is [here](https://github.com/kwatch/rack-jet_router/blob/dev/be
|
|
41
57
|
|
42
58
|
```
|
43
59
|
## Ranking usec/req Graph (longer=faster)
|
44
|
-
(JetRouter)
|
45
|
-
(JetRouter)
|
46
|
-
(
|
47
|
-
(JetRouter)
|
48
|
-
(Multiplexer)
|
49
|
-
(
|
50
|
-
(Multiplexer)
|
51
|
-
(Multiplexer)
|
60
|
+
(JetRouter) /api/aaa01 0.2816 (100.0%) ********************
|
61
|
+
(JetRouter) /api/zzz26 0.2823 ( 99.7%) ********************
|
62
|
+
(Multiplexer) /api/aaa01 1.2586 ( 22.4%) ****
|
63
|
+
(JetRouter) /api/aaa01/123 1.5861 ( 17.8%) ****
|
64
|
+
(Multiplexer) /api/aaa01/123 2.9166 ( 9.7%) **
|
65
|
+
(JetRouter) /api/zzz26/456 3.5767 ( 7.9%) **
|
66
|
+
(Multiplexer) /api/zzz26 14.8423 ( 1.9%)
|
67
|
+
(Multiplexer) /api/zzz26/456 16.8930 ( 1.7%)
|
52
68
|
```
|
53
69
|
|
54
|
-
* JetRouter is about
|
70
|
+
* JetRouter is about 4~6 times faster than Rack::Multiplexer.
|
71
|
+
* Rack::Multiplexer is getting worse in promotion to the number of URL paths.
|
72
|
+
|
73
|
+
|
74
|
+
### JetRouter vs. Hanami::Router
|
75
|
+
|
76
|
+
```
|
77
|
+
## Ranking usec/req Graph (longer=faster)
|
78
|
+
(JetRouter) /api/aaa01 0.2816 (100.0%) ********************
|
79
|
+
(JetRouter) /api/zzz26 0.2823 ( 99.7%) ********************
|
80
|
+
(Hanami::Router) /api/zzz26 1.3280 ( 21.2%) ****
|
81
|
+
(Hanami::Router) /api/aaa01 1.3296 ( 21.2%) ****
|
82
|
+
(JetRouter) /api/aaa01/123 1.5861 ( 17.8%) ****
|
83
|
+
(JetRouter) /api/zzz26/456 3.5767 ( 7.9%) **
|
84
|
+
(Hanami::Router) /api/zzz26/456 4.0898 ( 6.9%) *
|
85
|
+
(Hanami::Router) /api/aaa01/123 4.0996 ( 6.9%) *
|
86
|
+
```
|
87
|
+
|
88
|
+
* Hanami is slower than JetRouter, but it has enough speed.
|
55
89
|
|
56
90
|
|
57
91
|
## Examples
|
@@ -169,6 +203,69 @@ handler.__send__(action, args)
|
|
169
203
|
## Topics
|
170
204
|
|
171
205
|
|
206
|
+
### Nested Array v.s. Nested Hash
|
207
|
+
|
208
|
+
URL path mapping can be not only nested Array but also nested Hash.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
## nested Array
|
212
|
+
mapping = [
|
213
|
+
["/api", [
|
214
|
+
["/books", [
|
215
|
+
["" , book_list_api],
|
216
|
+
["/:id" , book_show_api],
|
217
|
+
]],
|
218
|
+
]],
|
219
|
+
]
|
220
|
+
|
221
|
+
## nested Hash
|
222
|
+
mapping = {
|
223
|
+
"/api" => {
|
224
|
+
"/books" => {
|
225
|
+
"" => book_list_api,
|
226
|
+
"/:id" => book_show_api,
|
227
|
+
},
|
228
|
+
},
|
229
|
+
}
|
230
|
+
```
|
231
|
+
|
232
|
+
But nested Hash mapping can't include request method mappings, because
|
233
|
+
it is hard to distinguish between URL path mapping and request method mapping.
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
## NOT OK
|
237
|
+
mapping = {
|
238
|
+
"/api" => {
|
239
|
+
"/books" => {
|
240
|
+
"" => {GET: book_list_api, POST: book_create_api},
|
241
|
+
"/:id" => {GET: book_show_api, PUT: book_update_api},
|
242
|
+
},
|
243
|
+
},
|
244
|
+
}
|
245
|
+
```
|
246
|
+
|
247
|
+
In this case, define subclass of Hash class and use it instead of Hash.
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
class Map < Hash # define subclass of Hash class
|
251
|
+
end
|
252
|
+
|
253
|
+
def Map(**kwargs) # helper method to create subclass object
|
254
|
+
return Map.new.update(kwargs)
|
255
|
+
end
|
256
|
+
|
257
|
+
## OK
|
258
|
+
mapping = {
|
259
|
+
"/api" => {
|
260
|
+
"/books" => {
|
261
|
+
"" => Map(GET: book_list_api, POST: book_create_api),
|
262
|
+
"/:id" => Map(GET: book_show_api, PUT: book_update_api),
|
263
|
+
},
|
264
|
+
},
|
265
|
+
}
|
266
|
+
```
|
267
|
+
|
268
|
+
|
172
269
|
### URL Path Parameters
|
173
270
|
|
174
271
|
In Rack application, URL path parameters (such as `{"id"=>"123"}`) are
|
@@ -181,13 +278,19 @@ BookApp = proc {|env|
|
|
181
278
|
}
|
182
279
|
```
|
183
280
|
|
281
|
+
Key name can be changed by ``env_key:`` keyword argument of ``JetRouter.new()``.
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
router = Rack::JetRouter.new(mapping, env_key: "rack.urlpath_params")
|
285
|
+
```
|
286
|
+
|
184
287
|
If you want to tweak URL path parameters, define subclass of Rack::JetRouter
|
185
|
-
and override `#
|
288
|
+
and override `#build_param_values(names, values)`.
|
186
289
|
|
187
290
|
```ruby
|
188
291
|
class MyRouter < JetRouter
|
189
292
|
|
190
|
-
def
|
293
|
+
def build_param_values(names, values)
|
191
294
|
return names.zip(values).each_with_object({}) {|(k, v), d|
|
192
295
|
## converts urlpath pavam value into integer
|
193
296
|
v = v.to_i if k == 'id' || k.end_with?('_id')
|
@@ -199,6 +302,81 @@ end
|
|
199
302
|
```
|
200
303
|
|
201
304
|
|
305
|
+
### Integer Type Parameters
|
306
|
+
|
307
|
+
Keyword argument ``int_param:`` of ``JetRouter.new()`` specifies
|
308
|
+
parameter name pattern (regexp) to treat as integer type.
|
309
|
+
For example, ``int_param: /(?:\A|_)id\z/`` treats ``id`` or ``xxx_id``
|
310
|
+
parameter values as integer type.
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
require 'rack'
|
314
|
+
require 'rack/jet_router'
|
315
|
+
|
316
|
+
rack_app = proc {|env|
|
317
|
+
params = env['rack.urlpath_params']
|
318
|
+
type = params["book_id"].class
|
319
|
+
text = "params=#{params.inspect}, type=#{type}"
|
320
|
+
[200, {}, [text]]
|
321
|
+
}
|
322
|
+
|
323
|
+
mapping = [
|
324
|
+
["/api/books/:book_id", rack_app]
|
325
|
+
]
|
326
|
+
router = Rack::JetRouter.new(mapping, int_param: /(?:\A|_)id\z/
|
327
|
+
|
328
|
+
env = Rack::MockRequest.env_for("/api/books/123")
|
329
|
+
tuple = router.call(env)
|
330
|
+
puts tuple[2] #=> params={"book_id"=>123}, type=Integer
|
331
|
+
```
|
332
|
+
|
333
|
+
Integer type parameters match to only integers.
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
env = Rack::MockRequest.env_for("/api/books/FooBar")
|
337
|
+
tuple = router.call(env)
|
338
|
+
puts tuple[2] #=> 404 Not Found
|
339
|
+
```
|
340
|
+
|
341
|
+
|
342
|
+
<!--
|
343
|
+
|
344
|
+
### URL Path Multiple Extension
|
345
|
+
|
346
|
+
It is available to specify multiple extension of URL path.
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
mapping = {
|
350
|
+
"/api/books" => {
|
351
|
+
"/:id(.html|.json)" => book_api,
|
352
|
+
},
|
353
|
+
}
|
354
|
+
```
|
355
|
+
|
356
|
+
In above example, the following URL path patterns are enabled.
|
357
|
+
|
358
|
+
* ``/api/books/:id``
|
359
|
+
* ``/api/books/:id.html``
|
360
|
+
* ``/api/books/:id.json``
|
361
|
+
|
362
|
+
Notice that ``env['rack.urlpath_params']['format']`` is not set
|
363
|
+
because ``:format`` is not specified in URL path pattern.
|
364
|
+
|
365
|
+
-->
|
366
|
+
|
367
|
+
|
368
|
+
### Auto-redirection
|
369
|
+
|
370
|
+
Rack::JetRouter implements auto-redirection.
|
371
|
+
|
372
|
+
* When `/foo` is provided and `/foo/` is requested, then Rack::JetRouter redirects to `/foo` automatically.
|
373
|
+
* When `/foo/` is provided and `/foo` is requested, then Rack::JetRouter redirects to `/foo/` automatically.
|
374
|
+
|
375
|
+
Notice that auto-redirection is occurred only on `GET` or `HEAD` methods, because
|
376
|
+
browser cannot handle redirection on `POST`, `PUT`, and `DELETE` methods correctly.
|
377
|
+
Don't depend on auto-redirection feature so much.
|
378
|
+
|
379
|
+
|
202
380
|
### Variable URL Path Cache
|
203
381
|
|
204
382
|
It is useful to classify URL path patterns into two types: fixed and variable.
|
@@ -249,29 +427,6 @@ Above methods are invoked from `Rack::JetRouter#call()`.
|
|
249
427
|
|
250
428
|
## Copyright and License
|
251
429
|
|
252
|
-
$Copyright: copyright(c) 2015
|
430
|
+
$Copyright: copyright(c) 2015 kwatch@gmail.com $
|
253
431
|
|
254
432
|
$License: MIT License $
|
255
|
-
|
256
|
-
|
257
|
-
## History
|
258
|
-
|
259
|
-
|
260
|
-
### 2015-12-28: Release 1.1.0
|
261
|
-
|
262
|
-
* **NOTICE** `Rack::JetRouter#find()` is renamed to `#lookup()`.<br>
|
263
|
-
`#find()` is also available for compatibility, but not recommended.
|
264
|
-
* Performance improved when number of URL path parameter is 1.
|
265
|
-
* Regular expression generated is improved.
|
266
|
-
* Benchmark script is improved to take some command-line options.
|
267
|
-
* Document fixed.
|
268
|
-
|
269
|
-
|
270
|
-
### 2015-12-06: Release 1.0.1
|
271
|
-
|
272
|
-
* Fix document
|
273
|
-
|
274
|
-
|
275
|
-
### 2015-12-06: Release 1.0.0
|
276
|
-
|
277
|
-
* First release
|
data/bench/Gemfile
ADDED
data/bench/Rakefile.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
|
5
|
+
desc "run 'bench.rb' script"
|
6
|
+
task :bench, :N do |t, args|
|
7
|
+
n = args[:N] || 1000000
|
8
|
+
ruby "bench.rb", "--N=#{n}"
|
9
|
+
#ruby "bench.rb", "--N=#{n}", "--sinatra=0", "--multiplexer=0"
|
10
|
+
#ruby "bench.rb", "--N=#{n}", "--rack=0", "--jetrouter=0", "--keight=0", "--multiplexer=0", "--sinatra=0", "--hanami=0"
|
11
|
+
end
|