rack-jet_router 1.1.1 → 1.3.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 +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
|