sinatra 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

@@ -315,7 +315,7 @@ Thin - это более производительный и функциона
315
315
 
316
316
  === Haml шаблоны
317
317
 
318
- Зависимости:: {haml}[http://haml-lang.com/]
318
+ Зависимости:: {haml}[http://haml.info/]
319
319
  Расширения файлов:: <tt>.haml</tt>
320
320
  Пример:: <tt>haml :index, :format => :html5</tt>
321
321
 
@@ -229,7 +229,7 @@ Rack body对象或者HTTP状态码:
229
229
 
230
230
  渲染 <tt>./views/index.haml</tt>。
231
231
 
232
- {Haml的选项}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options]
232
+ {Haml的选项}[http://haml.info/docs/yardoc/file.HAML_REFERENCE.html#options]
233
233
  可以通过Sinatra的配置全局设定,
234
234
  参见 {选项和配置}[http://www.sinatrarb.com/configuration.html],
235
235
  也可以个别的被覆盖。
data/Rakefile CHANGED
@@ -56,7 +56,7 @@ end
56
56
  # Rcov ================================================================
57
57
 
58
58
  namespace :test do
59
- desc 'Mesures test coverage'
59
+ desc 'Measures test coverage'
60
60
  task :coverage do
61
61
  rm_f "coverage"
62
62
  sh "rcov -Ilib test/*_test.rb"
@@ -117,6 +117,7 @@ task :authors, [:commit_range, :format, :sep] do |t, a|
117
117
  "a_user@mac.com" => blake, "ichverstehe" => "Harry Vangberg",
118
118
  "Wu Jiang (nouse)" => "Wu Jiang" }
119
119
  `git shortlog -s #{a.commit_range}`.lines.map do |line|
120
+ line = line.force_encoding 'binary' if line.respond_to? :force_encoding
120
121
  num, name = line.split("\t", 2).map(&:strip)
121
122
  authors[mapping[name] || name] += num.to_i
122
123
  overall += num.to_i
@@ -1,6 +1,3 @@
1
- libdir = File.dirname(__FILE__)
2
- $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
-
4
1
  require 'sinatra/base'
5
2
  require 'sinatra/main'
6
3
 
@@ -1,7 +1,7 @@
1
1
  # external dependencies
2
2
  require 'rack'
3
3
  require 'tilt'
4
- require "rack/protection"
4
+ require 'rack/protection'
5
5
 
6
6
  # stdlib dependencies
7
7
  require 'thread'
@@ -77,7 +77,9 @@ module Sinatra
77
77
  headers.delete "Content-Length"
78
78
  headers.delete "Content-Type"
79
79
  elsif Array === body and not [204, 304].include?(status.to_i)
80
- headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
80
+ # if some other code has already set Content-Length, don't muck with it
81
+ # currently, this would be the static file-handler
82
+ headers["Content-Length"] ||= body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
81
83
  end
82
84
 
83
85
  # Rack::Response#finish sometimes returns self as response body. We don't want that.
@@ -87,6 +89,55 @@ module Sinatra
87
89
  end
88
90
  end
89
91
 
92
+ # Some Rack handlers (Thin, Rainbows!) implement an extended body object protocol, however,
93
+ # some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
94
+ # This middleware will detect an extended body object and will make sure it reaches the
95
+ # handler directly. We do this here, so our middleware and middleware set up by the app will
96
+ # still be able to run.
97
+ class ExtendedRack < Struct.new(:app)
98
+ def call(env)
99
+ result, callback = app.call(env), env['async.callback']
100
+ return result unless callback and async?(*result)
101
+ after_response { callback.call result }
102
+ setup_close(env, *result)
103
+ throw :async
104
+ end
105
+
106
+ private
107
+
108
+ def setup_close(env, status, header, body)
109
+ return unless body.respond_to? :close and env.include? 'async.close'
110
+ env['async.close'].callback { body.close }
111
+ env['async.close'].errback { body.close }
112
+ end
113
+
114
+ def after_response(&block)
115
+ raise NotImplementedError, "only supports EventMachine at the moment" unless defined? EventMachine
116
+ EventMachine.next_tick(&block)
117
+ end
118
+
119
+ def async?(status, headers, body)
120
+ return true if status == -1
121
+ body.respond_to? :callback and body.respond_to? :errback
122
+ end
123
+ end
124
+
125
+ # Behaves exactly like Rack::CommonLogger with the notable exception that it does nothing,
126
+ # if another CommonLogger is already in the middleware chain.
127
+ class CommonLogger < Rack::CommonLogger
128
+ def call(env)
129
+ env['sinatra.commonlogger'] ? @app.call(env) : super
130
+ end
131
+
132
+ superclass.class_eval do
133
+ alias call_without_check call unless method_defined? :call_without_check
134
+ def call(env)
135
+ env['sinatra.commonlogger'] = true
136
+ call_without_check(env)
137
+ end
138
+ end
139
+ end
140
+
90
141
  class NotFound < NameError #:nodoc:
91
142
  def code ; 404 ; end
92
143
  end
@@ -275,6 +326,7 @@ module Sinatra
275
326
  end
276
327
 
277
328
  def callback(&block)
329
+ return yield if @closed
278
330
  @callbacks << block
279
331
  end
280
332
 
@@ -290,16 +342,7 @@ module Sinatra
290
342
  def stream(keep_open = false)
291
343
  scheduler = env['async.callback'] ? EventMachine : Stream
292
344
  current = @params.dup
293
- block = proc do |out|
294
- begin
295
- original, @params = @params, current
296
- yield(out)
297
- ensure
298
- @params = original if original
299
- end
300
- end
301
-
302
- body Stream.new(scheduler, keep_open, &block)
345
+ body Stream.new(scheduler, keep_open) { |out| with_params(current) { yield(out) } }
303
346
  end
304
347
 
305
348
  # Specify response freshness policy for HTTP caches (Cache-Control header).
@@ -486,6 +529,13 @@ module Sinatra
486
529
  return !new_resource if list == '*'
487
530
  list.to_s.split(/\s*,\s*/).include? response['ETag']
488
531
  end
532
+
533
+ def with_params(temp_params)
534
+ original, @params = @params, temp_params
535
+ yield
536
+ ensure
537
+ @params = original if original
538
+ end
489
539
  end
490
540
 
491
541
  private
@@ -814,7 +864,7 @@ module Sinatra
814
864
 
815
865
  if values.any?
816
866
  original, @params = params, params.merge('splat' => [], 'captures' => values)
817
- keys.zip(values) { |k,v| (@params[k] ||= '') << v if v }
867
+ keys.zip(values) { |k,v| Array === @params[k] ? @params[k] << v : @params[k] = v if v }
818
868
  end
819
869
 
820
870
  catch(:pass) do
@@ -990,9 +1040,7 @@ module Sinatra
990
1040
  when Proc
991
1041
  getter = value
992
1042
  when Symbol, Fixnum, FalseClass, TrueClass, NilClass
993
- # we have a lot of enable and disable calls, let's optimize those
994
- class_eval "def self.#{option}() #{value.inspect} end"
995
- getter = nil
1043
+ getter = value.inspect
996
1044
  when Hash
997
1045
  setter = proc do |val|
998
1046
  val = value.merge val if Hash === val
@@ -1000,13 +1048,9 @@ module Sinatra
1000
1048
  end
1001
1049
  end
1002
1050
 
1003
- (class << self; self; end).class_eval do
1004
- define_method("#{option}=", &setter) if setter
1005
- define_method(option, &getter) if getter
1006
- unless method_defined? "#{option}?"
1007
- class_eval "def #{option}?() !!#{option} end"
1008
- end
1009
- end
1051
+ define_singleton_method("#{option}=", setter) if setter
1052
+ define_singleton_method(option, getter) if getter
1053
+ define_singleton_method("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
1010
1054
  self
1011
1055
  end
1012
1056
 
@@ -1126,7 +1170,16 @@ module Sinatra
1126
1170
  set(:public_folder, value)
1127
1171
  end
1128
1172
 
1129
- private
1173
+ private
1174
+ # Dynamically defines a method on settings.
1175
+ def define_singleton_method(name, content = Proc.new)
1176
+ # replace with call to singleton_class once we're 1.9 only
1177
+ (class << self; self; end).class_eval do
1178
+ undef_method(name) if method_defined? name
1179
+ String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content)
1180
+ end
1181
+ end
1182
+
1130
1183
  # Condition for matching host name. Parameter might be String or Regexp.
1131
1184
  def host_name(pattern)
1132
1185
  condition { pattern === request.host }
@@ -1237,9 +1290,11 @@ module Sinatra
1237
1290
  end
1238
1291
  end
1239
1292
 
1293
+ URI = ::URI.const_defined?(:Parser) ? ::URI::Parser.new : ::URI
1294
+
1240
1295
  def encoded(char)
1241
- enc = URI.encode(char)
1242
- enc = "(?:#{Regexp.escape enc}|#{URI.encode char, /./})" if enc == char
1296
+ enc = URI.escape(char)
1297
+ enc = "(?:#{Regexp.escape enc}|#{URI.escape char, /./})" if enc == char
1243
1298
  enc = "(?:#{enc}|#{encoded('+')})" if char == " "
1244
1299
  enc
1245
1300
  end
@@ -1302,7 +1357,7 @@ module Sinatra
1302
1357
  set :running, true
1303
1358
  yield server if block_given?
1304
1359
  end
1305
- rescue Errno::EADDRINUSE => e
1360
+ rescue Errno::EADDRINUSE
1306
1361
  $stderr.puts "== Someone is already performing on port #{port}!"
1307
1362
  end
1308
1363
 
@@ -1336,6 +1391,7 @@ module Sinatra
1336
1391
 
1337
1392
  private
1338
1393
  def setup_default_middleware(builder)
1394
+ builder.use ExtendedRack
1339
1395
  builder.use ShowExceptions if show_exceptions?
1340
1396
  builder.use Rack::MethodOverride if method_override?
1341
1397
  builder.use Rack::Head
@@ -1362,8 +1418,7 @@ module Sinatra
1362
1418
  end
1363
1419
 
1364
1420
  def setup_common_logger(builder)
1365
- return if ["development", "deployment", nil].include? ENV["RACK_ENV"]
1366
- builder.use Rack::CommonLogger
1421
+ builder.use Sinatra::CommonLogger
1367
1422
  end
1368
1423
 
1369
1424
  def setup_custom_logger(builder)
@@ -1379,6 +1434,7 @@ module Sinatra
1379
1434
  options = Hash === protection ? protection.dup : {}
1380
1435
  options[:except] = Array options[:except]
1381
1436
  options[:except] += [:session_hijacking, :remote_token] unless sessions?
1437
+ options[:reaction] ||= :drop_session
1382
1438
  builder.use Rack::Protection, options
1383
1439
  end
1384
1440
 
@@ -1395,8 +1451,7 @@ module Sinatra
1395
1451
  servers.each do |server_name|
1396
1452
  begin
1397
1453
  return Rack::Handler.get(server_name.to_s)
1398
- rescue LoadError
1399
- rescue NameError
1454
+ rescue LoadError, NameError
1400
1455
  end
1401
1456
  end
1402
1457
  fail "Server handler (#{servers.join(',')}) not found."
@@ -1429,8 +1484,11 @@ module Sinatra
1429
1484
  /src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
1430
1485
  ]
1431
1486
 
1432
- # add rubinius (and hopefully other VM impls) ignore patterns ...
1433
- CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
1487
+ # contrary to what the comment said previously, rubinius never supported this
1488
+ if defined?(RUBY_IGNORE_CALLERS)
1489
+ warn "RUBY_IGNORE_CALLERS is deprecated and will no longer be supported by Sinatra 2.0"
1490
+ CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS)
1491
+ end
1434
1492
 
1435
1493
  # Like Kernel#caller but excluding certain magic entries and without
1436
1494
  # line / method information; the resulting array contains filenames only.
@@ -1,3 +1,3 @@
1
1
  module Sinatra
2
- VERSION = '1.3.2'
2
+ VERSION = '1.3.3'
3
3
  end
@@ -10,7 +10,7 @@ Gem::Specification.new 'sinatra', Sinatra::VERSION do |s|
10
10
  s.files = `git ls-files`.split("\n") - %w[.gitignore .travis.yml]
11
11
  s.test_files = s.files.select { |p| p =~ /^test\/.*_test.rb/ }
12
12
  s.extra_rdoc_files = s.files.select { |p| p =~ /^README/ } << 'LICENSE'
13
- s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc]
13
+ s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc --encoding=UTF-8]
14
14
 
15
15
  s.add_dependency 'rack', '~> 1.3', '>= 1.3.6'
16
16
  s.add_dependency 'rack-protection', '~> 1.2'
@@ -102,7 +102,7 @@ class DelegatorTest < Test::Unit::TestCase
102
102
  assert_equal ["helpers", mixin.to_s], app.last_call
103
103
  end
104
104
 
105
- it "registers helpers with the delegation target" do
105
+ it "registers middleware with the delegation target" do
106
106
  app, mixin = mirror, Module.new
107
107
  Sinatra.use mixin
108
108
  assert_equal ["use", mixin.to_s], app.last_call
@@ -158,11 +158,11 @@ class BeforeFilterTest < Test::Unit::TestCase
158
158
  end
159
159
 
160
160
  class AfterFilterTest < Test::Unit::TestCase
161
- it "executes filters in the order defined" do
161
+ it "executes before and after filters in correct order" do
162
162
  invoked = 0
163
163
  mock_app do
164
164
  before { invoked = 2 }
165
- get('/') { invoked += 2 }
165
+ get('/') { invoked += 2; 'hello' }
166
166
  after { invoked *= 2 }
167
167
  end
168
168
 
@@ -412,7 +412,7 @@ class AfterFilterTest < Test::Unit::TestCase
412
412
  assert ran
413
413
  end
414
414
 
415
- it 'is possible to apply user_agent conditions to before filters with a path' do
415
+ it 'is possible to apply user_agent conditions to after filters with a path' do
416
416
  ran = false
417
417
  mock_app do
418
418
  after('/foo', :user_agent => /foo/) { ran = true }
@@ -31,12 +31,12 @@ class HelpersTest < Test::Unit::TestCase
31
31
  assert_body 'true'
32
32
  end
33
33
 
34
- it 'is false for status > 404' do
34
+ it 'is false for status gt 404' do
35
35
  status_app(405) { not_found? }
36
36
  assert_body 'false'
37
37
  end
38
38
 
39
- it 'is false for status < 404' do
39
+ it 'is false for status lt 404' do
40
40
  status_app(403) { not_found? }
41
41
  assert_body 'false'
42
42
  end
@@ -616,7 +616,7 @@ class HelpersTest < Test::Unit::TestCase
616
616
  assert_equal '<sinatra></sinatra>', body
617
617
  end
618
618
 
619
- it 'sets the Content-Type response header without extname' do
619
+ it 'sets the Content-Type response header with extname' do
620
620
  mock_app do
621
621
  get '/attachment' do
622
622
  content_type :atom
@@ -828,12 +828,12 @@ class HelpersTest < Test::Unit::TestCase
828
828
  assert_not_nil response['Expires']
829
829
  end
830
830
 
831
- it 'allows passing time objects' do
831
+ it 'allows passing Time.now objects' do
832
832
  get '/bar'
833
833
  assert_not_nil response['Expires']
834
834
  end
835
835
 
836
- it 'allows passing time objects' do
836
+ it 'allows passing Time.at objects' do
837
837
  get '/baz'
838
838
  assert_equal 'Thu, 01 Jan 1970 00:00:00 GMT', response['Expires']
839
839
  end
@@ -1,6 +1,62 @@
1
+ $stderr.puts "loading"
1
2
  require 'sinatra'
2
3
 
4
+ configure do
5
+ set :foo, :bar
6
+ end
7
+
3
8
  get '/app_file' do
4
9
  content_type :txt
5
10
  settings.app_file
6
- end
11
+ end
12
+
13
+ get '/ping' do
14
+ 'pong'
15
+ end
16
+
17
+ get '/stream' do
18
+ stream do |out|
19
+ sleep 0.1
20
+ out << "a"
21
+ sleep 1.2
22
+ out << "b"
23
+ end
24
+ end
25
+
26
+ get '/mainonly' do
27
+ object = Object.new
28
+ begin
29
+ object.send(:get, '/foo') { }
30
+ 'false'
31
+ rescue NameError
32
+ 'true'
33
+ end
34
+ end
35
+
36
+ set :out, nil
37
+ get '/async' do
38
+ stream(:keep_open) { |o| (settings.out = o) << "hi!" }
39
+ end
40
+
41
+ get '/send' do
42
+ settings.out << params[:msg] if params[:msg]
43
+ settings.out.close if params[:close]
44
+ "ok"
45
+ end
46
+
47
+ class Subclass < Sinatra::Base
48
+ set :out, nil
49
+ get '/subclass/async' do
50
+ stream(:keep_open) { |o| (settings.out = o) << "hi!" }
51
+ end
52
+
53
+ get '/subclass/send' do
54
+ settings.out << params[:msg] if params[:msg]
55
+ settings.out.close if params[:close]
56
+ "ok"
57
+ end
58
+ end
59
+
60
+ use Subclass
61
+
62
+ $stderr.puts "starting"
@@ -0,0 +1,214 @@
1
+ require 'sinatra/base'
2
+ require 'rbconfig'
3
+ require 'open-uri'
4
+ require 'net/http'
5
+ require 'timeout'
6
+
7
+ module IntegrationHelper
8
+ class BaseServer
9
+ extend Enumerable
10
+ attr_accessor :server, :port, :pipe
11
+ alias name server
12
+
13
+ def self.all
14
+ @all ||= []
15
+ end
16
+
17
+ def self.each(&block)
18
+ all.each(&block)
19
+ end
20
+
21
+ def self.run(server, port)
22
+ new(server, port).run
23
+ end
24
+
25
+ def app_file
26
+ File.expand_path('../integration/app.rb', __FILE__)
27
+ end
28
+
29
+ def environment
30
+ "development"
31
+ end
32
+
33
+ def initialize(server, port)
34
+ @installed, @pipe, @server, @port = nil, nil, server, port
35
+ Server.all << self
36
+ end
37
+
38
+ def run
39
+ return unless installed?
40
+ kill
41
+ @log = ""
42
+ @pipe = IO.popen(command)
43
+ @started = Time.now
44
+ warn "#{server} up and running on port #{port}" if ping
45
+ at_exit { kill }
46
+ end
47
+
48
+ def ping(timeout = 30)
49
+ loop do
50
+ return if alive?
51
+ if Time.now - @started > timeout
52
+ $stderr.puts command, log
53
+ fail "timeout"
54
+ else
55
+ sleep 0.1
56
+ end
57
+ end
58
+ end
59
+
60
+ def alive?
61
+ 3.times { get('/ping') }
62
+ true
63
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError, SystemCallError, OpenURI::HTTPError, Timeout::Error => error
64
+ false
65
+ end
66
+
67
+ def get_stream(url = "/stream", &block)
68
+ Net::HTTP.start '127.0.0.1', port do |http|
69
+ request = Net::HTTP::Get.new url
70
+ http.request request do |response|
71
+ response.read_body(&block)
72
+ end
73
+ end
74
+ end
75
+
76
+ def get(url)
77
+ Timeout.timeout(1) { open("http://127.0.0.1:#{port}#{url}").read }
78
+ end
79
+
80
+ def log
81
+ @log ||= ""
82
+ loop { @log << @pipe.read_nonblock(1) }
83
+ rescue Exception
84
+ @log
85
+ end
86
+
87
+ def installed?
88
+ return @installed unless @installed.nil?
89
+ require server
90
+ @installed = true
91
+ rescue LoadError
92
+ warn "#{server} is not installed, skipping integration tests"
93
+ @installed = false
94
+ end
95
+
96
+ def command
97
+ @command ||= begin
98
+ cmd = ["RACK_ENV=#{environment}", "exec"]
99
+ if RbConfig.respond_to? :ruby
100
+ cmd << RbConfig.ruby.inspect
101
+ else
102
+ file, dir = RbConfig::CONFIG.values_at('ruby_install_name', 'bindir')
103
+ cmd << File.expand_path(file, dir).inspect
104
+ end
105
+ cmd << "-w" unless thin?
106
+ cmd << "-I" << File.expand_path('../../lib', __FILE__).inspect
107
+ cmd << app_file.inspect << '-s' << server << '-o' << '127.0.0.1' << '-p' << port
108
+ cmd << "-e" << environment.to_s << '2>&1'
109
+ cmd.join " "
110
+ end
111
+ end
112
+
113
+ def kill
114
+ return unless pipe
115
+ Process.kill("KILL", pipe.pid)
116
+ rescue NotImplementedError
117
+ system "kill -9 #{pipe.pid}"
118
+ rescue Errno::ESRCH
119
+ end
120
+
121
+ def webrick?
122
+ name.to_s == "webrick"
123
+ end
124
+
125
+ def thin?
126
+ name.to_s == "thin"
127
+ end
128
+
129
+ def warnings
130
+ log.scan(%r[(?:\(eval|lib/sinatra).*warning:.*$])
131
+ end
132
+
133
+ def run_test(target, &block)
134
+ retries ||= 3
135
+ target.server = self
136
+ run unless alive?
137
+ target.instance_eval(&block)
138
+ rescue Exception => error
139
+ retries -= 1
140
+ kill
141
+ retries < 0 ? retry : raise(error)
142
+ end
143
+ end
144
+
145
+ if RUBY_ENGINE == "jruby"
146
+ class JRubyServer < BaseServer
147
+ def start_vm
148
+ require 'java'
149
+ # Create a new container, set load paths and env
150
+ # SINGLETHREAD means create a new runtime
151
+ vm = org.jruby.embed.ScriptingContainer.new(org.jruby.embed.LocalContextScope::SINGLETHREAD)
152
+ vm.load_paths = [File.expand_path('../../lib', __FILE__)]
153
+ vm.environment = ENV.merge('RACK_ENV' => environment.to_s)
154
+
155
+ # This ensures processing of RUBYOPT which activates Bundler
156
+ vm.provider.ruby_instance_config.process_arguments []
157
+ vm.argv = ['-s', server.to_s, '-o', '127.0.0.1', '-p', port.to_s, '-e', environment.to_s]
158
+
159
+ # Set stdout/stderr so we can retrieve log
160
+ @pipe = java.io.ByteArrayOutputStream.new
161
+ vm.output = java.io.PrintStream.new(@pipe)
162
+ vm.error = java.io.PrintStream.new(@pipe)
163
+
164
+ Thread.new do
165
+ # Hack to ensure that Kernel#caller has the same info as
166
+ # when run from command-line, for Sintra::Application.app_file.
167
+ # Also, line numbers are zero-based in JRuby's parser
168
+ vm.provider.runtime.current_context.set_file_and_line(app_file, 0)
169
+ # Run the app
170
+ vm.run_scriptlet org.jruby.embed.PathType::ABSOLUTE, app_file
171
+ # terminate launches at_exit hooks which start server
172
+ vm.terminate
173
+ end
174
+ end
175
+
176
+ def run
177
+ return unless installed?
178
+ kill
179
+ @thread = start_vm
180
+ @started = Time.now
181
+ warn "#{server} up and running on port #{port}" if ping
182
+ at_exit { kill }
183
+ end
184
+
185
+ def log
186
+ String.from_java_bytes @pipe.to_byte_array
187
+ end
188
+
189
+ def kill
190
+ @thread.kill if @thread
191
+ @thread = nil
192
+ end
193
+ end
194
+ Server = JRubyServer
195
+ else
196
+ Server = BaseServer
197
+ end
198
+
199
+ def it(message, &block)
200
+ Server.each do |server|
201
+ next unless server.installed?
202
+ super("with #{server.name}: #{message}") { server.run_test(self, &block) }
203
+ end
204
+ end
205
+
206
+ def self.extend_object(obj)
207
+ super
208
+
209
+ base_port = 5000 + Process.pid % 100
210
+ Sinatra::Base.server.each_with_index do |server, index|
211
+ Server.run(server, 5000+index)
212
+ end
213
+ end
214
+ end