keight 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc49bd013923bbf4714db247133b1dee371519d3
4
- data.tar.gz: f5cda960b9bd0772aae79b835ceca64ae7470c5e
3
+ metadata.gz: 5674423ea6090c2163b9bff12f3ec5f2a1542dce
4
+ data.tar.gz: ecde3e22c5720bfd8be224b45bb3f2e28db092dc
5
5
  SHA512:
6
- metadata.gz: 32ef664b317f9c4053f1bad16e61de02616bcec598d40eb566f278fcc9e87ac35511c6f031cd91a26fae2c06a9de088b2ee8db80530b7966473878f6e613c3d7
7
- data.tar.gz: e45639182983542961cda6d1dfc9bdb7b4e6b282a235162a66dabe74da220bd0cdd46b177d5b4d2410a67ef48fc0d0bfa60dca17bf58fdf559a17b4f65eef4d6
6
+ metadata.gz: 0a976045af16e6ff169a3fe46decb0b9c0fe8d30ed4848dc8d5669298766c3651be375c2dc4690614f3b740c4b599ec209594d82203aaf3e3f05397f1eade1a3
7
+ data.tar.gz: 75720c41ec1250de00b5aeb2c1ed332b674d6c90e7a238bf4263fc1226caf9eedabb9c7d00ca1278f4a9d0609e9f59110d01e0b8e60f7e525d045e01bf744467
@@ -0,0 +1,64 @@
1
+ Changes
2
+ =======
3
+
4
+
5
+ Release 0.2.0 (2016-01-06)
6
+ --------------------------
7
+
8
+ * [change] `K8::RackApplication#mount()` is removed.
9
+ Use `K8::RackApplication.new([...])` instead.
10
+
11
+ * [change] `k8rb init` is renamed to `k8rb project`.
12
+
13
+ $ k8rb project myapp1
14
+ $ cd myapp1
15
+
16
+ * [enhance] Auto redirection support.
17
+ For example, `GET /books` is defined and `GET /books/` is requested,
18
+ then it will be redirected to `GET /books`.
19
+
20
+ * [enhance] Performance improved for variable urlpath.
21
+
22
+ * [enhance] Implement urlpath helpers.
23
+
24
+ p BookAPI[:do_update].method #=> :PUT
25
+ p BookAPI[:do_update].urlpath(123) #=> '/api/books/123'
26
+ p BookAPI[:do_update].form_action_attr(123) #=> '/api/books/123?_method=PUT'
27
+
28
+ * [change] `k8rb mapping` now prints output in text format, not YAML format.
29
+
30
+ * [enhance] `k8rb mapping` supports `--format=FORMAT` option.
31
+
32
+ $ k8rb mapping --format=text # or yaml/json/javascript/jquery/angular
33
+
34
+ * [enhance] `k8rb` command supports `cdnjs` action which download JavaScript
35
+ libraries from cdnjs.com.
36
+
37
+ $ k8rb cdnjs # list library
38
+ $ k8rb cdnjs 'jquery*' # search library
39
+ $ k8rb cdnjs jquery # list versions
40
+ $ k8rb cdnjs jquery 2.1.4 # download library
41
+
42
+ * [change] `k8rb init` command downloads jquery and modernizr from cdnjs.com.
43
+
44
+ * [change] `K8::Mock` and `K8::TestApp` are removed.
45
+ Use rack-test_app gem instead.
46
+
47
+ * [bugfix] Document fixed.
48
+
49
+ * [internal] Remove `K8::ActionClassMapping`, 'K8::ActionRouter' and
50
+ 'K8::ActionFinder' classes.
51
+
52
+ * [internal] Define new class `K8::ActionMapping` instead of remove classes.
53
+
54
+
55
+ Release 0.1.0 (2015-10-27)
56
+ --------------------------
57
+
58
+ * Public release
59
+
60
+
61
+ Release 0.0.1 (2015-10-26)
62
+ --------------------------
63
+
64
+ * Test release
@@ -1,4 +1,4 @@
1
- $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
1
+ $Copyright: copyright(c) 2014-2016 kuwata-lab.com all rights reserved $
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Keight.rb README
2
2
  ================
3
3
 
4
- ($Release: 0.1.0 $)
4
+ ($Release: 0.2.0 $)
5
5
 
6
6
 
7
7
  Overview
@@ -18,15 +18,15 @@ Benchmarks
18
18
 
19
19
  Measured with `app.call(env)` style in order to exclude server overhead:
20
20
 
21
- | FW | Request | sec/1000req | req/sec |
22
- |:--------|:-------------------|------------:|---------:|
23
- | Rails | GET /api/hello | 7.5188 | 133.0 |
24
- | Rails | GET /api/hello/123 | 8.0030 | 125.0 |
25
- | Sinatra | GET /api/hello | 1.5034 | 665.2 |
26
- | Sinatra | GET /api/hello/123 | 1.6328 | 612.4 |
27
- | Rack | GET /api/hello | 0.0789 | 12674.3 |
28
- | Keight | GET /api/hello | 0.0773 | 12936.6 |
29
- | Keight | GET /api/hello/123 | 0.1385 | 7220.2 |
21
+ | Framework | Request | usec/req | req/sec |
22
+ |:----------|:-------------------|---------:|---------:|
23
+ | Rails | GET /api/hello | 738.7 | 1353.7 |
24
+ | Rails | GET /api/hello/123 | 782.2 | 1278.4 |
25
+ | Sinatra | GET /api/hello | 144.1 | 6938.3 |
26
+ | Sinatra | GET /api/hello/123 | 158.4 | 6313.8 |
27
+ | Rack | GET /api/hello | 9.9 | 101050.9 |
28
+ | Keight | GET /api/hello | 7.6 | 132432.8 |
29
+ | Keight | GET /api/hello/123 | 10.6 | 94705.9 |
30
30
 
31
31
  * Ruby 2.2.3
32
32
  * Rails 4.2.4
@@ -48,7 +48,7 @@ $ export GEM_HOME=$PWD/gems
48
48
  $ export PATH=$GEM_HOME/bin:$PATH
49
49
 
50
50
  $ gem install keight
51
- $ vi hello.rb
51
+ $ vi hello.rb # see below
52
52
  $ vi config.ru # != 'config.rb'
53
53
  $ rackup -p 8000 config.ru
54
54
  ```
@@ -81,44 +81,46 @@ class HelloAction < K8::Action
81
81
  end
82
82
  ```
83
83
 
84
- config.rb:
84
+ config.ru:
85
85
 
86
86
  ```ruby
87
87
  # -*- coding: utf-8 -*-
88
88
  require 'keight'
89
89
  require './hello'
90
90
 
91
- app = K8::RackApplication.new()
92
- app.mount '/hello', HelloAction
93
-
94
- ### or
95
- #mapping = [
96
- # ['/api', [
97
- # ['/hello' , "./hello:HelloAction"],
98
- # ]],
99
- #]
100
- #app = K8::RackApplication.new(mapping)
91
+ mapping = [
92
+ ['/api', [
93
+ ['/hello' , HelloAction],
94
+ ## or
95
+ #['/hello' , "./hello:HelloAction"],
96
+ ]],
97
+ ]
98
+ app = K8::RackApplication.new(mapping)
101
99
 
102
100
  run app
103
101
  ```
104
102
 
105
- Open http://localhost:8000/hello or http://localhost:8000/hello/123
103
+ Open http://localhost:8000/api/hello or http://localhost:8000/api/hello/123
106
104
  with your browser.
107
105
 
108
- Do you like it? If so, try `k8rb init myapp1` to generate project skeleton.
106
+ Do you like it? If so, try `k8rb project myapp1` to generate project skeleton.
109
107
 
110
108
  ```console
111
- $ k8rb init myapp1
109
+ $ mkdir gems # if necessary
110
+ $ export GEM_HOME=$PWD/gems # if necessary
111
+ $ export PATH=$GEM_HOME/bin:$PATH # if necessary
112
+ $ gem install -N keight
113
+ $ k8rb help # show help
114
+ $ k8rb project myapp1 # create new project
112
115
  $ cd myapp1/
116
+ $ rake setup # install gems and download libs
113
117
  $ export APP_ENV=dev # 'dev', 'prod', or 'stg'
114
- $ k8rb mapping
115
- $ k8rb configs
116
- $ rackup -p 8000 -E production config.ru
117
- $ open http://127.0.0.1:8000/
118
- $ ab -n 1000 -c 10 http://127.0.0.1:8000/api/hello
119
- ## or:
120
- $ gem install puma
121
- $ rackup -p 8000 -E production -s puma config.ru
118
+ $ k8rb help mapping
119
+ $ k8rb mapping # list urlpath mappings
120
+ $ k8rb mapping --format=javascript # or jquery,angular,json,yaml
121
+ $ k8rb configs # list config parameters
122
+ $ rake server port=8000
123
+ $ open http://localhost:8000/
122
124
  $ ab -n 10000 -c 100 http://localhost:8000/api/hello
123
125
  ```
124
126
 
@@ -132,8 +134,8 @@ require 'keight'
132
134
  class HelloAction < K8::Action
133
135
 
134
136
  ## mapping
135
- mapping '', :GET=>:do_hello_world
136
- mapping '/{name:[a-zA-Z]+}', :GET=>:do_hello
137
+ mapping '', :GET=>:do_hello_world
138
+ mapping '/{name:\w+}', :GET=>:do_hello
137
139
 
138
140
  ## request, response, and helpers
139
141
 
@@ -199,7 +201,7 @@ class HelloAction < K8::Action
199
201
  end
200
202
 
201
203
  def handle_exception(ex) # exception handler
202
- meth = "on_#{ex.class}"
204
+ meth = "on_#{ex.class.name}"
203
205
  return __send__(meth, ex) if respond_to?(meth)
204
206
  super
205
207
  end
@@ -227,6 +229,144 @@ opts = {
227
229
  urlpath_cache_size: 0, # 0 means cache disabled
228
230
  }
229
231
  app = K8::RackApplication.new(urlpath_mapping, opts)
232
+
233
+ ## misc
234
+ p HelloAction[:do_update].method #=> :GET
235
+ p HelloAction[:do_update].urlpath(123) #=> "/api/books/123"
236
+ p HelloAction[:do_update].form_action_attr(123)
237
+ #=> "/api/books/123?_method=PUT"
238
+ ```
239
+
240
+
241
+ Topics
242
+ ------
243
+
244
+
245
+ ### Make Routing More Faster
246
+
247
+ Specify `urlpath_cache_size: n` (where n is 100 or so) to
248
+ `K8::RackApplication.new()`.
249
+
250
+ ```ruby
251
+ urlpath_mapping = [
252
+ ....
253
+ ]
254
+ rack_app = K8::RackApplication.new(urlpath_mapping,
255
+ urlpath_cache_size: 100) # !!!
256
+ ```
257
+
258
+ In general, there are two type of URL path pattern: fixed and variable.
259
+
260
+ * Fixed URL path pattern doesn't contain any URL path parameter.<br>
261
+ Example: `/`, `/api/books`, `/api/books/new`.
262
+ * Variable URL path pattern contains one or more URL path parameters.<br>
263
+ Example: `/api/books/{id}`, `/api/books/new.{format:html|json}`.
264
+
265
+ Keight.rb caches fixed patterns and doesn't variable ones, therefore
266
+ routing for fixed URL path is faster than variable one.
267
+
268
+ If `urlpath_cache_size: n` is specified, Keight.rb caches latest `n` entries
269
+ of request path matched to variable URL path pattern.
270
+ This will make routing for variable one much faster.
271
+
272
+
273
+ ### Default Pattern of URL Path Parameter
274
+
275
+ URL path parameter `{id}` and `{xxx_id}` are regarded as `{id:\d+}` and
276
+ `{xxx_id:\d+}` respectively and converted into positive interger automatically.
277
+ For example:
278
+
279
+ ```ruby
280
+ class BooksAction < K8::Action
281
+ mapping '/{id}', :GET=>:do_show
282
+ def do_show(id)
283
+ p id.class #=> Fixnum
284
+ ....
285
+ end
286
+ end
287
+ ```
288
+
289
+ URL path parameter `{date}` and `{xxx_date}` are regarded as
290
+ `{date:\d\d\d\d-\d\d-\d\d}` and `{xxx_date:\d\d\d\d-\d\d-\d\d}` respectively
291
+ and converted into Date object automatically.
292
+ For example:
293
+
294
+ ```ruby
295
+ class BlogAPI < K8::Action
296
+ mapping '/{date}', :GET=>:list_entries
297
+ def list_entries(date)
298
+ p date.class #=> Date
299
+ ....
300
+ end
301
+ end
302
+ ```
303
+
304
+ **If you specify `{id:\d+}` or `{date:\d\d\d\d-\d\d-\d\d}` explicitly,
305
+ URL path parameter value is not converted into integer nor Date object.**
306
+ In other words, you can cancel automatic conversion by specifing regular
307
+ expression of URL path parameters.
308
+
309
+
310
+ ### Nested Routing
311
+
312
+ ```ruby
313
+ urlpath_mapping = [
314
+ ['/api', [
315
+ ['/books' , BookAPI],
316
+ ['/books/{book_id}/comments' , BookCommentsAPI],
317
+ ]],
318
+ ]
319
+ ```
320
+
321
+
322
+ ### URL Path Helpers
323
+
324
+ ```ruby
325
+ p BooksAPI[:do_index].method #=> :GET
326
+ p BooksAPI[:do_index].urlpath() #=> "/api/books"
327
+
328
+ p BooksAPI[:do_update].method #=> :PUT
329
+ p BooksAPI[:do_update].urlpath(123) #=> "/api/books/123"
330
+ p BooksAPI[:do_update].form_action_attr(123) #=> "/api/books/123?_method=PUT"
331
+ ```
332
+
333
+ (Notice that these are availabe after `K8::RackApplication` object is created.)
334
+
335
+
336
+ ### Routing for JavaScript
337
+
338
+ Keight.rb can generate JavaScript routing file.
339
+
340
+ ```console
341
+ $ k8rb project myapp1
342
+ $ cd myapp1/
343
+ $ k8rb mapping --format=javascript | less # or 'jquery', 'angular'
344
+ $ mkdir -p static/js
345
+ $ jsfile=static/js/urlpath_mapping.js
346
+ $ rm -f $jsfile
347
+ $ echo 'var Mapping = {' >> $jsfile
348
+ $ k8rb mapping --format=javascript >> $jsfile
349
+ $ echo '};' >> $jsfile
350
+ ```
351
+
352
+
353
+ ### Download JavaScript Libraries
354
+
355
+ Keight.rb can download Javascript or CSS libraries from [cdnjs.com].
356
+ It is good idea to make layout of JavaScript libraries to be same as CDN.
357
+
358
+ [cdnjs.com]: https://cdnjs.com/
359
+
360
+ ```console
361
+ $ k8rb project myapp1
362
+ $ cd myapp1/
363
+ $ k8rb help cdnjs
364
+ $ k8rb cdnjs # list libraries
365
+ $ k8rb cdnjs 'jquery*' # search libraries
366
+ $ k8rb cdnjs jquery # list versions
367
+ $ k8rb cdnjs jquery 2.1.4 # download library
368
+ ## or
369
+ $ k8rb cdnjs --basedir=static/lib jquery 2.1.4
230
370
  ```
231
371
 
232
372
 
@@ -242,17 +382,17 @@ I don't think Keight.rb is so fast. Other frameworks are just too slow.
242
382
 
243
383
  #### How to setup template engine?
244
384
 
245
- Try `k8rb init myapp1; cd myapp1; less app/action.rb`.
385
+ Try `k8rb project myapp1; cd myapp1; less app/action.rb`.
246
386
 
247
387
 
248
388
  #### How to support static files?
249
389
 
250
- Try `k8rb init myapp1; cd myapp1; less app/action.rb`.
390
+ Try `k8rb project myapp1; cd myapp1; less app/action.rb`.
251
391
 
252
392
 
253
393
  #### How to setup session?
254
394
 
255
- Try `k8rb init myapp1; cd myapp1; less config.ru`.
395
+ Try `k8rb project myapp1; cd myapp1; less config.ru`.
256
396
 
257
397
 
258
398
  #### Can I use Rack::Request and Rack::Response instead of Keight's?
@@ -260,24 +400,9 @@ Try `k8rb init myapp1; cd myapp1; less config.ru`.
260
400
  Try `K8::REQUEST_CLASS = Rack::Request; K8::RESPONSE_CLASS = Rack::Response`.
261
401
 
262
402
 
263
- #### What `urlpath_cache_size: 0` means?
264
-
265
- `K8::RackApplication` can take `urlpath_cache_size: n` keyword arugment.
266
-
267
- * If `n == 0` then Keight.rb doesn't cache urlpath mapping containig
268
- urlpath parameters such as `/api/books/{id}`.
269
- * If `n > 0` then Keight.rb caches latest `n` entries of urlpath mapping
270
- containing urlpath parameters.
271
- * Keight.rb always caches urlpath mapping which has no urlpath parameters.
272
- For example, `/api/books` is always cached regardless
273
- `urlpath_cache_size:` value.
274
-
275
- If you need more performance, try `urlpath_cache_size: 1000` or so.
276
-
277
-
278
403
  License and Copyright
279
404
  ---------------------
280
405
 
281
406
  $License: MIT License $
282
407
 
283
- $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
408
+ $Copyright: copyright(c) 2014-2016 kuwata-lab.com all rights reserved $
data/Rakefile CHANGED
@@ -3,7 +3,7 @@
3
3
  ###
4
4
 
5
5
  RELEASE = ENV['rel'] || '0.0.0'
6
- COPYRIGHT = 'copyright(c) 2014-2015 kuwata-lab.com all rights reserved'
6
+ COPYRIGHT = 'copyright(c) 2014-2016 kuwata-lab.com all rights reserved'
7
7
  LICENSE = 'MIT License'
8
8
 
9
9
  PROJECT = 'keight'
@@ -2,13 +2,31 @@
2
2
 
3
3
  $LOAD_PATH << '.'
4
4
 
5
- require 'rack'
6
- require 'sinatra/base' rescue nil
7
- require 'rack-multiplexer' rescue nil
8
- require 'keight' rescue nil
5
+ def _version(cmdopt)
6
+ if cmdopt == '0'
7
+ return nil
8
+ end
9
+ begin
10
+ return yield
11
+ rescue LoadError
12
+ if cmdopt.to_s.empty?
13
+ return nil
14
+ else
15
+ raise
16
+ end
17
+ end
18
+ end
19
+
20
+ version_rack = _version($rack) { require 'rack' ; Rack.release }
21
+ version_sina = _version($sina) { require 'sinatra/base' ; Sinatra::VERSION }
22
+ version_mplx = _version($mplx) { require 'rack/multiplexer'; Rack::Multiplexer::VERSION }
23
+ version_k8 = _version($k8 ) { require 'keight' ; K8::RELEASE }
24
+ version_jet = _version($jet ) { require 'rack/jet_router' ; Rack::JetRouter::RELEASE }
9
25
 
26
+ $api_entries = ('a'..'z').each_with_index.map {|x, i| "%s%02d" % [x*3, i+1] }
10
27
 
11
- if defined?(Rack)
28
+
29
+ if version_rack
12
30
 
13
31
  class RackApp1
14
32
  def call(env)
@@ -48,14 +66,15 @@ if defined?(Rack)
48
66
  end
49
67
 
50
68
 
51
- $api_entries = %w[books authors account orders ranking about news support]
52
- $admin_entries = ('a'..'z').each_with_index.collect {|c,i| "%s%02d" % [c*3, i+1] }
53
-
54
-
55
- if defined?(Sinatra)
69
+ if version_sina
56
70
 
57
71
  class SinaApp < Sinatra::Base
58
72
 
73
+ set :sessions , false
74
+ set :logging , false
75
+ set :protection , false
76
+ set :x_cascade , false
77
+
59
78
  for x in $api_entries
60
79
  get "/api/#{x}" do "<h1>index</h1>" end
61
80
  post "/api/#{x}" do "<h1>create</h1>" end
@@ -66,14 +85,6 @@ if defined?(Sinatra)
66
85
  #get "/api/#{x}/:id/edit" do "<h1>edit</h1>" end
67
86
  end
68
87
 
69
- for x in $admin_entries # 'aaa01', 'bbb02', ..., 'zzz26'
70
- get "/admin/#{x}" do '<p>index</p>' end
71
- post "/admin/#{x}" do '<p>create</p>' end
72
- get "/admin/#{x}/:id" do '<p>show</p>' end
73
- put "/admin/#{x}/:id" do '<p>update</p>' end
74
- delete "/admin/#{x}/:id" do '<p>delete</p>' end
75
- end
76
-
77
88
  end
78
89
 
79
90
  sina_app = SinaApp.new
@@ -81,67 +92,35 @@ if defined?(Sinatra)
81
92
  end
82
93
 
83
94
 
84
- if defined?(Rack::Multiplexer)
85
-
86
- mplx_dummy = proc {|env|
87
- [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
88
- #req = Rack::Request.new(env)
89
- #resp = Rack::Response.new
90
- #[resp.status, resp.headers, ["<h1>index</h1>"]]
91
- }
92
-
93
- mplx_app1 = Rack::Multiplexer.new
94
-
95
- for x in $api_entries
96
- mplx_app1.get "/api/#{x}", mplx_dummy
97
- mplx_app1.post "/api/#{x}", mplx_dummy
98
- #mplx_app1.get "/api/#{x}/new", mplx_dummy
99
- mplx_app1.get "/api/#{x}/:id", mplx_dummy
100
- mplx_app1.post "/api/#{x}/:id", mplx_dummy
101
- mplx_app1.delete "/api/#{x}/:id", mplx_dummy
102
- #mplx_app1.get "/api/#{x}/:id/edit", mplx_dummy
103
- end
104
- for x in $admin_entries # 'aaa01', 'bbb02', ..., 'zzz26'
105
- mplx_app1.get "/admin/#{x}", mplx_dummy
106
- mplx_app1.post "/admin/#{x}", mplx_dummy
107
- mplx_app1.get "/admin/#{x}/:id", mplx_dummy
108
- mplx_app1.put "/admin/#{x}/:id", mplx_dummy
109
- mplx_app1.delete "/admin/#{x}/:id", mplx_dummy
110
- end
95
+ if version_mplx
111
96
 
112
- mplx_api = Rack::Multiplexer.new
113
- for x in $api_entries
114
- mplx_api.get "/api/#{x}", mplx_dummy
115
- mplx_api.post "/api/#{x}", mplx_dummy
116
- #mplx_api.get "/api/#{x}/new", mplx_dummy
117
- mplx_api.get "/api/#{x}/:id", mplx_dummy
118
- mplx_api.post "/api/#{x}/:id", mplx_dummy
119
- mplx_api.delete "/api/#{x}/:id", mplx_dummy
120
- #mplx_api.get "/api/#{x}/:id/edit", mplx_dummy
121
- end
122
- mplx_admin = Rack::Multiplexer.new
123
- for x in $admin_entries # 'aaa01', 'bbb02', ..., 'zzz26'
124
- mplx_admin.get "/admin/#{x}", mplx_dummy
125
- mplx_admin.post "/admin/#{x}", mplx_dummy
126
- mplx_admin.get "/admin/#{x}/:id", mplx_dummy
127
- mplx_admin.put "/admin/#{x}/:id", mplx_dummy
128
- mplx_admin.delete "/admin/#{x}/:id", mplx_dummy
129
- end
130
- mplx_app2 = proc {|env|
131
- urlpath = env['PATH_INFO']
132
- if urlpath.start_with?('/api')
133
- mplx_api.call(env)
134
- elsif urlpath.start_with?('/admin')
135
- mplx_admin.call(env)
136
- else
137
- [404, {}, []]
97
+ mplx_app = proc {
98
+ #
99
+ proc_ = proc {|env|
100
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
101
+ #req = Rack::Request.new(env)
102
+ #resp = Rack::Response.new
103
+ #[resp.status, resp.headers, ["<h1>index</h1>"]]
104
+ }
105
+ #
106
+ app = Rack::Multiplexer.new
107
+ for x in $api_entries
108
+ app.get "/api/#{x}", proc_
109
+ app.post "/api/#{x}", proc_
110
+ #app.get "/api/#{x}/new", proc_
111
+ app.get "/api/#{x}/:id", proc_
112
+ app.post "/api/#{x}/:id", proc_
113
+ app.delete "/api/#{x}/:id", proc_
114
+ #app.get "/api/#{x}/:id/edit", proc_
138
115
  end
139
- }
116
+ #
117
+ app
118
+ }.call()
140
119
 
141
120
  end
142
121
 
143
122
 
144
- if defined?(K8)
123
+ if version_k8
145
124
 
146
125
  class DummyAction < K8::Action
147
126
  mapping '', :GET=>:do_index, :POST=>:do_create
@@ -157,37 +136,59 @@ if defined?(K8)
157
136
  def do_edit(id) ; "<h1>edit</h1>"; end
158
137
  end
159
138
  #
160
- k8_app_opts = {urlpath_cache_size: 0}
161
- k8_app = K8::RackApplication.new(k8_app_opts)
162
- k8_app.mount '/api', [
163
- ['/books', DummyAction],
164
- ['/books/{id}/comments', DummyAction],
165
- ['/authors', DummyAction],
166
- ['/authors/{id}/comments', DummyAction],
167
- ['/account', DummyAction],
168
- ['/orders', DummyAction],
169
- ['/ranking', DummyAction],
170
- ['/about', DummyAction],
171
- ['/news', DummyAction],
172
- ['/support', DummyAction],
173
- ]
174
- pairs = $admin_entries.collect {|x| # 'aaa01', 'bbb02', ..., 'zzz26'
175
- ["/#{x}", DummyAction]
176
- }
177
- k8_app.mount '/admin', pairs
178
- #
179
- k8_app.find('/') # warm up
139
+ k8_app = proc {
140
+ mapping = [
141
+ ['/api', $api_entries.map {|x| ["/#{x}", DummyAction] }],
142
+ ]
143
+ opts = {
144
+ urlpath_cache_size: ($k8size || 0).to_i,
145
+ enable_urlpath_param_range: $k8range != '0',
146
+ }
147
+ K8::RackApplication.new(mapping, opts)
148
+ }.call()
149
+
150
+ end
151
+
152
+
153
+ if version_jet
154
+
155
+ jet_app = proc {
156
+ #
157
+ jet_proc = proc {|env|
158
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
159
+ #req = Rack::Request.new(env)
160
+ #resp = Rack::Response.new
161
+ #[resp.status, resp.headers, ["<h1>index</h1>"]]
162
+ }
163
+ methods1 = {:GET=>jet_proc, :POST=>jet_proc}
164
+ methods2 = {:GET=>jet_proc, :PUT=>jet_proc, :DELETE=>jet_proc}
165
+ #
166
+ arr = $api_entries.map {|x| ["/#{x}", [['', methods1], ['/:id', methods2]]] }
167
+ jet_mapping = [
168
+ ['/api', $api_entries.map {|x| ["/#{x}", [
169
+ ['', methods1],
170
+ ['/:id', methods2],
171
+ ]] }
172
+ ],
173
+ ]
174
+ #
175
+ jet_opts = {
176
+ urlpath_cache_size: ($jetcache || 0).to_i,
177
+ enable_urlpath_param_range: $jetrange != '0',
178
+ }
179
+ #
180
+ Rack::JetRouter.new(jet_mapping, jet_opts)
181
+ }.call()
180
182
 
181
183
  end
182
184
 
183
185
 
184
186
  def _chk(tuple)
185
187
  tuple[0] == 200 or raise "200 expected but got #{tuple[0]}"
186
- GC.start
187
188
  end
188
189
 
189
- $environ = Rack::MockRequest.env_for("http://localhost/")
190
- $environ['REQUEST_METHOD'] = 'GET'
190
+ require 'rack' unless defined?(Rack)
191
+ $environ = Rack::MockRequest.env_for("http://localhost/", method: 'GET')
191
192
 
192
193
  def newenv(path)
193
194
  env = $environ.dup
@@ -198,21 +199,27 @@ end
198
199
 
199
200
  require 'benchmarker'
200
201
 
202
+ N = ($N || 100000).to_i
201
203
 
202
- Benchmarker.new(:width=>30, :loop=>100000) do |bm|
203
-
204
- flag_rack = flag_sinatra = flag_multiplexer = flag_keight = false
205
- flag_rack = defined?(Rack)
206
- #flag_sinatra = defined?(Sinatra)
207
- flag_multiplexer = defined?(Rack::Multiplexer)
208
- flag_keight = defined?(K8)
209
-
210
- urlpaths = %w[/api/books /api/books/123 /api/support /api/support/123
211
- /admin/aaa01 /admin/aaa01/123 /admin/zzz26 /admin/zzz26/123]
204
+ Benchmarker.new(:width=>30, :loop=>N) do |bm|
212
205
 
206
+ urlpaths = [
207
+ '/api/aaa01',
208
+ '/api/aaa01/123',
209
+ '/api/zzz26',
210
+ '/api/zzz26/789',
211
+ ]
213
212
 
214
213
  tuple = nil
215
214
 
215
+ puts ""
216
+ puts "** rack : #{version_rack || '-'}"
217
+ puts "** rack-jet_router : #{version_jet || '-'}"
218
+ puts "** rack-multiplexer: #{version_mplx || '-'}"
219
+ puts "** sinatra : #{version_sina || '-'}"
220
+ puts "** keight : #{version_k8 || '-'}"
221
+ puts ""
222
+ puts "** N=#{N}"
216
223
 
217
224
  ### empty task
218
225
 
@@ -222,10 +229,11 @@ Benchmarker.new(:width=>30, :loop=>100000) do |bm|
222
229
 
223
230
 
224
231
  ### Rack
225
- if flag_rack
232
+ if version_rack
233
+ rack_labels = ['Rack', 'R:Rq', 'R:Rs', 'RqRs']
226
234
  rack_apps = [rack_app1, rack_app2, rack_app3, rack_app4]
227
- for rack_app, i in rack_apps.each_with_index
228
- bm.task("(Rack#{i+1}) /some/where") do
235
+ for rack_app, label in rack_apps.zip(rack_labels)
236
+ bm.task("(#{label}) /some/where") do
229
237
  tuple = rack_app.call(newenv("/some/where"))
230
238
  end
231
239
  _chk(tuple)
@@ -234,7 +242,7 @@ Benchmarker.new(:width=>30, :loop=>100000) do |bm|
234
242
 
235
243
 
236
244
  ### Sinatra
237
- if flag_sinatra
245
+ if version_sina
238
246
  for upath in urlpaths
239
247
  bm.task("(Sina) #{upath}") do
240
248
  tuple = sina_app.call(newenv(upath))
@@ -245,34 +253,126 @@ Benchmarker.new(:width=>30, :loop=>100000) do |bm|
245
253
 
246
254
 
247
255
  ### Rack::Multiplexer
248
- if flag_multiplexer
256
+ if version_mplx
249
257
  for upath in urlpaths
250
258
  bm.task("(Mplx) #{upath}") do
251
- tuple = mplx_app1.call(newenv(upath))
259
+ tuple = mplx_app.call(newenv(upath))
252
260
  end
253
261
  _chk(tuple)
254
262
  end
255
263
  end
256
264
 
257
- if flag_multiplexer
265
+
266
+ ### Keight
267
+
268
+ if version_k8
258
269
  for upath in urlpaths
259
- bm.task("(Mplx') #{upath}") do
260
- tuple = mplx_app2.call(newenv(upath))
270
+ bm.task("(K8 ) #{upath}") do
271
+ tuple = k8_app.call(newenv(upath))
261
272
  end
262
273
  _chk(tuple)
263
274
  end
264
275
  end
265
276
 
266
277
 
267
- ### Keight
278
+ ### Rack::JetRouter
268
279
 
269
- if flag_keight
280
+ if version_jet
270
281
  for upath in urlpaths
271
- bm.task("(K8) #{upath}") do
272
- tuple = k8_app.call(newenv(upath))
282
+ bm.task("(JetR) #{upath}") do
283
+ tuple = jet_app.call(newenv(upath))
273
284
  end
274
285
  _chk(tuple)
275
286
  end
276
287
  end
277
288
 
278
289
  end
290
+
291
+
292
+ __END__
293
+
294
+ ###
295
+ ### Example result
296
+ ###
297
+
298
+ $ ruby -I../lib -I. -s bench.rb -N=1000000
299
+
300
+ benchmarker.rb: release 0.0.0
301
+ RUBY_VERSION: 2.3.0
302
+ RUBY_PATCHLEVEL: 0
303
+ RUBY_PLATFORM: x86_64-darwin15
304
+
305
+ ** rack : 1.6.4
306
+ ** rack-jet_router : 1.1.0
307
+ ** rack-multiplexer: 0.0.8
308
+ ** sinatra : 1.4.6
309
+ ** keight : 0.2.0
310
+
311
+ ** N=1000000
312
+
313
+ ## user sys total real
314
+ (Empty) 7.3000 0.0900 7.3900 7.4131
315
+ (Rack) /some/where 0.8400 -0.0400 0.8000 0.7903
316
+ (R:Rq) /some/where 0.8400 -0.0500 0.7900 0.7743
317
+ (R:Rs) /some/where 6.1600 -0.0500 6.1100 6.0898
318
+ (RqRs) /some/where 6.4200 -0.0600 6.3600 6.3407
319
+ (Sina) /api/aaa01 84.5700 18.0800 102.6500 102.7069
320
+ (Sina) /api/aaa01/123 94.1300 18.4800 112.6100 112.6892
321
+ (Sina) /api/zzz26 125.7300 19.0800 144.8100 145.0454
322
+ (Sina) /api/zzz26/789 133.8000 18.9600 152.7600 152.9070
323
+ (Mplx) /api/aaa01 5.0200 0.1700 5.1900 5.1821
324
+ (Mplx) /api/aaa01/123 16.7100 0.3100 17.0200 17.0086
325
+ (Mplx) /api/zzz26 23.3700 -0.0400 23.3300 23.3190
326
+ (Mplx) /api/zzz26/789 35.6500 0.0100 35.6600 35.6661
327
+ (K8 ) /api/aaa01 5.9200 0.0300 5.9500 5.9423
328
+ (K8 ) /api/aaa01/123 9.2200 0.0900 9.3100 9.2934
329
+ (K8 ) /api/zzz26 6.2700 0.0600 6.3300 6.3158
330
+ (K8 ) /api/zzz26/789 10.0300 0.1300 10.1600 10.1547
331
+ (JetR) /api/aaa01 1.1800 0.0400 1.2200 1.2154
332
+ (JetR) /api/aaa01/123 5.0400 0.1100 5.1500 5.1431
333
+ (JetR) /api/zzz26 0.9600 0.0300 0.9900 0.9681
334
+ (JetR) /api/zzz26/789 5.6900 0.1100 5.8000 5.7946
335
+
336
+ ## Ranking real
337
+ (R:Rq) /some/where 0.7743 (100.0%) ********************
338
+ (Rack) /some/where 0.7903 ( 98.0%) ********************
339
+ (JetR) /api/zzz26 0.9681 ( 80.0%) ****************
340
+ (JetR) /api/aaa01 1.2154 ( 63.7%) *************
341
+ (JetR) /api/aaa01/123 5.1431 ( 15.1%) ***
342
+ (Mplx) /api/aaa01 5.1821 ( 14.9%) ***
343
+ (JetR) /api/zzz26/789 5.7946 ( 13.4%) ***
344
+ (K8 ) /api/aaa01 5.9423 ( 13.0%) ***
345
+ (R:Rs) /some/where 6.0898 ( 12.7%) ***
346
+ (K8 ) /api/zzz26 6.3158 ( 12.3%) **
347
+ (RqRs) /some/where 6.3407 ( 12.2%) **
348
+ (K8 ) /api/aaa01/123 9.2934 ( 8.3%) **
349
+ (K8 ) /api/zzz26/789 10.1547 ( 7.6%) **
350
+ (Mplx) /api/aaa01/123 17.0086 ( 4.6%) *
351
+ (Mplx) /api/zzz26 23.3190 ( 3.3%) *
352
+ (Mplx) /api/zzz26/789 35.6661 ( 2.2%)
353
+ (Sina) /api/aaa01 102.7069 ( 0.8%)
354
+ (Sina) /api/aaa01/123 112.6892 ( 0.7%)
355
+ (Sina) /api/zzz26 145.0454 ( 0.5%)
356
+ (Sina) /api/zzz26/789 152.9070 ( 0.5%)
357
+
358
+ ## Matrix real [01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
359
+ [01] (Rack2) /some/where 0.7743 100.0% 102.1% 125.0% 157.0% 664.2% 669.2% 748.3% 767.4% 786.5% 815.6% 818.9% 1200.2% 1311.4% 2196.6% 3011.5% 4606.1% 13264.0% 14553.1% 18731.7% 19747.0%
360
+ [02] (Rack1) /some/where 0.7903 98.0% 100.0% 122.5% 153.8% 650.7% 655.7% 733.2% 751.9% 770.5% 799.1% 802.3% 1175.9% 1284.8% 2152.1% 2950.5% 4512.7% 12995.2% 14258.3% 18352.2% 19346.9%
361
+ [03] (JetR) /api/zzz26 0.9681 80.0% 81.6% 100.0% 125.5% 531.2% 535.3% 598.5% 613.8% 629.0% 652.4% 654.9% 959.9% 1048.9% 1756.9% 2408.7% 3684.0% 10608.8% 11639.9% 14982.1% 15794.1%
362
+ [04] (JetR) /api/aaa01 1.2154 63.7% 65.0% 79.7% 100.0% 423.2% 426.4% 476.8% 488.9% 501.0% 519.6% 521.7% 764.6% 835.5% 1399.4% 1918.6% 2934.5% 8450.4% 9271.7% 11933.8% 12580.6%
363
+ [05] (JetR) /api/aaa01/123 5.1431 15.1% 15.4% 18.8% 23.6% 100.0% 100.8% 112.7% 115.5% 118.4% 122.8% 123.3% 180.7% 197.4% 330.7% 453.4% 693.5% 1997.0% 2191.1% 2820.2% 2973.1%
364
+ [06] (Mplx) /api/aaa01 5.1821 14.9% 15.3% 18.7% 23.5% 99.2% 100.0% 111.8% 114.7% 117.5% 121.9% 122.4% 179.3% 196.0% 328.2% 450.0% 688.3% 1982.0% 2174.6% 2799.0% 2950.7%
365
+ [07] (JetR) /api/zzz26/789 5.7946 13.4% 13.6% 16.7% 21.0% 88.8% 89.4% 100.0% 102.5% 105.1% 109.0% 109.4% 160.4% 175.2% 293.5% 402.4% 615.5% 1772.5% 1944.7% 2503.1% 2638.8%
366
+ [08] (K8) /api/aaa01 5.9423 13.0% 13.3% 16.3% 20.5% 86.6% 87.2% 97.5% 100.0% 102.5% 106.3% 106.7% 156.4% 170.9% 286.2% 392.4% 600.2% 1728.4% 1896.4% 2440.9% 2573.2%
367
+ [09] (Rack3) /some/where 6.0898 12.7% 13.0% 15.9% 20.0% 84.5% 85.1% 95.2% 97.6% 100.0% 103.7% 104.1% 152.6% 166.7% 279.3% 382.9% 585.7% 1686.5% 1850.5% 2381.8% 2510.9%
368
+ [10] (K8) /api/zzz26 6.3158 12.3% 12.5% 15.3% 19.2% 81.4% 82.0% 91.7% 94.1% 96.4% 100.0% 100.4% 147.1% 160.8% 269.3% 369.2% 564.7% 1626.2% 1784.3% 2296.6% 2421.0%
369
+ [11] (Rack4) /some/where 6.3407 12.2% 12.5% 15.3% 19.2% 81.1% 81.7% 91.4% 93.7% 96.0% 99.6% 100.0% 146.6% 160.2% 268.2% 367.8% 562.5% 1619.8% 1777.2% 2287.5% 2411.5%
370
+ [12] (K8) /api/aaa01/123 9.2934 8.3% 8.5% 10.4% 13.1% 55.3% 55.8% 62.4% 63.9% 65.5% 68.0% 68.2% 100.0% 109.3% 183.0% 250.9% 383.8% 1105.2% 1212.6% 1560.7% 1645.3%
371
+ [13] (K8) /api/zzz26/789 10.1547 7.6% 7.8% 9.5% 12.0% 50.6% 51.0% 57.1% 58.5% 60.0% 62.2% 62.4% 91.5% 100.0% 167.5% 229.6% 351.2% 1011.4% 1109.7% 1428.4% 1505.8%
372
+ [14] (Mplx) /api/aaa01/123 17.0086 4.6% 4.6% 5.7% 7.1% 30.2% 30.5% 34.1% 34.9% 35.8% 37.1% 37.3% 54.6% 59.7% 100.0% 137.1% 209.7% 603.9% 662.5% 852.8% 899.0%
373
+ [15] (Mplx) /api/zzz26 23.3190 3.3% 3.4% 4.2% 5.2% 22.1% 22.2% 24.8% 25.5% 26.1% 27.1% 27.2% 39.9% 43.5% 72.9% 100.0% 152.9% 440.4% 483.3% 622.0% 655.7%
374
+ [16] (Mplx) /api/zzz26/789 35.6661 2.2% 2.2% 2.7% 3.4% 14.4% 14.5% 16.2% 16.7% 17.1% 17.7% 17.8% 26.1% 28.5% 47.7% 65.4% 100.0% 288.0% 316.0% 406.7% 428.7%
375
+ [17] (Sina) /api/aaa01 102.7069 0.8% 0.8% 0.9% 1.2% 5.0% 5.0% 5.6% 5.8% 5.9% 6.1% 6.2% 9.0% 9.9% 16.6% 22.7% 34.7% 100.0% 109.7% 141.2% 148.9%
376
+ [18] (Sina) /api/aaa01/123 112.6892 0.7% 0.7% 0.9% 1.1% 4.6% 4.6% 5.1% 5.3% 5.4% 5.6% 5.6% 8.2% 9.0% 15.1% 20.7% 31.6% 91.1% 100.0% 128.7% 135.7%
377
+ [19] (Sina) /api/zzz26 145.0454 0.5% 0.5% 0.7% 0.8% 3.5% 3.6% 4.0% 4.1% 4.2% 4.4% 4.4% 6.4% 7.0% 11.7% 16.1% 24.6% 70.8% 77.7% 100.0% 105.4%
378
+ [20] (Sina) /api/zzz26/789 152.9070 0.5% 0.5% 0.6% 0.8% 3.4% 3.4% 3.8% 3.9% 4.0% 4.1% 4.1% 6.1% 6.6% 11.1% 15.3% 23.3% 67.2% 73.7% 94.9% 100.0%