keight 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +263 -0
  4. data/Rakefile +92 -0
  5. data/bench/bench.rb +278 -0
  6. data/bench/benchmarker.rb +502 -0
  7. data/bin/k8rb +496 -0
  8. data/keight.gemspec +36 -0
  9. data/lib/keight/skeleton/.gitignore +10 -0
  10. data/lib/keight/skeleton/app/action.rb +98 -0
  11. data/lib/keight/skeleton/app/api/hello.rb +39 -0
  12. data/lib/keight/skeleton/app/form/.keep +0 -0
  13. data/lib/keight/skeleton/app/helper/.keep +0 -0
  14. data/lib/keight/skeleton/app/model/.keep +0 -0
  15. data/lib/keight/skeleton/app/model.rb +144 -0
  16. data/lib/keight/skeleton/app/page/welcome.rb +17 -0
  17. data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
  18. data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
  19. data/lib/keight/skeleton/app/usecase/.keep +0 -0
  20. data/lib/keight/skeleton/config/app.rb +29 -0
  21. data/lib/keight/skeleton/config/app_dev.private +11 -0
  22. data/lib/keight/skeleton/config/app_dev.rb +8 -0
  23. data/lib/keight/skeleton/config/app_prod.rb +7 -0
  24. data/lib/keight/skeleton/config/app_stg.rb +5 -0
  25. data/lib/keight/skeleton/config/app_test.private +11 -0
  26. data/lib/keight/skeleton/config/app_test.rb +8 -0
  27. data/lib/keight/skeleton/config/server_puma.rb +22 -0
  28. data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
  29. data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
  30. data/lib/keight/skeleton/config.rb +44 -0
  31. data/lib/keight/skeleton/config.ru +21 -0
  32. data/lib/keight/skeleton/index.txt +38 -0
  33. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
  34. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
  35. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
  36. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
  37. data/lib/keight/skeleton/tmp/upload/.keep +0 -0
  38. data/lib/keight.rb +2017 -0
  39. data/test/data/example1.jpg +0 -0
  40. data/test/data/example1.png +0 -0
  41. data/test/data/multipart.form +0 -0
  42. data/test/data/wabisabi.js +77 -0
  43. data/test/data/wabisabi.js.gz +0 -0
  44. data/test/keight_test.rb +3161 -0
  45. data/test/oktest.rb +1537 -0
  46. metadata +114 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4c4b037e58fd8fe6bf09a20d6d682b749eb33aa1
4
+ data.tar.gz: ad00095bed413d481bba4c1ad309e93a5363781e
5
+ SHA512:
6
+ metadata.gz: 6ad2bde75007e0b5b65349d899f05cc27b85146845702e3057d888df325288a87bc182575e9752db1c24c5fb0ae79fa4e9965c0e3fd8e8e9127453bda55fa6fc
7
+ data.tar.gz: f9fa23872351a09629b3365d312ff5d4b45fdff6c90aa2cebd7f905f2ac3f9157ec1f51d1fe93fa2ab5c52a7e3ddf8ea361e302f04810d5b4687363b3e10c38e
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,263 @@
1
+ Keight.rb README
2
+ ================
3
+
4
+ ($Release: 0.0.1 $)
5
+
6
+
7
+ Overview
8
+ --------
9
+
10
+ Keight.rb is the very fast web application framework for Ruby.
11
+ It is about 100 times faster than Rails and 20 times faster than Sinatra.
12
+
13
+ *Keight.rb is under development and is subject to change without notice.*
14
+
15
+
16
+ Benchmarks
17
+ ----------
18
+
19
+ Measured with `app.call(env)` style in order to exclude server overhead:
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 |
30
+
31
+ * Ruby 2.2.3
32
+ * Rails 4.2.4
33
+ * Sinatra 1.4.6
34
+ * Rack 1.6.4 (= Rack::Request + Rack::Response)
35
+ * Keight 0.1.0
36
+
37
+ (Script: https://gist.github.com/kwatch/c634e91d2d6a6c4b1d40 )
38
+
39
+
40
+ Quick Tutorial
41
+ --------------
42
+
43
+ ```console
44
+ $ gem install keight
45
+ $ vi hello.rb
46
+ $ vi config.ru
47
+ $ rackup -c config.ru -p 8000
48
+ ```
49
+
50
+ hello.rb:
51
+
52
+ ```ruby
53
+ # -*- coding: utf-8 -*-
54
+ require 'keight'
55
+
56
+ class HelloAction < K8::Action
57
+
58
+ mapping '' , :GET=>:do_index, :POST=>:do_create
59
+ mapping '/{id}' , :GET=>:do_show, :PUT=>:do_update, :DELETE=>:do_delete
60
+
61
+ def do_index
62
+ #{"message"=>"Hello"} # JSON
63
+ "<h1>Hello</h1>" # HTML
64
+ end
65
+
66
+ def do_show(id)
67
+ ## 'id' or 'xxx_id' will be converted into integer.
68
+ "<h1>Hello: id=#{id.inspect}</h1>"
69
+ end
70
+
71
+ def do_create ; "<p>create</p>"; end
72
+ def do_update(id); "<p>update</p>"; end
73
+ def do_delete(id); "<p>delete</p>"; end
74
+
75
+ end
76
+ ```
77
+
78
+ config.rb:
79
+
80
+ ```ruby
81
+ # -*- coding: utf-8 -*-
82
+ require 'keight'
83
+ require './hello'
84
+
85
+ app = K8::RackApplication.new
86
+ app.mount '/hello', HelloAction
87
+
88
+ run app
89
+ ```
90
+
91
+ Open http://localhost:8000/hello or http://localhost:8000/hello/123 by browser.
92
+
93
+ Do you like it? If so, try `k8rb init myapp1` to generate project skeleton.
94
+
95
+ ```console
96
+ $ k8rb init myapp1
97
+ $ cd myapp1
98
+ $ export APP_ENV=dev # 'dev', 'prod', or 'stg'
99
+ $ k8rb mapping
100
+ $ k8rb configs
101
+ $ rackup -c config.ru -p 8000
102
+ $ ab -n 1000000 -c 100 http://127.0.0.1:8000/api/hello
103
+ ```
104
+
105
+
106
+ CheatSheet
107
+ ----------
108
+
109
+ ```ruby
110
+ require 'keight'
111
+
112
+ class HelloAction < K8::Action
113
+
114
+ ## mapping
115
+ mapping '', :GET=>:do_hello_world
116
+ mapping '/{name:[a-zA-Z]+}', :GET=>:do_hello
117
+
118
+ ## request, response, and helpers
119
+
120
+ def do_hello_world
121
+ do_hello('World')
122
+ end
123
+
124
+ def do_hello(name)
125
+
126
+ ## request
127
+ @req # K8::Request object (!= Rack::Request)
128
+ @req.env # Rack environment
129
+ @req.method # ex: :GET, :POST, :PUT, ...
130
+ @req.request_method # ex: "GET", "POST", "PUT", ...
131
+ @req.path # ex: '/api/hello'
132
+ @req.query # query string (Hash)
133
+ @req.form # form data (Hash)
134
+ @req.multipart # multipart form data ([Hash, Hash])
135
+ @req.json # JSON data (Hash)
136
+ @req.params # query, form, multipart or json
137
+ @req.cookies # cookies (Hash)
138
+ @req.xhr? # true when requested by jQuery etc
139
+ @req.client_ip_addr # ex: '127.0.0.1'
140
+
141
+ ## response
142
+ @resp # K8::Response object (!= Rack::Response)
143
+ @resp.status_code # ex: 200
144
+ @resp.status # alias of @resp.status_code
145
+ @resp.headers # Hash object
146
+ @resp.set_cookie(k, v) # cookie
147
+ @resp.content_type # same as @resp.headers['Content-Type']
148
+ @resp.content_length # same as @resp.headers['Content-Length'].to_i
149
+
150
+ ## session (requires Rack::Session)
151
+ @sess[key] = val # set session data
152
+ @sess[key] # get session data
153
+
154
+ ## helpers
155
+ token = csrf_token() # get csrf token
156
+ validation_failed() # same as @resp.status_code = 422
157
+ return redirect_to(location, 302, flash: "message")
158
+ return send_file(filepath)
159
+
160
+ end
161
+
162
+
163
+ ## hook methods
164
+
165
+ def before_action # setup
166
+ super
167
+ end
168
+
169
+ def after_action(ex) # teardown
170
+ super
171
+ end
172
+
173
+ def handle_content(content) # convert content
174
+ if content.is_a?(Hash)
175
+ @resp.content_type = 'application/json'
176
+ return [JSON.dump(content)]
177
+ end
178
+ super
179
+ end
180
+
181
+ def handle_exception(ex) # exception handler
182
+ meth = "on_#{ex.class}"
183
+ return __send__(meth, ex) if respond_to?(meth)
184
+ super
185
+ end
186
+
187
+ def csrf_protection_required?
188
+ x = @req.method
189
+ return x == :POST || x == :PUT || x == :DELETE
190
+ end
191
+
192
+ end
193
+
194
+ ## urlpath mapping
195
+ urlpath_mapping = [
196
+ ['/' , './app/page/welcome:WelcomePage'],
197
+ ['/api', [
198
+ ['/books' , './app/api/books:BooksAPI'],
199
+ ['/books/{book_id}/comments'
200
+ , './app/api/book_comments:BookCommentsAPI'],
201
+ ['/orders' , './app/api/orders:OrdersAPI'],
202
+ ]],
203
+ ]
204
+
205
+ ## application
206
+ opts = {
207
+ urlpath_cache_size: 0, # 0 means cache disabled
208
+ }
209
+ app = K8::RackApplication.new(urlpath_mapping, opts)
210
+ ```
211
+
212
+
213
+ FAQ
214
+ ---
215
+
216
+ #### Why Keight.rb is so fast?
217
+
218
+ I don't think Keight.rb is so fast. Other frameworks are just too slow.
219
+
220
+ **You should know that Rails is slow due to Rails itself, and not to Ruby.**
221
+
222
+
223
+ #### How to setup template engine?
224
+
225
+ Try `k8rb init myapp1; cd myapp1; less app/action.rb`.
226
+
227
+
228
+ #### How to support static files?
229
+
230
+ Try `k8rb init myapp1; cd myapp1; less app/action.rb`.
231
+
232
+
233
+ #### How to setup session?
234
+
235
+ Try `k8rb init myapp1; cd myapp1; less config.ru`.
236
+
237
+
238
+ #### Can I use Rack::Request and Rack::Response instead of Keight's?
239
+
240
+ Try `K8::REQUEST_CLASS = Rack::Request; K8::RESPONSE_CLASS = Rack::Response`.
241
+
242
+
243
+ #### What `urlpath_cache_size: 0` means?
244
+
245
+ `K8::RackApplication` can take `urlpath_cache_size: n` keyword arugment.
246
+
247
+ * If `n == 0` then Keight.rb doesn't cache urlpath mapping containig
248
+ urlpath parameters such as `/api/books/{id}`.
249
+ * If `n > 0` then Keight.rb caches latest `n` entries of urlpath mapping
250
+ containing urlpath parameters.
251
+ * Keight.rb always caches urlpath mapping which has no urlpath parameters.
252
+ For example, `/api/books` is always cached regardless
253
+ `urlpath_cache_size:` value.
254
+
255
+ If you need more performance, try `urlpath_cache_size: 1000` or so.
256
+
257
+
258
+ License and Copyright
259
+ ---------------------
260
+
261
+ $License: MIT License $
262
+
263
+ $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
data/Rakefile ADDED
@@ -0,0 +1,92 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+
5
+ RELEASE = ENV['rel'] || '0.0.0'
6
+ COPYRIGHT = 'copyright(c) 2014-2015 kuwata-lab.com all rights reserved'
7
+ LICENSE = 'MIT License'
8
+
9
+ PROJECT = 'keight'
10
+
11
+ ###
12
+
13
+ task :default => :test
14
+
15
+ def edit_content(content)
16
+ s = content
17
+ s = s.gsub /\$Release\:.*?\$/, "$Release\: #{RELEASE} $"
18
+ s = s.gsub /\$Copyright\:.*?\$/, "$Copyright\: #{COPYRIGHT} $"
19
+ s = s.gsub /\$License\:.*?\$/, "$License\: #{LICENSE} $"
20
+ s = s.gsub /\$Release\$/, RELEASE
21
+ s = s.gsub /\$Copyright\$/, COPYRIGHT
22
+ s = s.gsub /\$License\$/, LICENSE
23
+ s
24
+ end
25
+
26
+
27
+ desc "run test scripts"
28
+ task :test do
29
+ #sh "ruby -r minitest/autorun test/*_test.rb"
30
+ sh "ruby test/#{PROJECT}_test.rb"
31
+ end
32
+
33
+
34
+ desc "remove *.rbc"
35
+ task :clean do
36
+ rm_f [Dir.glob("lib/**/*.rbc"), Dir.glob("test/**/*.rbc")]
37
+ end
38
+
39
+
40
+ desc "copy files into 'dist/#{RELEASE}'"
41
+ task :dist => :clean do
42
+ require_release_number()
43
+ spec_src = File.open("#{PROJECT}.gemspec") {|f| f.read }
44
+ spec = eval spec_src
45
+ dir = "dist/#{RELEASE}"
46
+ rm_rf dir
47
+ mkdir_p dir
48
+ sh "tar cf - #{spec.files.join(' ')} | (cd #{dir}; tar xvf -)"
49
+ spec.files.each do |fpath|
50
+ next if fpath =~ /\.(gz|jpg|png|form)\z/
51
+ #filepath = File.join(dir, fpath)
52
+ #content = File.open(filepath, 'rb:utf-8') {|f| f.read }
53
+ #new_content = edit_content(content)
54
+ #File.open(filepath, 'wb:utf-8') {|f| f.write(new_content) }
55
+ content = File.open(File.join(dir, fpath), 'r+b:utf-8') do |f|
56
+ content = f.read
57
+ new_content = edit_content(content)
58
+ f.rewind()
59
+ f.truncate(0)
60
+ f.write(new_content)
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ desc "create rubygem pacakge"
67
+ task :package => :dist do
68
+ require_release_number()
69
+ chdir "dist/#{RELEASE}" do
70
+ sh "gem build *.gemspec"
71
+ end
72
+ mv Dir.glob("dist/#{RELEASE}/*.gem"), 'dist'
73
+ end
74
+
75
+
76
+ desc "release gem"
77
+ task :release => :package do
78
+ require_release_number()
79
+ sh "git tag ruby-#{RELEASE}"
80
+ chdir "dist" do
81
+ sh "gem push #{PROJECT}-#{RELEASE}.gem"
82
+ end
83
+ end
84
+
85
+
86
+ def require_release_number
87
+ if RELEASE == '0.0.0'
88
+ $stderr.puts "*** Release number is not speicified"
89
+ $stderr.puts "*** Usage: rake <task> rel=X.X.X"
90
+ raise StandardError
91
+ end
92
+ end
data/bench/bench.rb ADDED
@@ -0,0 +1,278 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $LOAD_PATH << '.'
4
+
5
+ require 'rack'
6
+ require 'sinatra/base' rescue nil
7
+ require 'rack-multiplexer' rescue nil
8
+ require 'keight' rescue nil
9
+
10
+
11
+ if defined?(Rack)
12
+
13
+ class RackApp1
14
+ def call(env)
15
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
16
+ end
17
+ end
18
+
19
+ class RackApp2
20
+ def call(env)
21
+ req = Rack::Request.new(env)
22
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
23
+ end
24
+ end
25
+
26
+ class RackApp3
27
+ def call(env)
28
+ resp = Rack::Response.new
29
+ #[resp.status, resp.headers, ["<h1>hello</h1>"]]
30
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
31
+ end
32
+ end
33
+
34
+ class RackApp4
35
+ def call(env)
36
+ req = Rack::Request.new(env)
37
+ resp = Rack::Response.new
38
+ #[resp.status, resp.headers, ["<h1>hello</h1>"]]
39
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
40
+ end
41
+ end
42
+
43
+ rack_app1 = RackApp1.new
44
+ rack_app2 = RackApp2.new
45
+ rack_app3 = RackApp3.new
46
+ rack_app4 = RackApp4.new
47
+
48
+ end
49
+
50
+
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)
56
+
57
+ class SinaApp < Sinatra::Base
58
+
59
+ for x in $api_entries
60
+ get "/api/#{x}" do "<h1>index</h1>" end
61
+ post "/api/#{x}" do "<h1>create</h1>" end
62
+ #get "/api/#{x}/new" do "<h1>new</h1>" end
63
+ get "/api/#{x}/:id" do "<h1>show</h1>" end
64
+ put "/api/#{x}/:id" do "<h1>update</h1>" end
65
+ delete "/api/#{x}/:id" do "<h1>delete</h1>" end
66
+ #get "/api/#{x}/:id/edit" do "<h1>edit</h1>" end
67
+ end
68
+
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
+ end
78
+
79
+ sina_app = SinaApp.new
80
+
81
+ end
82
+
83
+
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
111
+
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, {}, []]
138
+ end
139
+ }
140
+
141
+ end
142
+
143
+
144
+ if defined?(K8)
145
+
146
+ class DummyAction < K8::Action
147
+ mapping '', :GET=>:do_index, :POST=>:do_create
148
+ #mapping '/new', :GET=>:do_new
149
+ mapping '/{id}', :GET=>:do_show, :PUT=>:do_edit, :DELETE=>:do_delete
150
+ #mapping '/{id}/edit', :GET=>:do_edit
151
+ def do_index ; "<h1>index</h1>"; end
152
+ def do_create ; "<h1>create</h1>"; end
153
+ def do_new ; "<h1>new</h1>"; end
154
+ def do_show(id) ; "<h1>show</h1>"; end
155
+ def do_update(id) ; "<h1>update</h1>"; end
156
+ def do_delete(id) ; "<h1>delete</h1>"; end
157
+ def do_edit(id) ; "<h1>edit</h1>"; end
158
+ end
159
+ #
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
180
+
181
+ end
182
+
183
+
184
+ def _chk(tuple)
185
+ tuple[0] == 200 or raise "200 expected but got #{tuple[0]}"
186
+ GC.start
187
+ end
188
+
189
+ $environ = Rack::MockRequest.env_for("http://localhost/")
190
+ $environ['REQUEST_METHOD'] = 'GET'
191
+
192
+ def newenv(path)
193
+ env = $environ.dup
194
+ env['PATH_INFO'] = path
195
+ env
196
+ end
197
+
198
+
199
+ require 'benchmarker'
200
+
201
+
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]
212
+
213
+
214
+ tuple = nil
215
+
216
+
217
+ ### empty task
218
+
219
+ bm.empty_task do
220
+ newenv("/api/hello")
221
+ end
222
+
223
+
224
+ ### Rack
225
+ if flag_rack
226
+ 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
229
+ tuple = rack_app.call(newenv("/some/where"))
230
+ end
231
+ _chk(tuple)
232
+ end
233
+ end
234
+
235
+
236
+ ### Sinatra
237
+ if flag_sinatra
238
+ for upath in urlpaths
239
+ bm.task("(Sina) #{upath}") do
240
+ tuple = sina_app.call(newenv(upath))
241
+ end
242
+ _chk(tuple)
243
+ end
244
+ end
245
+
246
+
247
+ ### Rack::Multiplexer
248
+ if flag_multiplexer
249
+ for upath in urlpaths
250
+ bm.task("(Mplx) #{upath}") do
251
+ tuple = mplx_app1.call(newenv(upath))
252
+ end
253
+ _chk(tuple)
254
+ end
255
+ end
256
+
257
+ if flag_multiplexer
258
+ for upath in urlpaths
259
+ bm.task("(Mplx') #{upath}") do
260
+ tuple = mplx_app2.call(newenv(upath))
261
+ end
262
+ _chk(tuple)
263
+ end
264
+ end
265
+
266
+
267
+ ### Keight
268
+
269
+ if flag_keight
270
+ for upath in urlpaths
271
+ bm.task("(K8) #{upath}") do
272
+ tuple = k8_app.call(newenv(upath))
273
+ end
274
+ _chk(tuple)
275
+ end
276
+ end
277
+
278
+ end