rack-jet_router 1.3.1 → 1.4.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.
data/bench/bench.rb CHANGED
@@ -5,48 +5,85 @@
5
5
  ## Usage:
6
6
  ## $ gem install bundler
7
7
  ## $ bundler install
8
- ## $ ruby bench.rb --N=1000_000
9
- ## $ ruby bench.rb --N=1000_000 --rack=0 --sinatra=0 --multiplexer=0 # --hanami=0 --jetrouter=0 --keight=0
8
+ ## $ ruby bench.rb -n 1000000
9
+ ## $ ruby bench.rb -n 1000000 --rack=off --sinatra=off --multiplexer=off # --jet=off --keight=off --hanami=off --httprouter=off
10
10
  ##
11
11
 
12
12
 
13
13
  $LOAD_PATH << File.absolute_path("../../lib", __FILE__)
14
14
 
15
+
15
16
  require 'benchmarker'
16
17
  Benchmarker.parse_cmdopts()
17
18
 
18
- require 'rack' rescue nil unless '0' == $opt_rack
19
- require 'rack/jet_router' rescue nil unless '0' == $opt_jetrouter
20
- require 'rack/multiplexer' rescue nil unless '0' == $opt_multiplexer
21
- require 'sinatra/base' rescue nil unless '0' == $opt_sinatra
22
- require 'keight' rescue nil unless '0' == $opt_keight
23
- require 'hanami/router' rescue nil unless '0' == $opt_hanami
24
-
25
- flag_rack = defined?(Rack) && $opt_rack != '0'
26
- flag_jetrouter = defined?(Rack::JetRouter)
27
- flag_multiplexer = defined?(Rack::Multiplexer)
28
- flag_sinatra = defined?(Sinatra)
29
- flag_keight = defined?(K8)
30
- flag_hanami = defined?(Hanami::Router)
31
-
32
- def version_info(name, opt, flag)
33
- version = opt == '0' ? "(skipped)" \
34
- : ! flag ? "(not installed)" \
35
- : yield
36
- return "** %-20s : %s" % [name, version]
19
+
20
+ class GetFlag
21
+
22
+ def initialize(defaults={})
23
+ @flag_all = to_bool($opt_all)
24
+ @defaults = defaults
25
+ @output = String.new
26
+ end
27
+
28
+ attr_reader :output
29
+
30
+ def call(key, lib, &b)
31
+ default = @defaults[key]
32
+ default != nil or
33
+ raise KeyError.new(key.inspect)
34
+ opt_val = eval "$opt_#{key}"
35
+ arr = [to_bool(opt_val), @flag_all, default]
36
+ flag = arr.find {|x| x != nil }
37
+ #
38
+ begin
39
+ require lib
40
+ rescue LoadError
41
+ flag = nil
42
+ end
43
+ #
44
+ version = flag == false ? "(skipped)" \
45
+ : flag == nil ? "(not installed)" \
46
+ : yield
47
+ gem = [lib].flatten()[0].gsub('/', '-')
48
+ @output << "** %-20s : %s\n" % [gem, version]
49
+ #
50
+ return flag
51
+ end
52
+
53
+ def to_bool(val, default=nil)
54
+ case val
55
+ when 'on' , 'true' , 'yes', '1' ; return true
56
+ when 'off', 'false', 'no' , '0' ; return false
57
+ else ; return default
58
+ end
59
+ end
60
+
37
61
  end
38
62
 
39
- puts version_info("rack" , $opt_rack , flag_rack ) { Rack.release }
40
- puts version_info("rack-jet_router" , $opt_jetrouter , flag_jetrouter ) { Rack::JetRouter::RELEASE }
41
- puts version_info("rack-multiplexer", $opt_multiplexer, flag_multiplexer) { Rack::Multiplexer::VERSION }
42
- puts version_info("sinatra" , $opt_sinatra , flag_sinatra ) { Sinatra::VERSION }
43
- puts version_info("keight" , $opt_keight , flag_keight ) { K8::RELEASE }
44
- puts version_info("hanami-router" , $opt_hanami , flag_hanami ) { Hanami::Router::VERSION }
63
+ get_flag = GetFlag.new(
64
+ :rack => true,
65
+ :rocket => false,
66
+ :jet => true,
67
+ :keight => true,
68
+ :hanami => true,
69
+ :httprouter => true,
70
+ :multiplexer => true,
71
+ :sinatra => true,
72
+ )
73
+
74
+
75
+ flag_rack = get_flag.(:rack , "rack" ) { Rack.release }
76
+ flag_rocket = get_flag.(:rocket , "rocketrouter" ) { RocketRouter::VERSION }
77
+ flag_jet = get_flag.(:jet , "rack/jet_router" ) { Rack::JetRouter::RELEASE }
78
+ flag_keight = get_flag.(:keight , "keight" ) { K8::RELEASE }
79
+ flag_hanami = get_flag.(:hanami , "hanami/router" ) { Hanami::Router::VERSION }
80
+ flag_httprouter = get_flag.(:httprouter , "http_router" ) { require "http_router/version"; HttpRouter::VERSION }
81
+ flag_multiplexer = get_flag.(:multiplexer, "rack/multiplexer") { Rack::Multiplexer::VERSION }
82
+ flag_sinatra = get_flag.(:sinatra , "sinatra/base" ) { Sinatra::VERSION }
45
83
 
46
84
 
47
85
  ENTRIES = ('a'..'z').map.with_index {|x, i| "%s%02d" % [x*3, i+1] }
48
86
 
49
- #flag_sinatra = false # because too slow
50
87
  target_urlpaths = [
51
88
  "/api/aaa01",
52
89
  "/api/aaa01/123",
@@ -57,13 +94,36 @@ target_urlpaths = [
57
94
  ]
58
95
 
59
96
 
60
- if flag_rack
61
-
62
- rack_app1 = proc do |env|
63
- [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
97
+ def generate_apps(env_key, key_class)
98
+ if key_class == String ; id, c_id = 'id', 'comment_id'
99
+ elsif key_class == Symbol ; id, c_id = :id, :comment_id
100
+ else ; raise "** internal error: key_class=#{key_class.inspect}"
64
101
  end
102
+ index_app = proc {|env|
103
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
104
+ }
105
+ show_app = proc {|env|
106
+ d = env[env_key]
107
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d[id]}</h1>"]]
108
+ }
109
+ comment_app = proc {|env|
110
+ d = env[env_key]
111
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d[id]}, comment_id=#{d[c_id]}</h1>"]]
112
+ }
113
+ return index_app, show_app, comment_app
114
+ end
115
+
116
+
117
+ def let(*args)
118
+ return (yield *args)
119
+ end
120
+
65
121
 
66
- rack_app4 = proc do |env; req, resp|
122
+ rack_app = flag_rack && let() {
123
+ #proc do |env|
124
+ # [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
125
+ #end
126
+ proc do |env; req, resp|
67
127
  req = Rack::Request.new(env)
68
128
  resp = Rack::Response.new
69
129
  #[resp.status, resp.headers, ["<h1>hello</h1>"]]
@@ -73,73 +133,134 @@ if flag_rack
73
133
  resp.write("<h1>hello</h1>")
74
134
  resp.finish()
75
135
  end
76
-
77
- end
78
-
79
-
80
- if flag_jetrouter
81
-
82
- jet_router = proc {
83
- handler1 = proc {|env|
84
- [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
85
- }
86
- handler2 = proc {|env|
87
- d = env['rack.urlpath_params']
88
- [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}</h1>"]]
89
- }
90
- handler3 = proc {|env|
91
- d = env['rack.urlpath_params']
92
- [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}, comment_id=#{d['comment_id']}</h1>"]]
93
- }
94
- mapping = [
95
- ['/api', ENTRIES.each_with_object([]) {|x, arr|
96
- arr << ["/#{x}", [
97
- ['', handler1],
98
- ['/:id', handler2],
99
- ]]
100
- arr << ["/#{x}/:id/comments", [
101
- ['/:comment_id', handler3],
102
- ]]
103
- },
104
- ],
105
- ]
106
- opts = {
107
- cache_size: ($opt_k8cache || 0).to_i,
108
- _enable_range: $opt_k8range != '0',
109
- #prefix_minlength_target: /\A\/api\/\w/,
110
- }
111
- Rack::JetRouter.new(mapping, **opts)
112
- }.call()
113
-
114
- end
136
+ }
137
+
138
+
139
+ rocket_app = flag_rocket && let() {
140
+ index_app, show_app, comment_app = generate_apps('rack.urlpath_params', String)
141
+ mapping = {
142
+ "/api" => ENTRIES.each_with_object({}) {|x, map|
143
+ map.update({
144
+ "/#{x}" => {
145
+ "" => index_app,
146
+ "/{id}" => show_app,
147
+ "/{id}/comments" => {
148
+ "/{comment_id}" => comment_app,
149
+ },
150
+ },
151
+ })
152
+ },
153
+ }
154
+ opts = {
155
+ }
156
+ RocketRouter.new(mapping, **opts)
157
+ }
158
+
159
+
160
+ jet_app = flag_jet && let() {
161
+ index_app, show_app, comment_app = generate_apps('rack.urlpath_params', String)
162
+ mapping = {
163
+ "/api" => ENTRIES.each_with_object({}) {|x, map|
164
+ map.update({
165
+ "/#{x}" => {
166
+ "" => index_app,
167
+ "/:id" => show_app,
168
+ "/:id/comments" => {
169
+ "/:comment_id" => comment_app,
170
+ },
171
+ },
172
+ })
173
+ },
174
+ }
175
+ opts = {
176
+ cache_size: 0,
177
+ _enable_range: true,
178
+ #prefix_minlength_target: /\A\/api\/\w/,
179
+ }
180
+ Rack::JetRouter.new(mapping, **opts)
181
+ }
182
+
183
+
184
+ keight_app = flag_keight && let() {
185
+ class K8HelloAction < K8::Action
186
+ mapping '', :GET=>:do_index
187
+ mapping '/{id}', :GET=>:do_show
188
+ def do_index()
189
+ "<h1>hello</h1>"
190
+ end
191
+ def do_show(id)
192
+ "<h1>id=#{id.inspect}</h1>"
193
+ end
194
+ end
195
+ class K8CommentAction < K8::Action
196
+ mapping '/{comment_id}', :GET=>:do_show
197
+ def do_show(id, comment_id)
198
+ "<h1>id=#{id}, comment_id=#{comment_id}</h1>"
199
+ end
200
+ end
201
+ mapping = [
202
+ ["/api", ENTRIES.each_with_object([]) {|x, arr|
203
+ arr << ["/#{x}" , K8HelloAction]
204
+ arr << ["/#{x}/{id}/comments", K8CommentAction]
205
+ }
206
+ ],
207
+ ]
208
+ opts = {
209
+ #urlpath_cache_size: 0,
210
+ }
211
+ K8::RackApplication.new(mapping, **opts)
212
+ }
213
+
214
+
215
+ hanami_app = flag_hanami && let() {
216
+ ## ref: https://github.com/hanami/router
217
+ index_app, show_app, comment_app = generate_apps('router.params', Symbol)
218
+ Hanami::Router.new do
219
+ scope "api" do
220
+ ENTRIES.each do |x|
221
+ get "/#{x}" , to: index_app
222
+ get "/#{x}/:id", to: show_app
223
+ get "/#{x}/:id/comments/:comment_id", to: comment_app
224
+ end
225
+ end
226
+ end
227
+ }
115
228
 
116
229
 
117
- if flag_multiplexer
118
-
119
- mpx_app = Rack::Multiplexer.new().tap do |app|
120
- handler1 = proc {|env|
121
- [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
122
- }
123
- handler2 = proc {|env|
124
- d = env['rack.request.query_hash']
125
- [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}</h1>"]]
126
- }
127
- handler3 = proc {|env|
128
- d = env['rack.request.query_hash']
129
- [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}, comment_id=#{d['comment_id']}</h1>"]]
130
- }
230
+ httprouter_app = flag_httprouter && let() {
231
+ require 'uri'
232
+ require 'cgi'
233
+ class <<URI
234
+ #alias unescape decode_www_form
235
+ def unescape(x)
236
+ CGI.unescape(x)
237
+ end
238
+ end
239
+ #
240
+ index_app, show_app, comment_app = generate_apps('router.params', Symbol)
241
+ HttpRouter.new.tap do |r|
131
242
  ENTRIES.each do |x|
132
- app.get "/api/#{x}" , handler1
133
- app.get "/api/#{x}/:id" , handler2
134
- app.get "/api/#{x}/:id/comments/:comment_id" , handler3
243
+ r.add("/api/#{x}" ).to(index_app)
244
+ r.add("/api/#{x}/:id").to(show_app)
245
+ r.add("/api/#{x}/:id/comments/:comment_id").to(comment_app)
135
246
  end
136
247
  end
248
+ }
137
249
 
138
- end
139
250
 
251
+ multiplexer_app = flag_multiplexer && let() {
252
+ index_app, show_app, comment_app = generate_apps('rack.request.query_hash', String)
253
+ Rack::Multiplexer.new().tap do |app|
254
+ ENTRIES.each do |x|
255
+ app.get "/api/#{x}" , index_app
256
+ app.get "/api/#{x}/:id" , show_app
257
+ app.get "/api/#{x}/:id/comments/:comment_id" , comment_app
258
+ end
259
+ end
260
+ }
140
261
 
141
- if flag_sinatra
142
262
 
263
+ sinatra_app = flag_sinatra && let() {
143
264
  class SinaApp < Sinatra::Base
144
265
  ## run benchmarks without middlewares
145
266
  set :sessions , false
@@ -148,76 +269,19 @@ if flag_sinatra
148
269
  set :x_cascade , false
149
270
  #
150
271
  ENTRIES.each do |x|
151
- get "/api/#{x}" do "<h1>hello</h1>" end
152
- get "/api/#{x}/:id" do "<h1>id=#{params['id']}</h1>" end
153
- get "/api/#{x}/:id/comments/:comment_id" do "<h1>id=#{params['id']}, comment_id=#{params['comment_id']}</h1>" end
154
- end
155
- end
156
-
157
- sina_app = SinaApp.new
158
-
159
- end
160
-
161
-
162
- if flag_keight
163
-
164
- class K8HelloAction < K8::Action
165
- mapping '', :GET=>:do_index
166
- mapping '/{id}', :GET=>:do_show
167
- def do_index ; "<h1>hello</h1>"; end
168
- def do_show(id) ; "<h1>id=#{id.inspect}</h1>"; end
169
- end
170
-
171
- class K8CommentAction < K8::Action
172
- mapping '/{comment_id}', :GET=>:do_show
173
- def do_show(id, comment_id); "<h1>id=#{id}, comment_id=#{comment_id}</h1>"; end
174
- end
175
-
176
- k8_app = (proc {
177
- mapping = [
178
- ["/api", ENTRIES.each_with_object([]) {|x, arr|
179
- arr << ["/#{x}" , K8HelloAction]
180
- arr << ["/#{x}/{id}/comments", K8CommentAction]
181
- }
182
- ],
183
- ]
184
- opts = {
185
- #urlpath_cache_size: 0,
186
- }
187
- K8::RackApplication.new(mapping, **opts)
188
- }).call()
189
-
190
- #k8_app.find('/api/books') # warm up
191
-
192
- end
193
-
194
-
195
- if flag_hanami
196
-
197
- ## ref: https://github.com/hanami/router
198
- hanami_app = Hanami::Router.new do
199
- index_handler = proc do |env|
200
- [200, {"Content-Type": "text/html"}, ["<h1>hello</h1>"]]
201
- end
202
- show_handler = proc do |env|
203
- d = env['router.params']
204
- [200, {"Content-Type": "text/html"}, ["<h1>id=#{d[:id]}</h1>"]]
205
- end
206
- comment_handler = proc do |env|
207
- d = env['router.params']
208
- [200, {"Content-Type": "text/html"}, ["<h1>id=#{d[:id]}, comment_id=#{d[:comment_id]}</h1>"]]
209
- end
210
- #
211
- scope "api" do
212
- ENTRIES.each do |x|
213
- get "/#{x}" , to: index_handler
214
- get "/#{x}/:id", to: show_handler
215
- get "/#{x}/:id/comments/:comment_id", to: comment_handler
272
+ get "/api/#{x}" do
273
+ "<h1>hello</h1>"
274
+ end
275
+ get "/api/#{x}/:id" do
276
+ "<h1>id=#{params['id']}</h1>"
277
+ end
278
+ get "/api/#{x}/:id/comments/:comment_id" do
279
+ "<h1>id=#{params['id']}, comment_id=#{params['comment_id']}</h1>"
216
280
  end
217
281
  end
218
282
  end
219
-
220
- end
283
+ SinaApp.new
284
+ }
221
285
 
222
286
 
223
287
  begin
@@ -235,10 +299,12 @@ def newenv(path)
235
299
  end
236
300
 
237
301
 
238
- N = ($opt_N || 100000).to_i
302
+ N = Benchmarker::OPTIONS.delete(:loop) || 1000_000
239
303
  title = "Router library benchmark"
240
- Benchmarker.scope(title, width: 33, loop: 1, iter: 1, extra: 0, sleep: 0) do
304
+ width = target_urlpaths.collect(&:length).max()
305
+ Benchmarker.scope(title, width: width + 17, loop: 1, iter: 1, extra: 0, sleep: 0) do
241
306
 
307
+ puts get_flag.output()
242
308
  puts "** N=#{N}"
243
309
  puts ""
244
310
 
@@ -251,117 +317,137 @@ Benchmarker.scope(title, width: 33, loop: 1, iter: 1, extra: 0, sleep: 0) do
251
317
  end
252
318
 
253
319
  ### Rack
254
- if flag_rack
255
- #target_urlpaths.each do |x|
256
- # rack_app1.call(newenv(x)) # warm up
257
- # task "(Rack plain app) #{x}" do # no routing
258
- # env = newenv(x)
259
- # i = 0; n = N
260
- # while (i += 1) <= n
261
- # tuple = rack_app1.call(env)
262
- # end
263
- # tuple
264
- # end
265
- #end
266
- target_urlpaths.each do |x|
267
- rack_app4.call(newenv(x)) # warm up
268
- task "(Rack::Req+Res) #{x}" do # no routing
269
- env = newenv(x)
270
- i = 0; n = N
271
- while (i += 1) <= n
272
- tuple = rack_app4.call(env)
273
- end
274
- tuple
320
+ #flag_rack and target_urlpaths.each do |path|
321
+ # rack_app.call(newenv(path)) # warm up
322
+ # task "(Rack plain app) #{path}" do # no routing
323
+ # env = newenv(path)
324
+ # i = 0; n = N
325
+ # while (i += 1) <= n
326
+ # result = rack_app.call(env)
327
+ # end
328
+ # result
329
+ # end
330
+ #end
331
+ flag_rack and target_urlpaths.each do |path|
332
+ rack_app.call(newenv(path)) # warm up
333
+ task "(Rack::Req+Res) #{path}" do # no routing
334
+ env = newenv(path)
335
+ i = 0; n = N
336
+ while (i += 1) <= n
337
+ result = rack_app.call(env)
338
+ end
339
+ result
340
+ end
341
+ end
342
+
343
+ ### RocketRouter
344
+ flag_rocket and target_urlpaths.each do |path|
345
+ rocket_app.call(newenv(path)) # warm up
346
+ task "(RocketRouter) #{path}" do
347
+ env = newenv(path)
348
+ i = 0; n = N
349
+ while (i += 1) <= n
350
+ result = rocket_app.call(env)
351
+ #result = rocket_app.find(path)
275
352
  end
353
+ result
276
354
  end
277
355
  end
278
356
 
279
357
  ### Rack::JetRouter
280
- if flag_jetrouter
281
- target_urlpaths.each do |x|
282
- jet_router.call(newenv(x)) # warm up
283
- task "(JetRouter) #{x}" do
284
- env = newenv(x)
285
- i = 0; n = N
286
- while (i += 1) <= n
287
- tuple = jet_router.call(env)
288
- end
289
- tuple
358
+ flag_jet and target_urlpaths.each do |path|
359
+ jet_app.call(newenv(path)) # warm up
360
+ task "(JetRouter) #{path}" do
361
+ env = newenv(path)
362
+ i = 0; n = N
363
+ while (i += 1) <= n
364
+ result = jet_app.call(env)
365
+ #result = jet_app.find(path)
290
366
  end
367
+ result
291
368
  end
292
369
  end
293
370
 
294
- ### Rack::Multiplexer
295
- if flag_multiplexer
296
- target_urlpaths.each do |x|
297
- mpx_app.call(newenv(x)) # warm up
298
- task "(Multiplexer) #{x}" do
299
- env = newenv(x)
300
- i = 0; n = N
301
- while (i += 1) <= n
302
- tuple = mpx_app.call(env)
303
- end
304
- tuple
371
+ ### Keight
372
+ flag_keight and target_urlpaths.each do |path|
373
+ keight_app.call(newenv(path)) # warm up
374
+ task "(Keight) #{path}" do
375
+ env = newenv(path)
376
+ i = 0; n = N
377
+ while (i += 1) <= n
378
+ result = keight_app.call(env)
305
379
  end
380
+ result
306
381
  end
307
382
  end
308
383
 
309
- ### Sinatra
310
- if flag_sinatra
311
- target_urlpaths.each do |x|
312
- sina_app.call(newenv(x)) # warm up
313
- task "(Sinatra) #{x}" do
314
- env = newenv(x)
315
- i = 0; n = N
316
- while (i += 1) <= n
317
- tuple = sina_app.call(env)
318
- end
319
- tuple
384
+ ### Hanami::Router
385
+ flag_hanami and target_urlpaths.each do |path|
386
+ hanami_app.call(newenv(path)) # warm up
387
+ task "(Hanami::Router) #{path}" do
388
+ env = newenv(path)
389
+ i = 0; n = N
390
+ while (i += 1) <= n
391
+ result = hanami_app.call(env)
392
+ #result = hanami_app.route(path)
320
393
  end
394
+ result
321
395
  end
322
396
  end
323
397
 
324
- ### Keight
325
- if flag_keight
326
- target_urlpaths.each do |x|
327
- k8_app.call(newenv(x)) # warm up
328
- task "(Keight) #{x}" do
329
- env = newenv(x)
330
- i = 0; n = N
331
- while (i += 1) <= n
332
- tuple = k8_app.call(env)
333
- end
334
- tuple
398
+ ### HttpRouter
399
+ flag_httprouter and target_urlpaths.each do |path|
400
+ httprouter_app.call(newenv(path)) # warm up
401
+ task "(HttpRouter) #{path}" do
402
+ env = newenv(path)
403
+ i = 0; n = N
404
+ while (i += 1) <= n
405
+ result = httprouter_app.call(env)
406
+ #result = httprouter_app.route(path)
335
407
  end
408
+ result
336
409
  end
337
410
  end
338
411
 
339
- ### Hanami
340
- if flag_hanami
341
- target_urlpaths.each do |x|
342
- hanami_app.call(newenv(x)) # warm up
343
- task "(Hanami::Router) #{x}" do
344
- env = newenv(x)
345
- i = 0; n = N
346
- while (i += 1) <= n
347
- tuple = hanami_app.call(env)
348
- end
349
- tuple
412
+ ### Rack::Multiplexer
413
+ flag_multiplexer and target_urlpaths.each do |path|
414
+ multiplexer_app.call(newenv(path)) # warm up
415
+ task "(Multiplexer) #{path}" do
416
+ env = newenv(path)
417
+ i = 0; n = N
418
+ while (i += 1) <= n
419
+ result = multiplexer_app.call(env)
350
420
  end
421
+ result
422
+ end
423
+ end
424
+
425
+ ### Sinatra
426
+ flag_sinatra and target_urlpaths.each do |path|
427
+ sinatra_app.call(newenv(path)) # warm up
428
+ task "(Sinatra) #{path}" do
429
+ env = newenv(path)
430
+ i = 0; n = N
431
+ while (i += 1) <= n
432
+ result = sinatra_app.call(env)
433
+ end
434
+ result
351
435
  end
352
436
  end
353
437
 
354
438
  ## validation
355
- validate do |val| # or: validate do |val, task_name, tag|
356
- tuple = val
357
- assert tuple[0] == 200, "200 expected but got #{tuple[0]}"
439
+ validate do |result| # or: validate do |result, task_name, tag|
440
+ tuple = result
441
+ assert tuple[0] == 200, "Expected 200 but got #{tuple[0]}"
358
442
  body = tuple[2].each {|x| break x }
359
- assert body == "<h1>hello</h1>" || \
360
- body == "<h1>id=123</h1>" || \
361
- body == "<h1>id=456</h1>" || \
362
- body == "<h1>id=123, comment_id=7</h1>" || \
363
- body == "<h1>id=456, comment_id=7</h1>", \
364
- "#{body.inspect}: unpexpected body"
443
+ expected_bodies = [
444
+ "<h1>hello</h1>",
445
+ "<h1>id=123</h1>",
446
+ "<h1>id=456</h1>",
447
+ "<h1>id=123, comment_id=7</h1>",
448
+ "<h1>id=456, comment_id=7</h1>",
449
+ ]
450
+ assert expected_bodies.include?(body), "#{body.inspect}: Unpexpected body."
365
451
  end
366
452
 
367
453
  end