keight 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +263 -0
- data/Rakefile +92 -0
- data/bench/bench.rb +278 -0
- data/bench/benchmarker.rb +502 -0
- data/bin/k8rb +496 -0
- data/keight.gemspec +36 -0
- data/lib/keight/skeleton/.gitignore +10 -0
- data/lib/keight/skeleton/app/action.rb +98 -0
- data/lib/keight/skeleton/app/api/hello.rb +39 -0
- data/lib/keight/skeleton/app/form/.keep +0 -0
- data/lib/keight/skeleton/app/helper/.keep +0 -0
- data/lib/keight/skeleton/app/model/.keep +0 -0
- data/lib/keight/skeleton/app/model.rb +144 -0
- data/lib/keight/skeleton/app/page/welcome.rb +17 -0
- data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
- data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
- data/lib/keight/skeleton/app/usecase/.keep +0 -0
- data/lib/keight/skeleton/config/app.rb +29 -0
- data/lib/keight/skeleton/config/app_dev.private +11 -0
- data/lib/keight/skeleton/config/app_dev.rb +8 -0
- data/lib/keight/skeleton/config/app_prod.rb +7 -0
- data/lib/keight/skeleton/config/app_stg.rb +5 -0
- data/lib/keight/skeleton/config/app_test.private +11 -0
- data/lib/keight/skeleton/config/app_test.rb +8 -0
- data/lib/keight/skeleton/config/server_puma.rb +22 -0
- data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
- data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
- data/lib/keight/skeleton/config.rb +44 -0
- data/lib/keight/skeleton/config.ru +21 -0
- data/lib/keight/skeleton/index.txt +38 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
- data/lib/keight/skeleton/tmp/upload/.keep +0 -0
- data/lib/keight.rb +2017 -0
- data/test/data/example1.jpg +0 -0
- data/test/data/example1.png +0 -0
- data/test/data/multipart.form +0 -0
- data/test/data/wabisabi.js +77 -0
- data/test/data/wabisabi.js.gz +0 -0
- data/test/keight_test.rb +3161 -0
- data/test/oktest.rb +1537 -0
- 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
|