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