sinatra 1.3.0.e → 1.3.0.f
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.
- data/.travis.yml +16 -0
- data/CHANGES +77 -18
- data/Gemfile +43 -26
- data/README.de.rdoc +264 -88
- data/README.es.rdoc +241 -80
- data/README.fr.rdoc +206 -81
- data/README.hu.rdoc +2 -2
- data/README.jp.rdoc +2 -2
- data/README.pt-br.rdoc +2 -2
- data/README.pt-pt.rdoc +2 -2
- data/README.rdoc +169 -23
- data/README.ru.rdoc +373 -433
- data/README.zh.rdoc +5 -5
- data/Rakefile +8 -2
- data/lib/sinatra/base.rb +191 -46
- data/lib/sinatra/main.rb +1 -1
- data/lib/sinatra/showexceptions.rb +2 -2
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +7 -5
- data/test/contest.rb +62 -28
- data/test/filter_test.rb +2 -2
- data/test/helpers_test.rb +185 -12
- data/test/mapped_error_test.rb +25 -6
- data/test/nokogiri_test.rb +5 -6
- data/test/response_test.rb +10 -1
- data/test/result_test.rb +2 -2
- data/test/routing_test.rb +13 -0
- data/test/server_test.rb +3 -2
- data/test/settings_test.rb +98 -11
- data/test/slim_test.rb +15 -25
- data/test/static_test.rb +3 -3
- data/test/streaming_test.rb +100 -0
- metadata +82 -35
data/README.zh.rdoc
CHANGED
@@ -194,10 +194,10 @@ Rack body对象或者HTTP状态码:
|
|
194
194
|
|
195
195
|
== 静态文件
|
196
196
|
|
197
|
-
静态文件是从 <tt>./
|
197
|
+
静态文件是从 <tt>./public_folder</tt> 目录提供服务。你可以通过设置<tt>:public</tt>
|
198
198
|
选项设定一个不同的位置:
|
199
199
|
|
200
|
-
set :
|
200
|
+
set :public_folder, File.dirname(__FILE__) + '/static'
|
201
201
|
|
202
202
|
请注意public目录名并没有被包含在URL之中。文件
|
203
203
|
<tt>./public/css/style.css</tt>是通过
|
@@ -897,7 +897,7 @@ Session被用来在请求之间保持状态。如果被激活,每一个用户
|
|
897
897
|
get '/foo' do
|
898
898
|
status 418
|
899
899
|
headers \
|
900
|
-
"Allow" => "BREW, POST, GET, PROPFIND, WHEN"
|
900
|
+
"Allow" => "BREW, POST, GET, PROPFIND, WHEN",
|
901
901
|
"Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
|
902
902
|
body "I'm a tea pot!"
|
903
903
|
end
|
@@ -961,7 +961,7 @@ Sinatra并不理解。使用 +mime_type+ 通过文件扩展名来注册它们:
|
|
961
961
|
|
962
962
|
或者使用session:
|
963
963
|
|
964
|
-
enable :
|
964
|
+
enable :sessions
|
965
965
|
|
966
966
|
get '/foo' do
|
967
967
|
session[:secret] = 'foo'
|
@@ -1268,7 +1268,7 @@ Sinatra会自动处理range请求。
|
|
1268
1268
|
<tt>redirect '/foo'</tt> 会和
|
1269
1269
|
<tt>redirect to('/foo')</tt>起相同作用。默认禁用。
|
1270
1270
|
|
1271
|
-
[
|
1271
|
+
[public_folder] public文件夹的位置。
|
1272
1272
|
|
1273
1273
|
[reload_templates] 是否每个请求都重新载入模板。
|
1274
1274
|
在development mode和 Ruby 1.8.6 中被企业(用来
|
data/Rakefile
CHANGED
@@ -3,6 +3,12 @@ require 'rake/testtask'
|
|
3
3
|
require 'fileutils'
|
4
4
|
require 'date'
|
5
5
|
|
6
|
+
# CI Reporter is only needed for the CI
|
7
|
+
begin
|
8
|
+
require 'ci/reporter/rake/test_unit'
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
6
12
|
task :default => :test
|
7
13
|
task :spec => :test
|
8
14
|
|
@@ -77,7 +83,7 @@ task :add_template, [:name] do |t, args|
|
|
77
83
|
puts "Liquid not found in #{file}"
|
78
84
|
else
|
79
85
|
puts "Adding section to #{file}"
|
80
|
-
template = template.gsub(/Liquid/, args.name.capitalize).gsub(/liquid/, args.name.downcase)
|
86
|
+
template = template.gsub(/Liquid/, args.name.capitalize).gsub(/liquid/, args.name.downcase)
|
81
87
|
code.gsub! /^(\s*===.*CoffeeScript)/, "\n" << template << "\n\\1"
|
82
88
|
File.open(file, "w") { |f| f << code }
|
83
89
|
end
|
@@ -102,7 +108,7 @@ end
|
|
102
108
|
|
103
109
|
desc "list of authors"
|
104
110
|
task :authors, [:commit_range, :format, :sep] do |t, a|
|
105
|
-
a.with_defaults :format => "%s (%d)", :sep => ", "
|
111
|
+
a.with_defaults :format => "%s (%d)", :sep => ", ", :commit_range => '--all'
|
106
112
|
authors = Hash.new { |h,k| h[k] = 0 }
|
107
113
|
blake = "Blake Mizerany"
|
108
114
|
overall = 0
|
data/lib/sinatra/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# external dependencies
|
2
2
|
require 'rack'
|
3
3
|
require 'tilt'
|
4
|
+
require "rack/protection"
|
4
5
|
|
5
6
|
# stdlib dependencies
|
6
7
|
require 'thread'
|
@@ -39,6 +40,14 @@ module Sinatra
|
|
39
40
|
@env.include? "HTTP_X_FORWARDED_HOST"
|
40
41
|
end
|
41
42
|
|
43
|
+
def safe?
|
44
|
+
get? or head? or options? or trace?
|
45
|
+
end
|
46
|
+
|
47
|
+
def idempotent?
|
48
|
+
safe? or put? or delete?
|
49
|
+
end
|
50
|
+
|
42
51
|
private
|
43
52
|
|
44
53
|
def accept_entry(entry)
|
@@ -55,8 +64,8 @@ module Sinatra
|
|
55
64
|
# http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
|
56
65
|
class Response < Rack::Response
|
57
66
|
def body=(value)
|
58
|
-
value = value.body while
|
59
|
-
@body = value
|
67
|
+
value = value.body while Rack::Response === value
|
68
|
+
@body = String === value ? [value.to_str] : value
|
60
69
|
end
|
61
70
|
|
62
71
|
def each
|
@@ -64,10 +73,17 @@ module Sinatra
|
|
64
73
|
end
|
65
74
|
|
66
75
|
def finish
|
67
|
-
if
|
76
|
+
if status.to_i / 100 == 1
|
77
|
+
headers.delete "Content-Length"
|
78
|
+
headers.delete "Content-Type"
|
79
|
+
elsif Array === body and not [204, 304].include?(status.to_i)
|
68
80
|
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
|
69
81
|
end
|
70
|
-
|
82
|
+
|
83
|
+
# Rack::Response#finish sometimes returns self as response body. We don't want that.
|
84
|
+
status, headers, result = super
|
85
|
+
result = body if result == self
|
86
|
+
[status, headers, result]
|
71
87
|
end
|
72
88
|
end
|
73
89
|
|
@@ -98,7 +114,11 @@ module Sinatra
|
|
98
114
|
|
99
115
|
# Halt processing and redirect to the URI provided.
|
100
116
|
def redirect(uri, *args)
|
101
|
-
|
117
|
+
if env['HTTP_VERSION'] == 'HTTP/1.1' and env["REQUEST_METHOD"] != 'GET'
|
118
|
+
status 303
|
119
|
+
else
|
120
|
+
status 302
|
121
|
+
end
|
102
122
|
|
103
123
|
# According to RFC 2616 section 14.30, "the field value consists of a
|
104
124
|
# single absolute URI"
|
@@ -186,6 +206,8 @@ module Sinatra
|
|
186
206
|
if filename
|
187
207
|
params = '; filename="%s"' % File.basename(filename)
|
188
208
|
response['Content-Disposition'] << params
|
209
|
+
ext = File.extname(filename)
|
210
|
+
content_type(ext) unless response['Content-Type'] or ext.empty?
|
189
211
|
end
|
190
212
|
end
|
191
213
|
|
@@ -212,6 +234,61 @@ module Sinatra
|
|
212
234
|
not_found
|
213
235
|
end
|
214
236
|
|
237
|
+
# Class of the response body in case you use #stream.
|
238
|
+
#
|
239
|
+
# Three things really matter: The front and back block (back being the
|
240
|
+
# blog generating content, front the one sending it to the client) and
|
241
|
+
# the scheduler, integrating with whatever concurrency feature the Rack
|
242
|
+
# handler is using.
|
243
|
+
#
|
244
|
+
# Scheduler has to respond to defer and schedule.
|
245
|
+
class Stream
|
246
|
+
def self.schedule(*) yield end
|
247
|
+
def self.defer(*) yield end
|
248
|
+
|
249
|
+
def initialize(scheduler = self.class, keep_open = false, &back)
|
250
|
+
@back, @scheduler, @callback, @keep_open = back.to_proc, scheduler, nil, keep_open
|
251
|
+
end
|
252
|
+
|
253
|
+
def close
|
254
|
+
@scheduler.schedule { @callback.call if @callback }
|
255
|
+
end
|
256
|
+
|
257
|
+
def each(&front)
|
258
|
+
@front = front
|
259
|
+
@scheduler.defer do
|
260
|
+
begin
|
261
|
+
@back.call(self)
|
262
|
+
rescue Exception => e
|
263
|
+
@scheduler.schedule { raise e }
|
264
|
+
end
|
265
|
+
close unless @keep_open
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def <<(data)
|
270
|
+
@scheduler.schedule { @front.call(data.to_s) }
|
271
|
+
self
|
272
|
+
end
|
273
|
+
|
274
|
+
def callback(&block)
|
275
|
+
@callback = block
|
276
|
+
end
|
277
|
+
|
278
|
+
alias errback callback
|
279
|
+
end
|
280
|
+
|
281
|
+
# Allows to start sending data to the client even though later parts of
|
282
|
+
# the response body have not yet been generated.
|
283
|
+
#
|
284
|
+
# The close parameter specifies whether Stream#close should be called
|
285
|
+
# after the block has been executed. This is only relevant for evented
|
286
|
+
# servers like Thin or Rainbows.
|
287
|
+
def stream(keep_open = false, &block)
|
288
|
+
scheduler = env['async.callback'] ? EventMachine : Stream
|
289
|
+
body Stream.new(scheduler, keep_open, &block)
|
290
|
+
end
|
291
|
+
|
215
292
|
# Specify response freshness policy for HTTP caches (Cache-Control header).
|
216
293
|
# Any number of non-value directives (:public, :private, :no_cache,
|
217
294
|
# :no_store, :must_revalidate, :proxy_revalidate) may be passed along with
|
@@ -298,10 +375,13 @@ module Sinatra
|
|
298
375
|
value = 'W/' + value if kind == :weak
|
299
376
|
response['ETag'] = value
|
300
377
|
|
301
|
-
# Conditional GET check
|
302
378
|
if etags = env['HTTP_IF_NONE_MATCH']
|
303
379
|
etags = etags.split(/\s*,\s*/)
|
304
|
-
|
380
|
+
if etags.include?(value) or etags.include?('*')
|
381
|
+
halt 304 if request.safe?
|
382
|
+
else
|
383
|
+
halt 412 unless request.safe?
|
384
|
+
end
|
305
385
|
end
|
306
386
|
end
|
307
387
|
|
@@ -310,11 +390,38 @@ module Sinatra
|
|
310
390
|
request.referer
|
311
391
|
end
|
312
392
|
|
313
|
-
|
393
|
+
# whether or not the status is set to 1xx
|
394
|
+
def informational?
|
395
|
+
status.between? 100, 199
|
396
|
+
end
|
397
|
+
|
398
|
+
# whether or not the status is set to 2xx
|
399
|
+
def success?
|
400
|
+
status.between? 200, 299
|
401
|
+
end
|
402
|
+
|
403
|
+
# whether or not the status is set to 3xx
|
404
|
+
def redirect?
|
405
|
+
status.between? 300, 399
|
406
|
+
end
|
407
|
+
|
408
|
+
# whether or not the status is set to 4xx
|
409
|
+
def client_error?
|
410
|
+
status.between? 400, 499
|
411
|
+
end
|
412
|
+
|
413
|
+
# whether or not the status is set to 5xx
|
414
|
+
def server_error?
|
415
|
+
status.between? 500, 599
|
416
|
+
end
|
417
|
+
|
418
|
+
# whether or not the status is set to 404
|
419
|
+
def not_found?
|
420
|
+
status == 404
|
421
|
+
end
|
314
422
|
|
315
|
-
#
|
316
|
-
#
|
317
|
-
# if 1.8 support is dropped.
|
423
|
+
# Generates a Time object from the given value.
|
424
|
+
# Used by #expires and #last_modified.
|
318
425
|
def time_for(value)
|
319
426
|
if value.respond_to? :to_time
|
320
427
|
value.to_time
|
@@ -340,6 +447,8 @@ module Sinatra
|
|
340
447
|
end
|
341
448
|
end
|
342
449
|
|
450
|
+
private
|
451
|
+
|
343
452
|
# Template rendering methods. Each method takes the name of a template
|
344
453
|
# to render as a Symbol and returns a String with the rendered output,
|
345
454
|
# as well as an optional hash with additional options.
|
@@ -374,7 +483,7 @@ module Sinatra
|
|
374
483
|
|
375
484
|
def erubis(template, options={}, locals={})
|
376
485
|
warn "Sinatra::Templates#erubis is deprecated and will be removed, use #erb instead.\n" \
|
377
|
-
"If you have Erubis installed, it will be used automatically
|
486
|
+
"If you have Erubis installed, it will be used automatically."
|
378
487
|
render :erubis, template, options, locals
|
379
488
|
end
|
380
489
|
|
@@ -567,7 +676,7 @@ module Sinatra
|
|
567
676
|
invoke { error_block!(response.status) }
|
568
677
|
|
569
678
|
unless @response['Content-Type']
|
570
|
-
if body
|
679
|
+
if Array === body and body[0].respond_to? :content_type
|
571
680
|
content_type body[0].content_type
|
572
681
|
else
|
573
682
|
content_type :html
|
@@ -589,7 +698,7 @@ module Sinatra
|
|
589
698
|
|
590
699
|
def options
|
591
700
|
warn "Sinatra::Base#options is deprecated and will be removed, " \
|
592
|
-
"use #settings instead
|
701
|
+
"use #settings instead."
|
593
702
|
settings
|
594
703
|
end
|
595
704
|
|
@@ -653,12 +762,12 @@ module Sinatra
|
|
653
762
|
# Revert params afterwards.
|
654
763
|
#
|
655
764
|
# Returns pass block.
|
656
|
-
def process_route(pattern, keys, conditions, block = nil)
|
765
|
+
def process_route(pattern, keys, conditions, block = nil, values = [])
|
657
766
|
@original_params ||= @params
|
658
767
|
route = @request.path_info
|
659
768
|
route = '/' if route.empty? and not settings.empty_path_info?
|
660
769
|
if match = pattern.match(route)
|
661
|
-
values
|
770
|
+
values += match.captures.to_a.map { |v| force_encoding URI.decode(v) if v }
|
662
771
|
params =
|
663
772
|
if keys.any?
|
664
773
|
keys.zip(values).inject({}) do |hash,(k,v)|
|
@@ -701,7 +810,7 @@ module Sinatra
|
|
701
810
|
# Attempt to serve static files from public directory. Throws :halt when
|
702
811
|
# a matching file is found, returns nil otherwise.
|
703
812
|
def static!
|
704
|
-
return if (public_dir = settings.
|
813
|
+
return if (public_dir = settings.public_folder).nil?
|
705
814
|
public_dir = File.expand_path(public_dir)
|
706
815
|
|
707
816
|
path = File.expand_path(public_dir + unescape(request.path_info))
|
@@ -753,32 +862,34 @@ module Sinatra
|
|
753
862
|
# Error handling during requests.
|
754
863
|
def handle_exception!(boom)
|
755
864
|
@env['sinatra.error'] = boom
|
756
|
-
|
757
|
-
raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
|
758
|
-
@response.status = boom.respond_to?(:code) ? Integer(boom.code) : 500
|
865
|
+
status boom.respond_to?(:code) ? Integer(boom.code) : 500
|
759
866
|
|
760
|
-
if
|
761
|
-
|
762
|
-
|
867
|
+
if server_error?
|
868
|
+
dump_errors! boom if settings.dump_errors?
|
869
|
+
raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
|
763
870
|
end
|
764
871
|
|
765
|
-
if
|
766
|
-
|
767
|
-
|
768
|
-
raise boom if settings.raise_errors? or settings.show_exceptions?
|
769
|
-
error_block! Exception
|
872
|
+
if not_found?
|
873
|
+
headers['X-Cascade'] = 'pass'
|
874
|
+
body '<h1>Not Found</h1>'
|
770
875
|
end
|
876
|
+
|
877
|
+
res = error_block!(boom.class, boom) || error_block!(status, boom)
|
878
|
+
return res if res or not server_error?
|
879
|
+
raise boom if settings.raise_errors? or settings.show_exceptions?
|
880
|
+
error_block! Exception, boom
|
771
881
|
end
|
772
882
|
|
773
883
|
# Find an custom error block for the key(s) specified.
|
774
|
-
def error_block!(key)
|
884
|
+
def error_block!(key, *block_params)
|
775
885
|
base = settings
|
776
886
|
while base.respond_to?(:errors)
|
777
887
|
next base = base.superclass unless args = base.errors[key]
|
888
|
+
args += [block_params]
|
778
889
|
return process_route(*args)
|
779
890
|
end
|
780
891
|
return false unless key.respond_to? :superclass and key.superclass < Exception
|
781
|
-
error_block!
|
892
|
+
error_block!(key.superclass, *block_params)
|
782
893
|
end
|
783
894
|
|
784
895
|
def dump_errors!(boom)
|
@@ -979,6 +1090,11 @@ module Sinatra
|
|
979
1090
|
@conditions << generate_method(name, &block)
|
980
1091
|
end
|
981
1092
|
|
1093
|
+
def public=(value)
|
1094
|
+
warn ":public is no longer used to avoid overloading Module#public, use :public_folder instead"
|
1095
|
+
set(:public_folder, value)
|
1096
|
+
end
|
1097
|
+
|
982
1098
|
private
|
983
1099
|
# Condition for matching host name. Parameter might be String or Regexp.
|
984
1100
|
def host_name(pattern)
|
@@ -1036,8 +1152,10 @@ module Sinatra
|
|
1036
1152
|
# Because of self.options.host
|
1037
1153
|
host_name(options.delete(:host)) if options.key?(:host)
|
1038
1154
|
enable :empty_path_info if path == "" and empty_path_info.nil?
|
1039
|
-
|
1155
|
+
signature = compile!(verb, path, block, options)
|
1156
|
+
(@routes[verb] ||= []) << signature
|
1040
1157
|
invoke_hook(:route_added, verb, path, block)
|
1158
|
+
signature
|
1041
1159
|
end
|
1042
1160
|
|
1043
1161
|
def invoke_hook(name, *args)
|
@@ -1134,23 +1252,28 @@ module Sinatra
|
|
1134
1252
|
def quit!(server, handler_name)
|
1135
1253
|
# Use Thin's hard #stop! if available, otherwise just #stop.
|
1136
1254
|
server.respond_to?(:stop!) ? server.stop! : server.stop
|
1137
|
-
|
1255
|
+
$stderr.puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i
|
1138
1256
|
end
|
1139
1257
|
|
1140
1258
|
# Run the Sinatra app as a self-hosted server using
|
1141
|
-
# Thin, Mongrel or WEBrick (in that order)
|
1259
|
+
# Thin, Mongrel or WEBrick (in that order). If given a block, will call
|
1260
|
+
# with the constructed handler once we have taken the stage.
|
1142
1261
|
def run!(options={})
|
1143
1262
|
set options
|
1144
1263
|
handler = detect_rack_handler
|
1145
1264
|
handler_name = handler.name.gsub(/.*::/, '')
|
1146
|
-
STDERR.puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
|
1147
|
-
"on #{port} for #{environment} with backup from #{handler_name}" unless handler_name =~/cgi/i
|
1148
1265
|
handler.run self, :Host => bind, :Port => port do |server|
|
1266
|
+
unless handler_name =~ /cgi/i
|
1267
|
+
$stderr.puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
|
1268
|
+
"on #{port} for #{environment} with backup from #{handler_name}"
|
1269
|
+
end
|
1149
1270
|
[:INT, :TERM].each { |sig| trap(sig) { quit!(server, handler_name) } }
|
1271
|
+
server.threaded = settings.threaded if server.respond_to? :threaded=
|
1150
1272
|
set :running, true
|
1273
|
+
yield server if block_given?
|
1151
1274
|
end
|
1152
1275
|
rescue Errno::EADDRINUSE => e
|
1153
|
-
|
1276
|
+
$stderr.puts "== Someone is already performing on port #{port}!"
|
1154
1277
|
end
|
1155
1278
|
|
1156
1279
|
# The prototype instance used to process requests.
|
@@ -1186,8 +1309,9 @@ module Sinatra
|
|
1186
1309
|
builder.use ShowExceptions if show_exceptions?
|
1187
1310
|
builder.use Rack::MethodOverride if method_override?
|
1188
1311
|
builder.use Rack::Head
|
1189
|
-
setup_logging
|
1190
|
-
setup_sessions
|
1312
|
+
setup_logging builder
|
1313
|
+
setup_sessions builder
|
1314
|
+
setup_protection builder
|
1191
1315
|
end
|
1192
1316
|
|
1193
1317
|
def setup_middleware(builder)
|
@@ -1207,6 +1331,14 @@ module Sinatra
|
|
1207
1331
|
end
|
1208
1332
|
end
|
1209
1333
|
|
1334
|
+
def setup_protection(builder)
|
1335
|
+
return unless protection?
|
1336
|
+
options = Hash === protection ? protection.dup : {}
|
1337
|
+
options[:except] = Array options[:except]
|
1338
|
+
options[:except] += [:session_hijacking, :remote_token] unless sessions?
|
1339
|
+
builder.use Rack::Protection, options
|
1340
|
+
end
|
1341
|
+
|
1210
1342
|
def setup_sessions(builder)
|
1211
1343
|
return unless sessions?
|
1212
1344
|
options = {}
|
@@ -1219,7 +1351,7 @@ module Sinatra
|
|
1219
1351
|
servers = Array(server)
|
1220
1352
|
servers.each do |server_name|
|
1221
1353
|
begin
|
1222
|
-
return Rack::Handler.get(server_name)
|
1354
|
+
return Rack::Handler.get(server_name.to_s)
|
1223
1355
|
rescue LoadError
|
1224
1356
|
rescue NameError
|
1225
1357
|
end
|
@@ -1250,7 +1382,8 @@ module Sinatra
|
|
1250
1382
|
/rubygems\/custom_require\.rb$/, # rubygems require hacks
|
1251
1383
|
/active_support/, # active_support require hacks
|
1252
1384
|
/bundler(\/runtime)?\.rb/, # bundler require hacks
|
1253
|
-
/<internal
|
1385
|
+
/<internal:/, # internal in ruby >= 1.9.2
|
1386
|
+
/src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
|
1254
1387
|
]
|
1255
1388
|
|
1256
1389
|
# add rubinius (and hopefully other VM impls) ignore patterns ...
|
@@ -1259,16 +1392,26 @@ module Sinatra
|
|
1259
1392
|
# Like Kernel#caller but excluding certain magic entries and without
|
1260
1393
|
# line / method information; the resulting array contains filenames only.
|
1261
1394
|
def caller_files
|
1262
|
-
|
1263
|
-
map { |file,line| file }
|
1395
|
+
cleaned_caller(1).flatten
|
1264
1396
|
end
|
1265
1397
|
|
1266
1398
|
# Like caller_files, but containing Arrays rather than strings with the
|
1267
1399
|
# first element being the file, and the second being the line.
|
1268
1400
|
def caller_locations
|
1401
|
+
cleaned_caller 2
|
1402
|
+
end
|
1403
|
+
|
1404
|
+
private
|
1405
|
+
# used for deprecation warnings
|
1406
|
+
def warn(message)
|
1407
|
+
super message + "\n\tfrom #{cleaned_caller.first.join(':')}"
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
# Like Kernel#caller but excluding certain magic entries
|
1411
|
+
def cleaned_caller(keep = 3)
|
1269
1412
|
caller(1).
|
1270
|
-
map { |line| line.split(/:(?=\d|in )
|
1271
|
-
reject { |file,
|
1413
|
+
map { |line| line.split(/:(?=\d|in )/, 3)[0,keep] }.
|
1414
|
+
reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
1272
1415
|
end
|
1273
1416
|
end
|
1274
1417
|
|
@@ -1303,6 +1446,7 @@ module Sinatra
|
|
1303
1446
|
set :show_exceptions, Proc.new { development? }
|
1304
1447
|
set :sessions, false
|
1305
1448
|
set :logging, false
|
1449
|
+
set :protection, true
|
1306
1450
|
set :method_override, false
|
1307
1451
|
set :default_encoding, "utf-8"
|
1308
1452
|
set :add_charset, %w[javascript xml xhtml+xml json].map { |t| "application/#{t}" }
|
@@ -1337,9 +1481,10 @@ module Sinatra
|
|
1337
1481
|
set :views, Proc.new { root && File.join(root, 'views') }
|
1338
1482
|
set :reload_templates, Proc.new { development? }
|
1339
1483
|
set :lock, false
|
1484
|
+
set :threaded, true
|
1340
1485
|
|
1341
|
-
set :
|
1342
|
-
set :static, Proc.new {
|
1486
|
+
set :public_folder, Proc.new { root && File.join(root, 'public') }
|
1487
|
+
set :static, Proc.new { public_folder && File.exist?(public_folder) }
|
1343
1488
|
set :static_cache_control, false
|
1344
1489
|
|
1345
1490
|
error ::Exception do
|