keight 0.0.1

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.
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