sinatra 2.2.0 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sinatra/base.rb CHANGED
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # external dependencies
@@ -10,7 +9,6 @@ require 'mustermann/sinatra'
10
9
  require 'mustermann/regular'
11
10
 
12
11
  # stdlib dependencies
13
- require 'thread'
14
12
  require 'time'
15
13
  require 'uri'
16
14
 
@@ -23,19 +21,20 @@ module Sinatra
23
21
  # The request object. See Rack::Request for more info:
24
22
  # http://rubydoc.info/github/rack/rack/master/Rack/Request
25
23
  class Request < Rack::Request
26
- HEADER_PARAM = /\s*[\w.]+=(?:[\w.]+|"(?:[^"\\]|\\.)*")?\s*/
27
- HEADER_VALUE_WITH_PARAMS = /(?:(?:\w+|\*)\/(?:\w+(?:\.|\-|\+)?|\*)*)\s*(?:;#{HEADER_PARAM})*/
24
+ HEADER_PARAM = /\s*[\w.]+=(?:[\w.]+|"(?:[^"\\]|\\.)*")?\s*/.freeze
25
+ HEADER_VALUE_WITH_PARAMS = %r{(?:(?:\w+|\*)/(?:\w+(?:\.|-|\+)?|\*)*)\s*(?:;#{HEADER_PARAM})*}.freeze
28
26
 
29
27
  # Returns an array of acceptable media types for the response
30
28
  def accept
31
- @env['sinatra.accept'] ||= begin
32
- if @env.include? 'HTTP_ACCEPT' and @env['HTTP_ACCEPT'].to_s != ''
33
- @env['HTTP_ACCEPT'].to_s.scan(HEADER_VALUE_WITH_PARAMS).
34
- map! { |e| AcceptEntry.new(e) }.sort
35
- else
36
- [AcceptEntry.new('*/*')]
37
- end
38
- end
29
+ @env['sinatra.accept'] ||= if @env.include?('HTTP_ACCEPT') && (@env['HTTP_ACCEPT'].to_s != '')
30
+ @env['HTTP_ACCEPT']
31
+ .to_s
32
+ .scan(HEADER_VALUE_WITH_PARAMS)
33
+ .map! { |e| AcceptEntry.new(e) }
34
+ .sort
35
+ else
36
+ [AcceptEntry.new('*/*')]
37
+ end
39
38
  end
40
39
 
41
40
  def accept?(type)
@@ -44,8 +43,10 @@ module Sinatra
44
43
 
45
44
  def preferred_type(*types)
46
45
  return accept.first if types.empty?
46
+
47
47
  types.flatten!
48
48
  return types.first if accept.empty?
49
+
49
50
  accept.detect do |accept_header|
50
51
  type = types.detect { |t| MimeTypeEntry.new(t).accepts?(accept_header) }
51
52
  return type if type
@@ -55,23 +56,23 @@ module Sinatra
55
56
  alias secure? ssl?
56
57
 
57
58
  def forwarded?
58
- @env.include? "HTTP_X_FORWARDED_HOST"
59
+ @env.include? 'HTTP_X_FORWARDED_HOST'
59
60
  end
60
61
 
61
62
  def safe?
62
- get? or head? or options? or trace?
63
+ get? || head? || options? || trace?
63
64
  end
64
65
 
65
66
  def idempotent?
66
- safe? or put? or delete? or link? or unlink?
67
+ safe? || put? || delete? || link? || unlink?
67
68
  end
68
69
 
69
70
  def link?
70
- request_method == "LINK"
71
+ request_method == 'LINK'
71
72
  end
72
73
 
73
74
  def unlink?
74
- request_method == "UNLINK"
75
+ request_method == 'UNLINK'
75
76
  end
76
77
 
77
78
  def params
@@ -95,17 +96,17 @@ module Sinatra
95
96
 
96
97
  @entry = entry
97
98
  @type = entry[/[^;]+/].delete(' ')
98
- @params = Hash[params]
99
+ @params = params.to_h
99
100
  @q = @params.delete('q') { 1.0 }.to_f
100
101
  end
101
102
 
102
103
  def <=>(other)
103
- other.priority <=> self.priority
104
+ other.priority <=> priority
104
105
  end
105
106
 
106
107
  def priority
107
108
  # We sort in descending order; better matches should be higher.
108
- [ @q, -@type.count('*'), @params.size ]
109
+ [@q, -@type.count('*'), @params.size]
109
110
  end
110
111
 
111
112
  def to_str
@@ -117,7 +118,7 @@ module Sinatra
117
118
  end
118
119
 
119
120
  def respond_to?(*args)
120
- super or to_str.respond_to?(*args)
121
+ super || to_str.respond_to?(*args)
121
122
  end
122
123
 
123
124
  def method_missing(*args, &block)
@@ -136,7 +137,7 @@ module Sinatra
136
137
  end
137
138
 
138
139
  @type = entry[/[^;]+/].delete(' ')
139
- @params = Hash[params]
140
+ @params = params.to_h
140
141
  end
141
142
 
142
143
  def accepts?(entry)
@@ -150,7 +151,7 @@ module Sinatra
150
151
  def matches_params?(params)
151
152
  return true if @params.empty?
152
153
 
153
- params.all? { |k,v| !@params.has_key?(k) || @params[k] == v }
154
+ params.all? { |k, v| !@params.key?(k) || @params[k] == v }
154
155
  end
155
156
  end
156
157
  end
@@ -160,7 +161,7 @@ module Sinatra
160
161
  # http://rubydoc.info/github/rack/rack/master/Rack/Response
161
162
  # http://rubydoc.info/github/rack/rack/master/Rack/Response/Helpers
162
163
  class Response < Rack::Response
163
- DROP_BODY_RESPONSES = [204, 304]
164
+ DROP_BODY_RESPONSES = [204, 304].freeze
164
165
 
165
166
  def body=(value)
166
167
  value = value.body while Rack::Response === value
@@ -175,8 +176,8 @@ module Sinatra
175
176
  result = body
176
177
 
177
178
  if drop_content_info?
178
- headers.delete "Content-Length"
179
- headers.delete "Content-Type"
179
+ headers.delete 'Content-Length'
180
+ headers.delete 'Content-Type'
180
181
  end
181
182
 
182
183
  if drop_body?
@@ -187,7 +188,7 @@ module Sinatra
187
188
  if calculate_content_length?
188
189
  # if some other code has already set Content-Length, don't muck with it
189
190
  # currently, this would be the static file-handler
190
- headers["Content-Length"] = body.map(&:bytesize).reduce(0, :+).to_s
191
+ headers['Content-Length'] = body.map(&:bytesize).reduce(0, :+).to_s
191
192
  end
192
193
 
193
194
  [status, headers, result]
@@ -196,11 +197,11 @@ module Sinatra
196
197
  private
197
198
 
198
199
  def calculate_content_length?
199
- headers["Content-Type"] and not headers["Content-Length"] and Array === body
200
+ headers['Content-Type'] && !headers['Content-Length'] && (Array === body)
200
201
  end
201
202
 
202
203
  def drop_content_info?
203
- informational? or drop_body?
204
+ informational? || drop_body?
204
205
  end
205
206
 
206
207
  def drop_body?
@@ -215,8 +216,10 @@ module Sinatra
215
216
  # still be able to run.
216
217
  class ExtendedRack < Struct.new(:app)
217
218
  def call(env)
218
- result, callback = app.call(env), env['async.callback']
219
- return result unless callback and async?(*result)
219
+ result = app.call(env)
220
+ callback = env['async.callback']
221
+ return result unless callback && async?(*result)
222
+
220
223
  after_response { callback.call result }
221
224
  setup_close(env, *result)
222
225
  throw :async
@@ -224,20 +227,23 @@ module Sinatra
224
227
 
225
228
  private
226
229
 
227
- def setup_close(env, status, headers, body)
228
- return unless body.respond_to? :close and env.include? 'async.close'
230
+ def setup_close(env, _status, _headers, body)
231
+ return unless body.respond_to?(:close) && env.include?('async.close')
232
+
229
233
  env['async.close'].callback { body.close }
230
234
  env['async.close'].errback { body.close }
231
235
  end
232
236
 
233
237
  def after_response(&block)
234
- raise NotImplementedError, "only supports EventMachine at the moment" unless defined? EventMachine
238
+ raise NotImplementedError, 'only supports EventMachine at the moment' unless defined? EventMachine
239
+
235
240
  EventMachine.next_tick(&block)
236
241
  end
237
242
 
238
- def async?(status, headers, body)
243
+ def async?(status, _headers, body)
239
244
  return true if status == -1
240
- body.respond_to? :callback and body.respond_to? :errback
245
+
246
+ body.respond_to?(:callback) && body.respond_to?(:errback)
241
247
  end
242
248
  end
243
249
 
@@ -249,7 +255,7 @@ module Sinatra
249
255
  end
250
256
 
251
257
  superclass.class_eval do
252
- alias call_without_check call unless method_defined? :call_without_check
258
+ alias_method :call_without_check, :call unless method_defined? :call_without_check
253
259
  def call(env)
254
260
  env['sinatra.commonlogger'] = true
255
261
  call_without_check(env)
@@ -257,11 +263,14 @@ module Sinatra
257
263
  end
258
264
  end
259
265
 
260
- class BadRequest < TypeError #:nodoc:
266
+ class Error < StandardError # :nodoc:
267
+ end
268
+
269
+ class BadRequest < Error # :nodoc:
261
270
  def http_status; 400 end
262
271
  end
263
272
 
264
- class NotFound < NameError #:nodoc:
273
+ class NotFound < Error # :nodoc:
265
274
  def http_status; 404 end
266
275
  end
267
276
 
@@ -293,7 +302,7 @@ module Sinatra
293
302
 
294
303
  # Halt processing and redirect to the URI provided.
295
304
  def redirect(uri, *args)
296
- if env['HTTP_VERSION'] == 'HTTP/1.1' and env["REQUEST_METHOD"] != 'GET'
305
+ if (env['HTTP_VERSION'] == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
297
306
  status 303
298
307
  else
299
308
  status 302
@@ -308,18 +317,19 @@ module Sinatra
308
317
  # Generates the absolute URI for a given path in the app.
309
318
  # Takes Rack routers and reverse proxies into account.
310
319
  def uri(addr = nil, absolute = true, add_script_name = true)
311
- return addr if addr =~ /\A[a-z][a-z0-9\+\.\-]*:/i
320
+ return addr if addr =~ /\A[a-z][a-z0-9+.\-]*:/i
321
+
312
322
  uri = [host = String.new]
313
323
  if absolute
314
324
  host << "http#{'s' if request.secure?}://"
315
- if request.forwarded? or request.port != (request.secure? ? 443 : 80)
316
- host << request.host_with_port
317
- else
318
- host << request.host
319
- end
325
+ host << if request.forwarded? || (request.port != (request.secure? ? 443 : 80))
326
+ request.host_with_port
327
+ else
328
+ request.host
329
+ end
320
330
  end
321
331
  uri << request.script_name.to_s if add_script_name
322
- uri << (addr ? addr : request.path_info).to_s
332
+ uri << (addr || request.path_info).to_s
323
333
  File.join uri
324
334
  end
325
335
 
@@ -328,7 +338,10 @@ module Sinatra
328
338
 
329
339
  # Halt processing and return the error status provided.
330
340
  def error(code, body = nil)
331
- code, body = 500, code.to_str if code.respond_to? :to_str
341
+ if code.respond_to? :to_str
342
+ body = code.to_str
343
+ code = 500
344
+ end
332
345
  response.body = body unless body.nil?
333
346
  halt code
334
347
  end
@@ -363,11 +376,13 @@ module Sinatra
363
376
  # extension.
364
377
  def content_type(type = nil, params = {})
365
378
  return response['Content-Type'] unless type
379
+
366
380
  default = params.delete :default
367
381
  mime_type = mime_type(type) || default
368
- fail "Unknown media type: %p" % type if mime_type.nil?
382
+ raise format('Unknown media type: %p', type) if mime_type.nil?
383
+
369
384
  mime_type = mime_type.dup
370
- unless params.include? :charset or settings.add_charset.all? { |p| not p === mime_type }
385
+ unless params.include?(:charset) || settings.add_charset.all? { |p| !(p === mime_type) }
371
386
  params[:charset] = params.delete('charset') || settings.default_encoding
372
387
  end
373
388
  params.delete :charset if mime_type.include? 'charset'
@@ -381,27 +396,34 @@ module Sinatra
381
396
  response['Content-Type'] = mime_type
382
397
  end
383
398
 
399
+ # https://html.spec.whatwg.org/#multipart-form-data
400
+ MULTIPART_FORM_DATA_REPLACEMENT_TABLE = {
401
+ '"' => '%22',
402
+ "\r" => '%0D',
403
+ "\n" => '%0A'
404
+ }.freeze
405
+
384
406
  # Set the Content-Disposition to "attachment" with the specified filename,
385
407
  # instructing the user agents to prompt to save.
386
408
  def attachment(filename = nil, disposition = :attachment)
387
409
  response['Content-Disposition'] = disposition.to_s.dup
388
- if filename
389
- params = '; filename="%s"' % File.basename(filename)
390
- response['Content-Disposition'] << params
391
- ext = File.extname(filename)
392
- content_type(ext) unless response['Content-Type'] or ext.empty?
393
- end
410
+ return unless filename
411
+
412
+ params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE))
413
+ response['Content-Disposition'] << params
414
+ ext = File.extname(filename)
415
+ content_type(ext) unless response['Content-Type'] || ext.empty?
394
416
  end
395
417
 
396
418
  # Use the contents of the file at +path+ as the response body.
397
419
  def send_file(path, opts = {})
398
- if opts[:type] or not response['Content-Type']
399
- content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
420
+ if opts[:type] || !response['Content-Type']
421
+ content_type opts[:type] || File.extname(path), default: 'application/octet-stream'
400
422
  end
401
423
 
402
424
  disposition = opts[:disposition]
403
425
  filename = opts[:filename]
404
- disposition = :attachment if disposition.nil? and filename
426
+ disposition = :attachment if disposition.nil? && filename
405
427
  filename = path if filename.nil?
406
428
  attachment(filename, disposition) if disposition
407
429
 
@@ -410,7 +432,7 @@ module Sinatra
410
432
  file = Rack::File.new(File.dirname(settings.app_file))
411
433
  result = file.serving(request, path)
412
434
 
413
- result[1].each { |k,v| headers[k] ||= v }
435
+ result[1].each { |k, v| headers[k] ||= v }
414
436
  headers['Content-Length'] = result[1]['Content-Length']
415
437
  opts[:status] &&= Integer(opts[:status])
416
438
  halt (opts[:status] || result[0]), result[2]
@@ -431,12 +453,16 @@ module Sinatra
431
453
  def self.defer(*) yield end
432
454
 
433
455
  def initialize(scheduler = self.class, keep_open = false, &back)
434
- @back, @scheduler, @keep_open = back.to_proc, scheduler, keep_open
435
- @callbacks, @closed = [], false
456
+ @back = back.to_proc
457
+ @scheduler = scheduler
458
+ @keep_open = keep_open
459
+ @callbacks = []
460
+ @closed = false
436
461
  end
437
462
 
438
463
  def close
439
464
  return if closed?
465
+
440
466
  @closed = true
441
467
  @scheduler.schedule { @callbacks.each { |c| c.call } }
442
468
  end
@@ -460,6 +486,7 @@ module Sinatra
460
486
 
461
487
  def callback(&block)
462
488
  return yield if closed?
489
+
463
490
  @callbacks << block
464
491
  end
465
492
 
@@ -493,18 +520,18 @@ module Sinatra
493
520
  # See RFC 2616 / 14.9 for more on standard cache control directives:
494
521
  # http://tools.ietf.org/html/rfc2616#section-14.9.1
495
522
  def cache_control(*values)
496
- if values.last.kind_of?(Hash)
523
+ if values.last.is_a?(Hash)
497
524
  hash = values.pop
498
- hash.reject! { |k, v| v == false }
525
+ hash.reject! { |_k, v| v == false }
499
526
  hash.reject! { |k, v| values << k if v == true }
500
527
  else
501
528
  hash = {}
502
529
  end
503
530
 
504
- values.map! { |value| value.to_s.tr('_','-') }
531
+ values.map! { |value| value.to_s.tr('_', '-') }
505
532
  hash.each do |key, value|
506
533
  key = key.to_s.tr('_', '-')
507
- value = value.to_i if ['max-age', 's-maxage'].include? key
534
+ value = value.to_i if %w[max-age s-maxage].include? key
508
535
  values << "#{key}=#{value}"
509
536
  end
510
537
 
@@ -521,7 +548,7 @@ module Sinatra
521
548
  # => Expires: Mon, 08 Jun 2009 08:50:17 GMT
522
549
  #
523
550
  def expires(amount, *values)
524
- values << {} unless values.last.kind_of?(Hash)
551
+ values << {} unless values.last.is_a?(Hash)
525
552
 
526
553
  if amount.is_a? Integer
527
554
  time = Time.now + amount.to_i
@@ -531,7 +558,7 @@ module Sinatra
531
558
  max_age = time - Time.now
532
559
  end
533
560
 
534
- values.last.merge!(:max_age => max_age)
561
+ values.last.merge!(max_age: max_age) { |_key, v1, v2| v1 || v2 }
535
562
  cache_control(*values)
536
563
 
537
564
  response['Expires'] = time.httpdate
@@ -546,17 +573,18 @@ module Sinatra
546
573
  # with a '304 Not Modified' response.
547
574
  def last_modified(time)
548
575
  return unless time
576
+
549
577
  time = time_for time
550
578
  response['Last-Modified'] = time.httpdate
551
579
  return if env['HTTP_IF_NONE_MATCH']
552
580
 
553
- if status == 200 and env['HTTP_IF_MODIFIED_SINCE']
581
+ if (status == 200) && env['HTTP_IF_MODIFIED_SINCE']
554
582
  # compare based on seconds since epoch
555
583
  since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i
556
584
  halt 304 if since >= time.to_i
557
585
  end
558
586
 
559
- if (success? or status == 412) and env['HTTP_IF_UNMODIFIED_SINCE']
587
+ if (success? || (status == 412)) && env['HTTP_IF_UNMODIFIED_SINCE']
560
588
  # compare based on seconds since epoch
561
589
  since = Time.httpdate(env['HTTP_IF_UNMODIFIED_SINCE']).to_i
562
590
  halt 412 if since < time.to_i
@@ -564,7 +592,7 @@ module Sinatra
564
592
  rescue ArgumentError
565
593
  end
566
594
 
567
- ETAG_KINDS = [:strong, :weak]
595
+ ETAG_KINDS = %i[strong weak].freeze
568
596
  # Set the response entity tag (HTTP 'ETag' header) and halt if conditional
569
597
  # GET matches. The +value+ argument is an identifier that uniquely
570
598
  # identifies the current version of the resource. The +kind+ argument
@@ -576,27 +604,31 @@ module Sinatra
576
604
  # GET or HEAD, a '304 Not Modified' response is sent.
577
605
  def etag(value, options = {})
578
606
  # Before touching this code, please double check RFC 2616 14.24 and 14.26.
579
- options = {:kind => options} unless Hash === options
607
+ options = { kind: options } unless Hash === options
580
608
  kind = options[:kind] || :strong
581
609
  new_resource = options.fetch(:new_resource) { request.post? }
582
610
 
583
611
  unless ETAG_KINDS.include?(kind)
584
- raise ArgumentError, ":strong or :weak expected"
612
+ raise ArgumentError, ':strong or :weak expected'
585
613
  end
586
614
 
587
- value = '"%s"' % value
615
+ value = format('"%s"', value)
588
616
  value = "W/#{value}" if kind == :weak
589
617
  response['ETag'] = value
590
618
 
591
- if success? or status == 304
592
- if etag_matches? env['HTTP_IF_NONE_MATCH'], new_resource
593
- halt(request.safe? ? 304 : 412)
594
- end
619
+ return unless success? || status == 304
595
620
 
596
- if env['HTTP_IF_MATCH']
597
- halt 412 unless etag_matches? env['HTTP_IF_MATCH'], new_resource
598
- end
621
+ if etag_matches?(env['HTTP_IF_NONE_MATCH'], new_resource)
622
+ halt(request.safe? ? 304 : 412)
623
+ end
624
+
625
+ if env['HTTP_IF_MATCH']
626
+ return if etag_matches?(env['HTTP_IF_MATCH'], new_resource)
627
+
628
+ halt 412
599
629
  end
630
+
631
+ nil
600
632
  end
601
633
 
602
634
  # Sugar for redirect (example: redirect back)
@@ -649,8 +681,8 @@ module Sinatra
649
681
  else
650
682
  value.to_time
651
683
  end
652
- rescue ArgumentError => boom
653
- raise boom
684
+ rescue ArgumentError => e
685
+ raise e
654
686
  rescue Exception
655
687
  raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
656
688
  end
@@ -660,11 +692,13 @@ module Sinatra
660
692
  # Helper method checking if a ETag value list includes the current ETag.
661
693
  def etag_matches?(list, new_resource = request.post?)
662
694
  return !new_resource if list == '*'
695
+
663
696
  list.to_s.split(/\s*,\s*/).include? response['ETag']
664
697
  end
665
698
 
666
699
  def with_params(temp_params)
667
- original, @params = @params, temp_params
700
+ original = @params
701
+ @params = temp_params
668
702
  yield
669
703
  ensure
670
704
  @params = original if original
@@ -682,7 +716,7 @@ module Sinatra
682
716
  # Possible options are:
683
717
  # :content_type The content type to use, same arguments as content_type.
684
718
  # :layout If set to something falsy, no layout is rendered, otherwise
685
- # the specified layout is used (Ignored for `sass` and `less`)
719
+ # the specified layout is used
686
720
  # :layout_engine Engine to use for rendering the layout.
687
721
  # :locals A hash with local variables that should be available
688
722
  # in the template
@@ -704,36 +738,10 @@ module Sinatra
704
738
  render(:erb, template, options, locals, &block)
705
739
  end
706
740
 
707
- def erubis(template, options = {}, locals = {})
708
- warn "Sinatra::Templates#erubis is deprecated and will be removed, use #erb instead.\n" \
709
- "If you have Erubis installed, it will be used automatically."
710
- render :erubis, template, options, locals
711
- end
712
-
713
741
  def haml(template, options = {}, locals = {}, &block)
714
742
  render(:haml, template, options, locals, &block)
715
743
  end
716
744
 
717
- def sass(template, options = {}, locals = {})
718
- options.merge! :layout => false, :default_content_type => :css
719
- render :sass, template, options, locals
720
- end
721
-
722
- def scss(template, options = {}, locals = {})
723
- options.merge! :layout => false, :default_content_type => :css
724
- render :scss, template, options, locals
725
- end
726
-
727
- def less(template, options = {}, locals = {})
728
- options.merge! :layout => false, :default_content_type => :css
729
- render :less, template, options, locals
730
- end
731
-
732
- def stylus(template, options = {}, locals = {})
733
- options.merge! :layout => false, :default_content_type => :css
734
- render :styl, template, options, locals
735
- end
736
-
737
745
  def builder(template = nil, options = {}, locals = {}, &block)
738
746
  options[:default_content_type] = :xml
739
747
  render_ruby(:builder, template, options, locals, &block)
@@ -748,10 +756,6 @@ module Sinatra
748
756
  render :markdown, template, options, locals
749
757
  end
750
758
 
751
- def textile(template, options = {}, locals = {})
752
- render :textile, template, options, locals
753
- end
754
-
755
759
  def rdoc(template, options = {}, locals = {})
756
760
  render :rdoc, template, options, locals
757
761
  end
@@ -760,19 +764,10 @@ module Sinatra
760
764
  render :asciidoc, template, options, locals
761
765
  end
762
766
 
763
- def radius(template, options = {}, locals = {})
764
- render :radius, template, options, locals
765
- end
766
-
767
767
  def markaby(template = nil, options = {}, locals = {}, &block)
768
768
  render_ruby(:mab, template, options, locals, &block)
769
769
  end
770
770
 
771
- def coffee(template, options = {}, locals = {})
772
- options.merge! :layout => false, :default_content_type => :js
773
- render :coffee, template, options, locals
774
- end
775
-
776
771
  def nokogiri(template = nil, options = {}, locals = {}, &block)
777
772
  options[:default_content_type] = :xml
778
773
  render_ruby(:nokogiri, template, options, locals, &block)
@@ -782,18 +777,6 @@ module Sinatra
782
777
  render(:slim, template, options, locals, &block)
783
778
  end
784
779
 
785
- def creole(template, options = {}, locals = {})
786
- render :creole, template, options, locals
787
- end
788
-
789
- def mediawiki(template, options = {}, locals = {})
790
- render :mediawiki, template, options, locals
791
- end
792
-
793
- def wlang(template, options = {}, locals = {}, &block)
794
- render(:wlang, template, options, locals, &block)
795
- end
796
-
797
780
  def yajl(template, options = {}, locals = {})
798
781
  options[:default_content_type] = :json
799
782
  render :yajl, template, options, locals
@@ -818,24 +801,27 @@ module Sinatra
818
801
 
819
802
  # logic shared between builder and nokogiri
820
803
  def render_ruby(engine, template, options = {}, locals = {}, &block)
821
- options, template = template, nil if template.is_a?(Hash)
822
- template = Proc.new { block } if template.nil?
804
+ if template.is_a?(Hash)
805
+ options = template
806
+ template = nil
807
+ end
808
+ template = proc { block } if template.nil?
823
809
  render engine, template, options, locals
824
810
  end
825
811
 
826
812
  def render(engine, data, options = {}, locals = {}, &block)
827
813
  # merge app-level options
828
814
  engine_options = settings.respond_to?(engine) ? settings.send(engine) : {}
829
- options.merge!(engine_options) { |key, v1, v2| v1 }
815
+ options.merge!(engine_options) { |_key, v1, _v2| v1 }
830
816
 
831
817
  # extract generic options
832
818
  locals = options.delete(:locals) || locals || {}
833
- views = options.delete(:views) || settings.views || "./views"
819
+ views = options.delete(:views) || settings.views || './views'
834
820
  layout = options[:layout]
835
821
  layout = false if layout.nil? && options.include?(:layout)
836
822
  eat_errors = layout.nil?
837
- layout = engine_options[:layout] if layout.nil? or (layout == true && engine_options[:layout] != false)
838
- layout = @default_layout if layout.nil? or layout == true
823
+ layout = engine_options[:layout] if layout.nil? || (layout == true && engine_options[:layout] != false)
824
+ layout = @default_layout if layout.nil? || (layout == true)
839
825
  layout_options = options.delete(:layout_options) || {}
840
826
  content_type = options.delete(:default_content_type)
841
827
  content_type = options.delete(:content_type) || content_type
@@ -860,8 +846,9 @@ module Sinatra
860
846
 
861
847
  # render layout
862
848
  if layout
863
- options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope).
864
- merge!(layout_options)
849
+ extra_options = { views: views, layout: false, eat_errors: eat_errors, scope: scope }
850
+ options = options.merge(extra_options).merge!(layout_options)
851
+
865
852
  catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
866
853
  end
867
854
 
@@ -886,12 +873,13 @@ module Sinatra
886
873
  @preferred_extension = engine.to_s
887
874
  find_template(views, data, template) do |file|
888
875
  path ||= file # keep the initial path rather than the last one
889
- if found = File.exist?(file)
876
+ found = File.exist?(file)
877
+ if found
890
878
  path = file
891
879
  break
892
880
  end
893
881
  end
894
- throw :layout_missing if eat_errors and not found
882
+ throw :layout_missing if eat_errors && !found
895
883
  template.new(path, 1, options)
896
884
  end
897
885
  end
@@ -907,9 +895,11 @@ module Sinatra
907
895
  end
908
896
 
909
897
  def compile_block_template(template, options, &body)
910
- caller = settings.caller_locations.first
911
- path = options[:path] || caller[0]
912
- line = options[:line] || caller[1]
898
+ first_location = caller_locations.first
899
+ path = first_location.path
900
+ line = first_location.lineno
901
+ path = options[:path] || path
902
+ line = options[:line] || line
913
903
  template.new(path, line.to_i, options, &body)
914
904
  end
915
905
  end
@@ -925,7 +915,7 @@ module Sinatra
925
915
  attr_accessor :app, :env, :request, :response, :params
926
916
  attr_reader :template_cache
927
917
 
928
- def initialize(app = nil, **kwargs)
918
+ def initialize(app = nil, **_kwargs)
929
919
  super()
930
920
  @app = app
931
921
  @template_cache = Tilt::Cache.new
@@ -952,7 +942,7 @@ module Sinatra
952
942
  unless @response['Content-Type']
953
943
  if Array === body && body[0].respond_to?(:content_type)
954
944
  content_type body[0].content_type
955
- elsif default = settings.default_content_type
945
+ elsif (default = settings.default_content_type)
956
946
  content_type default
957
947
  end
958
948
  end
@@ -970,12 +960,6 @@ module Sinatra
970
960
  self.class.settings
971
961
  end
972
962
 
973
- def options
974
- warn "Sinatra::Base#options is deprecated and will be removed, " \
975
- "use #settings instead."
976
- settings
977
- end
978
-
979
963
  # Exit the current block, halts any further processing
980
964
  # of the request, and returns the specified response.
981
965
  def halt(*response)
@@ -992,7 +976,8 @@ module Sinatra
992
976
 
993
977
  # Forward the request to the downstream app -- middleware only.
994
978
  def forward
995
- fail "downstream app not set" unless @app.respond_to? :call
979
+ raise 'downstream app not set' unless @app.respond_to? :call
980
+
996
981
  status, headers, body = @app.call env
997
982
  @response.status = status
998
983
  @response.body = body
@@ -1014,18 +999,18 @@ module Sinatra
1014
999
 
1015
1000
  # Run routes defined on the class and all superclasses.
1016
1001
  def route!(base = settings, pass_block = nil)
1017
- if routes = base.routes[@request.request_method]
1018
- routes.each do |pattern, conditions, block|
1019
- response.delete_header('Content-Type') unless @pinned_response
1002
+ routes = base.routes[@request.request_method]
1020
1003
 
1021
- returned_pass_block = process_route(pattern, conditions) do |*args|
1022
- env['sinatra.route'] = "#{@request.request_method} #{pattern}"
1023
- route_eval { block[*args] }
1024
- end
1004
+ routes&.each do |pattern, conditions, block|
1005
+ response.delete_header('Content-Type') unless @pinned_response
1025
1006
 
1026
- # don't wipe out pass_block in superclass
1027
- pass_block = returned_pass_block if returned_pass_block
1007
+ returned_pass_block = process_route(pattern, conditions) do |*args|
1008
+ env['sinatra.route'] = "#{@request.request_method} #{pattern}"
1009
+ route_eval { block[*args] }
1028
1010
  end
1011
+
1012
+ # don't wipe out pass_block in superclass
1013
+ pass_block = returned_pass_block if returned_pass_block
1029
1014
  end
1030
1015
 
1031
1016
  # Run routes defined in superclass.
@@ -1049,15 +1034,17 @@ module Sinatra
1049
1034
  # Returns pass block.
1050
1035
  def process_route(pattern, conditions, block = nil, values = [])
1051
1036
  route = @request.path_info
1052
- route = '/' if route.empty? and not settings.empty_path_info?
1037
+ route = '/' if route.empty? && !settings.empty_path_info?
1053
1038
  route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/')
1054
- return unless params = pattern.params(route)
1055
1039
 
1056
- params.delete("ignore") # TODO: better params handling, maybe turn it into "smart" object or detect changes
1040
+ params = pattern.params(route)
1041
+ return unless params
1042
+
1043
+ params.delete('ignore') # TODO: better params handling, maybe turn it into "smart" object or detect changes
1057
1044
  force_encoding(params)
1058
- @params = @params.merge(params) if params.any?
1045
+ @params = @params.merge(params) { |_k, v1, v2| v2 || v1 } if params.any?
1059
1046
 
1060
- regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? {|subpattern| subpattern.is_a?(Mustermann::Regular)} )
1047
+ regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? { |subpattern| subpattern.is_a?(Mustermann::Regular) })
1061
1048
  if regexp_exists
1062
1049
  captures = pattern.match(route).captures.map { |c| URI_INSTANCE.unescape(c) if c }
1063
1050
  values += captures
@@ -1070,7 +1057,7 @@ module Sinatra
1070
1057
  conditions.each { |c| throw :pass if c.bind(self).call == false }
1071
1058
  block ? block[self, values] : yield(self, values)
1072
1059
  end
1073
- rescue
1060
+ rescue StandardError
1074
1061
  @env['sinatra.error.params'] = @params
1075
1062
  raise
1076
1063
  ensure
@@ -1084,35 +1071,35 @@ module Sinatra
1084
1071
  # a NotFound exception. Subclasses can override this method to perform
1085
1072
  # custom route miss logic.
1086
1073
  def route_missing
1087
- if @app
1088
- forward
1089
- else
1090
- raise NotFound, "#{request.request_method} #{request.path_info}"
1091
- end
1074
+ raise NotFound unless @app
1075
+
1076
+ forward
1092
1077
  end
1093
1078
 
1094
1079
  # Attempt to serve static files from public directory. Throws :halt when
1095
1080
  # a matching file is found, returns nil otherwise.
1096
1081
  def static!(options = {})
1097
1082
  return if (public_dir = settings.public_folder).nil?
1083
+
1098
1084
  path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}"
1099
1085
  return unless valid_path?(path)
1100
1086
 
1101
1087
  path = File.expand_path(path)
1102
- return unless path.start_with?(File.expand_path(public_dir) + '/')
1088
+ return unless path.start_with?("#{File.expand_path(public_dir)}/")
1089
+
1103
1090
  return unless File.file?(path)
1104
1091
 
1105
1092
  env['sinatra.static_file'] = path
1106
1093
  cache_control(*settings.static_cache_control) if settings.static_cache_control?
1107
- send_file path, options.merge(:disposition => nil)
1094
+ send_file path, options.merge(disposition: nil)
1108
1095
  end
1109
1096
 
1110
1097
  # Run the block with 'throw :halt' support and apply result to the response.
1111
- def invoke
1112
- res = catch(:halt) { yield }
1098
+ def invoke(&block)
1099
+ res = catch(:halt, &block)
1113
1100
 
1114
- res = [res] if Integer === res or String === res
1115
- if Array === res and Integer === res.first
1101
+ res = [res] if (Integer === res) || (String === res)
1102
+ if (Array === res) && (Integer === res.first)
1116
1103
  res = res.dup
1117
1104
  status(res.shift)
1118
1105
  body(res.pop)
@@ -1128,6 +1115,7 @@ module Sinatra
1128
1115
  # Avoid passing frozen string in force_encoding
1129
1116
  @params.merge!(@request.params).each do |key, val|
1130
1117
  next unless val.respond_to?(:force_encoding)
1118
+
1131
1119
  val = val.dup if val.frozen?
1132
1120
  @params[key] = force_encoding(val)
1133
1121
  end
@@ -1139,39 +1127,43 @@ module Sinatra
1139
1127
  end
1140
1128
  route!
1141
1129
  end
1142
- rescue ::Exception => boom
1143
- invoke { handle_exception!(boom) }
1130
+ rescue ::Exception => e
1131
+ invoke { handle_exception!(e) }
1144
1132
  ensure
1145
1133
  begin
1146
1134
  filter! :after unless env['sinatra.static_file']
1147
- rescue ::Exception => boom
1148
- invoke { handle_exception!(boom) } unless @env['sinatra.error']
1135
+ rescue ::Exception => e
1136
+ invoke { handle_exception!(e) } unless @env['sinatra.error']
1149
1137
  end
1150
1138
  end
1151
1139
 
1152
1140
  # Error handling during requests.
1153
1141
  def handle_exception!(boom)
1154
- if error_params = @env['sinatra.error.params']
1155
- @params = @params.merge(error_params)
1156
- end
1142
+ error_params = @env['sinatra.error.params']
1143
+
1144
+ @params = @params.merge(error_params) if error_params
1145
+
1157
1146
  @env['sinatra.error'] = boom
1158
1147
 
1159
- if boom.respond_to? :http_status and boom.http_status.between? 400, 599
1160
- status(boom.http_status)
1161
- elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599
1162
- status(boom.code)
1163
- else
1164
- status(500)
1165
- end
1148
+ http_status = if boom.is_a? Sinatra::Error
1149
+ if boom.respond_to? :http_status
1150
+ boom.http_status
1151
+ elsif settings.use_code? && boom.respond_to?(:code)
1152
+ boom.code
1153
+ end
1154
+ end
1155
+
1156
+ http_status = 500 unless http_status&.between?(400, 599)
1157
+ status(http_status)
1166
1158
 
1167
1159
  if server_error?
1168
1160
  dump_errors! boom if settings.dump_errors?
1169
- raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
1161
+ raise boom if settings.show_exceptions? && (settings.show_exceptions != :after_handler)
1170
1162
  elsif not_found?
1171
1163
  headers['X-Cascade'] = 'pass' if settings.x_cascade?
1172
1164
  end
1173
1165
 
1174
- if res = error_block!(boom.class, boom) || error_block!(status, boom)
1166
+ if (res = error_block!(boom.class, boom) || error_block!(status, boom))
1175
1167
  return res
1176
1168
  end
1177
1169
 
@@ -1180,12 +1172,14 @@ module Sinatra
1180
1172
  body Rack::Utils.escape_html(boom.message)
1181
1173
  else
1182
1174
  content_type 'text/html'
1183
- body '<h1>' + (not_found? ? 'Not Found' : 'Bad Request') + '</h1>'
1175
+ body "<h1>#{not_found? ? 'Not Found' : 'Bad Request'}</h1>"
1184
1176
  end
1185
1177
  end
1186
1178
 
1187
1179
  return unless server_error?
1188
- raise boom if settings.raise_errors? or settings.show_exceptions?
1180
+
1181
+ raise boom if settings.raise_errors? || settings.show_exceptions?
1182
+
1189
1183
  error_block! Exception, boom
1190
1184
  end
1191
1185
 
@@ -1193,7 +1187,10 @@ module Sinatra
1193
1187
  def error_block!(key, *block_params)
1194
1188
  base = settings
1195
1189
  while base.respond_to?(:errors)
1196
- next base = base.superclass unless args_array = base.errors[key]
1190
+ args_array = base.errors[key]
1191
+
1192
+ next base = base.superclass unless args_array
1193
+
1197
1194
  args_array.reverse_each do |args|
1198
1195
  first = args == args_array.first
1199
1196
  args += [block_params]
@@ -1201,32 +1198,26 @@ module Sinatra
1201
1198
  return resp unless resp.nil? && !first
1202
1199
  end
1203
1200
  end
1204
- return false unless key.respond_to? :superclass and key.superclass < Exception
1201
+ return false unless key.respond_to?(:superclass) && (key.superclass < Exception)
1202
+
1205
1203
  error_block!(key.superclass, *block_params)
1206
1204
  end
1207
1205
 
1208
1206
  def dump_errors!(boom)
1209
- msg = ["#{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1207
+ msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1210
1208
  @env['rack.errors'].puts(msg)
1211
1209
  end
1212
1210
 
1213
1211
  class << self
1214
1212
  CALLERS_TO_IGNORE = [ # :nodoc:
1215
- /\/sinatra(\/(base|main|show_exceptions))?\.rb$/, # all sinatra code
1216
- /lib\/tilt.*\.rb$/, # all tilt code
1213
+ %r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code
1214
+ %r{lib/tilt.*\.rb$}, # all tilt code
1217
1215
  /^\(.*\)$/, # generated code
1218
- /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
1216
+ %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1219
1217
  /active_support/, # active_support require hacks
1220
- /bundler(\/(?:runtime|inline))?\.rb/, # bundler require hacks
1221
- /<internal:/, # internal in ruby >= 1.9.2
1222
- /src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
1223
- ]
1224
-
1225
- # contrary to what the comment said previously, rubinius never supported this
1226
- if defined?(RUBY_IGNORE_CALLERS)
1227
- warn "RUBY_IGNORE_CALLERS is deprecated and will no longer be supported by Sinatra 2.0"
1228
- CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS)
1229
- end
1218
+ %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
1219
+ /<internal:/ # internal in ruby >= 1.9.2
1220
+ ].freeze
1230
1221
 
1231
1222
  attr_reader :routes, :filters, :templates, :errors
1232
1223
 
@@ -1235,17 +1226,17 @@ module Sinatra
1235
1226
  def reset!
1236
1227
  @conditions = []
1237
1228
  @routes = {}
1238
- @filters = {:before => [], :after => []}
1229
+ @filters = { before: [], after: [] }
1239
1230
  @errors = {}
1240
1231
  @middleware = []
1241
1232
  @prototype = nil
1242
1233
  @extensions = []
1243
1234
 
1244
- if superclass.respond_to?(:templates)
1245
- @templates = Hash.new { |hash, key| superclass.templates[key] }
1246
- else
1247
- @templates = {}
1248
- end
1235
+ @templates = if superclass.respond_to?(:templates)
1236
+ Hash.new { |_hash, key| superclass.templates[key] }
1237
+ else
1238
+ {}
1239
+ end
1249
1240
  end
1250
1241
 
1251
1242
  # Extension modules registered on this class and all superclasses.
@@ -1269,16 +1260,21 @@ module Sinatra
1269
1260
  # Sets an option to the given value. If the value is a proc,
1270
1261
  # the proc will be called every time the option is accessed.
1271
1262
  def set(option, value = (not_set = true), ignore_setter = false, &block)
1272
- raise ArgumentError if block and !not_set
1273
- value, not_set = block, false if block
1263
+ raise ArgumentError if block && !not_set
1264
+
1265
+ if block
1266
+ value = block
1267
+ not_set = false
1268
+ end
1274
1269
 
1275
1270
  if not_set
1276
1271
  raise ArgumentError unless option.respond_to?(:each)
1277
- option.each { |k,v| set(k, v) }
1272
+
1273
+ option.each { |k, v| set(k, v) }
1278
1274
  return self
1279
1275
  end
1280
1276
 
1281
- if respond_to?("#{option}=") and not ignore_setter
1277
+ if respond_to?("#{option}=") && !ignore_setter
1282
1278
  return __send__("#{option}=", value)
1283
1279
  end
1284
1280
 
@@ -1317,7 +1313,7 @@ module Sinatra
1317
1313
  # class, or an HTTP status code to specify which errors should be
1318
1314
  # handled.
1319
1315
  def error(*codes, &block)
1320
- args = compile! "ERROR", /.*/, block
1316
+ args = compile! 'ERROR', /.*/, block
1321
1317
  codes = codes.flat_map(&method(:Array))
1322
1318
  codes << Exception if codes.empty?
1323
1319
  codes << Sinatra::NotFound if codes.include?(404)
@@ -1343,7 +1339,7 @@ module Sinatra
1343
1339
  # Load embedded templates from the file; uses the caller's __FILE__
1344
1340
  # when no file is specified.
1345
1341
  def inline_templates=(file = nil)
1346
- file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file
1342
+ file = (caller_files.first || File.expand_path($0)) if file.nil? || file == true
1347
1343
 
1348
1344
  begin
1349
1345
  io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
@@ -1352,23 +1348,24 @@ module Sinatra
1352
1348
  app, data = nil
1353
1349
  end
1354
1350
 
1355
- if data
1356
- if app and app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
1357
- encoding = $2
1358
- else
1359
- encoding = settings.default_encoding
1360
- end
1361
- lines = app.count("\n") + 1
1362
- template = nil
1363
- force_encoding data, encoding
1364
- data.each_line do |line|
1365
- lines += 1
1366
- if line =~ /^@@\s*(.*\S)\s*$/
1367
- template = force_encoding(String.new, encoding)
1368
- templates[$1.to_sym] = [template, file, lines]
1369
- elsif template
1370
- template << line
1371
- end
1351
+ return unless data
1352
+
1353
+ encoding = if app && app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
1354
+ $2
1355
+ else
1356
+ settings.default_encoding
1357
+ end
1358
+
1359
+ lines = app.count("\n") + 1
1360
+ template = nil
1361
+ force_encoding data, encoding
1362
+ data.each_line do |line|
1363
+ lines += 1
1364
+ if line =~ /^@@\s*(.*\S)\s*$/
1365
+ template = force_encoding(String.new, encoding)
1366
+ templates[$1.to_sym] = [template, file, lines]
1367
+ elsif template
1368
+ template << line
1372
1369
  end
1373
1370
  end
1374
1371
  end
@@ -1377,8 +1374,10 @@ module Sinatra
1377
1374
  def mime_type(type, value = nil)
1378
1375
  return type if type.nil?
1379
1376
  return type.to_s if type.to_s.include?('/')
1380
- type = ".#{type}" unless type.to_s[0] == ?.
1377
+
1378
+ type = ".#{type}" unless type.to_s[0] == '.'
1381
1379
  return Rack::Mime.mime_type(type, nil) unless value
1380
+
1382
1381
  Rack::Mime::MIME_TYPES[type] = value
1383
1382
  end
1384
1383
 
@@ -1387,7 +1386,7 @@ module Sinatra
1387
1386
  # mime_types :js # => ['application/javascript', 'text/javascript']
1388
1387
  def mime_types(type)
1389
1388
  type = mime_type type
1390
- type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
1389
+ type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
1391
1390
  end
1392
1391
 
1393
1392
  # Define a before filter; runs before all requests within the same
@@ -1416,7 +1415,7 @@ module Sinatra
1416
1415
  end
1417
1416
 
1418
1417
  def public=(value)
1419
- warn ":public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead"
1418
+ warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
1420
1419
  set(:public_folder, value)
1421
1420
  end
1422
1421
 
@@ -1438,14 +1437,21 @@ module Sinatra
1438
1437
  route('HEAD', path, opts, &block)
1439
1438
  end
1440
1439
 
1441
- def put(path, opts = {}, &bk) route 'PUT', path, opts, &bk end
1442
- def post(path, opts = {}, &bk) route 'POST', path, opts, &bk end
1443
- def delete(path, opts = {}, &bk) route 'DELETE', path, opts, &bk end
1444
- def head(path, opts = {}, &bk) route 'HEAD', path, opts, &bk end
1445
- def options(path, opts = {}, &bk) route 'OPTIONS', path, opts, &bk end
1446
- def patch(path, opts = {}, &bk) route 'PATCH', path, opts, &bk end
1447
- def link(path, opts = {}, &bk) route 'LINK', path, opts, &bk end
1448
- def unlink(path, opts = {}, &bk) route 'UNLINK', path, opts, &bk end
1440
+ def put(path, opts = {}, &block) route 'PUT', path, opts, &block end
1441
+
1442
+ def post(path, opts = {}, &block) route 'POST', path, opts, &block end
1443
+
1444
+ def delete(path, opts = {}, &block) route 'DELETE', path, opts, &block end
1445
+
1446
+ def head(path, opts = {}, &block) route 'HEAD', path, opts, &block end
1447
+
1448
+ def options(path, opts = {}, &block) route 'OPTIONS', path, opts, &block end
1449
+
1450
+ def patch(path, opts = {}, &block) route 'PATCH', path, opts, &block end
1451
+
1452
+ def link(path, opts = {}, &block) route 'LINK', path, opts, &block end
1453
+
1454
+ def unlink(path, opts = {}, &block) route 'UNLINK', path, opts, &block end
1449
1455
 
1450
1456
  # Makes the methods defined in the block and in the Modules given
1451
1457
  # in `extensions` available to the handlers and templates
@@ -1485,37 +1491,39 @@ module Sinatra
1485
1491
  # Stop the self-hosted server if running.
1486
1492
  def quit!
1487
1493
  return unless running?
1494
+
1488
1495
  # Use Thin's hard #stop! if available, otherwise just #stop.
1489
1496
  running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
1490
- $stderr.puts "== Sinatra has ended his set (crowd applauds)" unless suppress_messages?
1497
+ warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
1491
1498
  set :running_server, nil
1492
1499
  set :handler_name, nil
1493
1500
  end
1494
1501
 
1495
- alias_method :stop!, :quit!
1502
+ alias stop! quit!
1496
1503
 
1497
1504
  # Run the Sinatra app as a self-hosted server using
1498
- # Puma, Mongrel, or WEBrick (in that order). If given a block, will call
1505
+ # Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call
1499
1506
  # with the constructed handler once we have taken the stage.
1500
1507
  def run!(options = {}, &block)
1501
1508
  return if running?
1509
+
1502
1510
  set options
1503
1511
  handler = Rack::Handler.pick(server)
1504
1512
  handler_name = handler.name.gsub(/.*::/, '')
1505
1513
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
1506
- server_settings.merge!(:Port => port, :Host => bind)
1514
+ server_settings.merge!(Port: port, Host: bind)
1507
1515
 
1508
1516
  begin
1509
1517
  start_server(handler, server_settings, handler_name, &block)
1510
1518
  rescue Errno::EADDRINUSE
1511
- $stderr.puts "== Someone is already performing on port #{port}!"
1519
+ warn "== Someone is already performing on port #{port}!"
1512
1520
  raise
1513
1521
  ensure
1514
1522
  quit!
1515
1523
  end
1516
1524
  end
1517
1525
 
1518
- alias_method :start!, :run!
1526
+ alias start! run!
1519
1527
 
1520
1528
  # Check whether the self-hosted server is running or not.
1521
1529
  def running?
@@ -1533,10 +1541,11 @@ module Sinatra
1533
1541
  # Create a new instance of the class fronted by its middleware
1534
1542
  # pipeline. The object is guaranteed to respond to #call but may not be
1535
1543
  # an instance of the class new was called on.
1536
- def new(*args, **kwargs, &bk)
1537
- instance = new!(*args, **kwargs, &bk)
1544
+ def new(*args, &block)
1545
+ instance = new!(*args, &block)
1538
1546
  Wrapper.new(build(instance).to_app, instance)
1539
1547
  end
1548
+ ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
1540
1549
 
1541
1550
  # Creates a Rack::Builder instance with all the middleware set up and
1542
1551
  # the given +app+ as end point.
@@ -1558,12 +1567,6 @@ module Sinatra
1558
1567
  cleaned_caller(1).flatten
1559
1568
  end
1560
1569
 
1561
- # Like caller_files, but containing Arrays rather than strings with the
1562
- # first element being the file, and the second being the line.
1563
- def caller_locations
1564
- cleaned_caller 2
1565
- end
1566
-
1567
1570
  private
1568
1571
 
1569
1572
  # Starts the server by running the Rack Handler.
@@ -1574,7 +1577,7 @@ module Sinatra
1574
1577
  # Run the instance we created:
1575
1578
  handler.run(self, **server_settings) do |server|
1576
1579
  unless suppress_messages?
1577
- $stderr.puts "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
1580
+ warn "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
1578
1581
  end
1579
1582
 
1580
1583
  setup_traps
@@ -1591,18 +1594,18 @@ module Sinatra
1591
1594
  end
1592
1595
 
1593
1596
  def setup_traps
1594
- if traps?
1595
- at_exit { quit! }
1597
+ return unless traps?
1596
1598
 
1597
- [:INT, :TERM].each do |signal|
1598
- old_handler = trap(signal) do
1599
- quit!
1600
- old_handler.call if old_handler.respond_to?(:call)
1601
- end
1602
- end
1599
+ at_exit { quit! }
1603
1600
 
1604
- set :traps, false
1601
+ %i[INT TERM].each do |signal|
1602
+ old_handler = trap(signal) do
1603
+ quit!
1604
+ old_handler.call if old_handler.respond_to?(:call)
1605
+ end
1605
1606
  end
1607
+
1608
+ set :traps, false
1606
1609
  end
1607
1610
 
1608
1611
  # Dynamically defines a method on settings.
@@ -1630,18 +1633,21 @@ module Sinatra
1630
1633
  end
1631
1634
  end
1632
1635
  end
1633
- alias_method :agent, :user_agent
1636
+ alias agent user_agent
1634
1637
 
1635
1638
  # Condition for matching mimetypes. Accepts file extensions.
1636
1639
  def provides(*types)
1637
1640
  types.map! { |t| mime_types(t) }
1638
1641
  types.flatten!
1639
1642
  condition do
1640
- if type = response['Content-Type']
1641
- types.include? type or types.include? type[/^[^;]+/]
1642
- elsif type = request.preferred_type(types)
1643
- params = (type.respond_to?(:params) ? type.params : {})
1644
- content_type(type, params)
1643
+ response_content_type = response['Content-Type']
1644
+ preferred_type = request.preferred_type(types)
1645
+
1646
+ if response_content_type
1647
+ types.include?(response_content_type) || types.include?(response_content_type[/^[^;]+/])
1648
+ elsif preferred_type
1649
+ params = (preferred_type.respond_to?(:params) ? preferred_type.params : {})
1650
+ content_type(preferred_type, params)
1645
1651
  true
1646
1652
  else
1647
1653
  false
@@ -1650,7 +1656,7 @@ module Sinatra
1650
1656
  end
1651
1657
 
1652
1658
  def route(verb, path, options = {}, &block)
1653
- enable :empty_path_info if path == "" and empty_path_info.nil?
1659
+ enable :empty_path_info if path == '' && empty_path_info.nil?
1654
1660
  signature = compile!(verb, path, block, **options)
1655
1661
  (@routes[verb] ||= []) << signature
1656
1662
  invoke_hook(:route_added, verb, path, block)
@@ -1679,12 +1685,13 @@ module Sinatra
1679
1685
  pattern = compile(path, route_mustermann_opts)
1680
1686
  method_name = "#{verb} #{path}"
1681
1687
  unbound_method = generate_method(method_name, &block)
1682
- conditions, @conditions = @conditions, []
1683
- wrapper = block.arity != 0 ?
1684
- proc { |a, p| unbound_method.bind(a).call(*p) } :
1685
- proc { |a, p| unbound_method.bind(a).call }
1688
+ conditions = @conditions
1689
+ @conditions = []
1690
+ wrapper = block.arity.zero? ?
1691
+ proc { |a, _p| unbound_method.bind(a).call } :
1692
+ proc { |a, p| unbound_method.bind(a).call(*p) }
1686
1693
 
1687
- [ pattern, conditions, wrapper ]
1694
+ [pattern, conditions, wrapper]
1688
1695
  end
1689
1696
 
1690
1697
  def compile(path, route_mustermann_opts = {})
@@ -1702,7 +1709,7 @@ module Sinatra
1702
1709
  end
1703
1710
 
1704
1711
  def setup_middleware(builder)
1705
- middleware.each { |c,a,b| builder.use(c, *a, &b) }
1712
+ middleware.each { |c, a, b| builder.use(c, *a, &b) }
1706
1713
  end
1707
1714
 
1708
1715
  def setup_logging(builder)
@@ -1732,9 +1739,10 @@ module Sinatra
1732
1739
 
1733
1740
  def setup_protection(builder)
1734
1741
  return unless protection?
1742
+
1735
1743
  options = Hash === protection ? protection.dup : {}
1736
1744
  options = {
1737
- img_src: "'self' data:",
1745
+ img_src: "'self' data:",
1738
1746
  font_src: "'self'"
1739
1747
  }.merge options
1740
1748
 
@@ -1748,6 +1756,7 @@ module Sinatra
1748
1756
 
1749
1757
  def setup_sessions(builder)
1750
1758
  return unless sessions?
1759
+
1751
1760
  options = {}
1752
1761
  options[:secret] = session_secret if session_secret?
1753
1762
  options.merge! sessions.to_hash if sessions.respond_to? :to_hash
@@ -1770,15 +1779,15 @@ module Sinatra
1770
1779
  end
1771
1780
 
1772
1781
  # used for deprecation warnings
1773
- def warn(message)
1774
- super message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1782
+ def warn_for_deprecation(message)
1783
+ warn message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1775
1784
  end
1776
1785
 
1777
1786
  # Like Kernel#caller but excluding certain magic entries
1778
1787
  def cleaned_caller(keep = 3)
1779
- caller(1).
1780
- map! { |line| line.split(/:(?=\d|in )/, 3)[0,keep] }.
1781
- reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1788
+ caller(1)
1789
+ .map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] }
1790
+ .reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1782
1791
  end
1783
1792
  end
1784
1793
 
@@ -1786,6 +1795,7 @@ module Sinatra
1786
1795
  # which is UTF-8 by default
1787
1796
  def self.force_encoding(data, encoding = default_encoding)
1788
1797
  return if data == settings || data.is_a?(Tempfile)
1798
+
1789
1799
  if data.respond_to? :force_encoding
1790
1800
  data.force_encoding(encoding).encode!
1791
1801
  elsif data.respond_to? :each_value
@@ -1796,24 +1806,26 @@ module Sinatra
1796
1806
  data
1797
1807
  end
1798
1808
 
1799
- def force_encoding(*args) settings.force_encoding(*args) end
1809
+ def force_encoding(*args)
1810
+ settings.force_encoding(*args)
1811
+ end
1800
1812
 
1801
1813
  reset!
1802
1814
 
1803
1815
  set :environment, (ENV['APP_ENV'] || ENV['RACK_ENV'] || :development).to_sym
1804
- set :raise_errors, Proc.new { test? }
1805
- set :dump_errors, Proc.new { !test? }
1806
- set :show_exceptions, Proc.new { development? }
1816
+ set :raise_errors, proc { test? }
1817
+ set :dump_errors, proc { !test? }
1818
+ set :show_exceptions, proc { development? }
1807
1819
  set :sessions, false
1808
- set :session_store, Rack::Session::Cookie
1820
+ set :session_store, Rack::Protection::EncryptedCookie
1809
1821
  set :logging, false
1810
1822
  set :protection, true
1811
1823
  set :method_override, false
1812
1824
  set :use_code, false
1813
- set :default_encoding, "utf-8"
1825
+ set :default_encoding, 'utf-8'
1814
1826
  set :x_cascade, true
1815
1827
  set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
1816
- settings.add_charset << /^text\//
1828
+ settings.add_charset << %r{^text/}
1817
1829
  set :mustermann_opts, {}
1818
1830
  set :default_content_type, 'text/html'
1819
1831
 
@@ -1823,12 +1835,12 @@ module Sinatra
1823
1835
  set :session_secret, SecureRandom.hex(64)
1824
1836
  rescue LoadError, NotImplementedError
1825
1837
  # SecureRandom raises a NotImplementedError if no random device is available
1826
- set :session_secret, "%064x" % Kernel.rand(2**256-1)
1838
+ set :session_secret, format('%064x', Kernel.rand((2**256) - 1))
1827
1839
  end
1828
1840
 
1829
1841
  class << self
1830
- alias_method :methodoverride?, :method_override?
1831
- alias_method :methodoverride=, :method_override=
1842
+ alias methodoverride? method_override?
1843
+ alias methodoverride= method_override=
1832
1844
  end
1833
1845
 
1834
1846
  set :run, false # start server via at-exit hook?
@@ -1836,21 +1848,17 @@ module Sinatra
1836
1848
  set :handler_name, nil
1837
1849
  set :traps, true
1838
1850
  set :server, %w[HTTP webrick]
1839
- set :bind, Proc.new { development? ? 'localhost' : '0.0.0.0' }
1851
+ set :bind, proc { development? ? 'localhost' : '0.0.0.0' }
1840
1852
  set :port, Integer(ENV['PORT'] && !ENV['PORT'].empty? ? ENV['PORT'] : 4567)
1841
1853
  set :quiet, false
1842
1854
 
1843
1855
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1844
1856
 
1845
- if ruby_engine == 'macruby'
1846
- server.unshift 'control_tower'
1847
- else
1848
- server.unshift 'reel'
1849
- server.unshift 'puma'
1850
- server.unshift 'mongrel' if ruby_engine.nil?
1851
- server.unshift 'thin' if ruby_engine != 'jruby'
1852
- server.unshift 'trinidad' if ruby_engine == 'jruby'
1853
- end
1857
+ server.unshift 'puma'
1858
+ server.unshift 'falcon' if ruby_engine != 'jruby'
1859
+ server.unshift 'mongrel' if ruby_engine.nil?
1860
+ server.unshift 'thin' if ruby_engine != 'jruby'
1861
+ server.unshift 'trinidad' if ruby_engine == 'jruby'
1854
1862
 
1855
1863
  set :absolute_redirects, true
1856
1864
  set :prefixed_redirects, false
@@ -1858,14 +1866,14 @@ module Sinatra
1858
1866
  set :strict_paths, true
1859
1867
 
1860
1868
  set :app_file, nil
1861
- set :root, Proc.new { app_file && File.expand_path(File.dirname(app_file)) }
1862
- set :views, Proc.new { root && File.join(root, 'views') }
1863
- set :reload_templates, Proc.new { development? }
1869
+ set :root, proc { app_file && File.expand_path(File.dirname(app_file)) }
1870
+ set :views, proc { root && File.join(root, 'views') }
1871
+ set :reload_templates, proc { development? }
1864
1872
  set :lock, false
1865
1873
  set :threaded, true
1866
1874
 
1867
- set :public_folder, Proc.new { root && File.join(root, 'public') }
1868
- set :static, Proc.new { public_folder && File.exist?(public_folder) }
1875
+ set :public_folder, proc { root && File.join(root, 'public') }
1876
+ set :static, proc { public_folder && File.exist?(public_folder) }
1869
1877
  set :static_cache_control, false
1870
1878
 
1871
1879
  error ::Exception do
@@ -1884,7 +1892,7 @@ module Sinatra
1884
1892
  error NotFound do
1885
1893
  content_type 'text/html'
1886
1894
 
1887
- if self.class == Sinatra::Application
1895
+ if instance_of?(Sinatra::Application)
1888
1896
  code = <<-RUBY.gsub(/^ {12}/, '')
1889
1897
  #{request.request_method.downcase} '#{request.path_info}' do
1890
1898
  "Hello World"
@@ -1899,11 +1907,11 @@ module Sinatra
1899
1907
  end
1900
1908
  RUBY
1901
1909
 
1902
- file = settings.app_file.to_s.sub(settings.root.to_s, '').sub(/^\//, '')
1910
+ file = settings.app_file.to_s.sub(settings.root.to_s, '').sub(%r{^/}, '')
1903
1911
  code = "# in #{file}\n#{code}" unless file.empty?
1904
1912
  end
1905
1913
 
1906
- (<<-HTML).gsub(/^ {10}/, '')
1914
+ <<-HTML.gsub(/^ {10}/, '')
1907
1915
  <!DOCTYPE html>
1908
1916
  <html>
1909
1917
  <head>
@@ -1915,7 +1923,7 @@ module Sinatra
1915
1923
  </head>
1916
1924
  <body>
1917
1925
  <h2>Sinatra doesn’t know this ditty.</h2>
1918
- <img src='#{uri "/__sinatra__/404.png"}'>
1926
+ <img src='#{uri '/__sinatra__/404.png'}'>
1919
1927
  <div id="c">
1920
1928
  Try this:
1921
1929
  <pre>#{Rack::Utils.escape_html(code)}</pre>
@@ -1935,12 +1943,12 @@ module Sinatra
1935
1943
  # top-level. Subclassing Sinatra::Base is highly recommended for
1936
1944
  # modular applications.
1937
1945
  class Application < Base
1938
- set :logging, Proc.new { !test? }
1946
+ set :logging, proc { !test? }
1939
1947
  set :method_override, true
1940
- set :run, Proc.new { !test? }
1948
+ set :run, proc { !test? }
1941
1949
  set :app_file, nil
1942
1950
 
1943
- def self.register(*extensions, &block) #:nodoc:
1951
+ def self.register(*extensions, &block) # :nodoc:
1944
1952
  added_methods = extensions.flat_map(&:public_instance_methods)
1945
1953
  Delegator.delegate(*added_methods)
1946
1954
  super(*extensions, &block)
@@ -1950,11 +1958,12 @@ module Sinatra
1950
1958
  # Sinatra delegation mixin. Mixing this module into an object causes all
1951
1959
  # methods to be delegated to the Sinatra::Application class. Used primarily
1952
1960
  # at the top-level.
1953
- module Delegator #:nodoc:
1961
+ module Delegator # :nodoc:
1954
1962
  def self.delegate(*methods)
1955
1963
  methods.each do |method_name|
1956
1964
  define_method(method_name) do |*args, &block|
1957
1965
  return super(*args, &block) if respond_to? method_name
1966
+
1958
1967
  Delegator.target.send(method_name, *args, &block)
1959
1968
  end
1960
1969
  # ensure keyword argument passing is compatible with ruby >= 2.7
@@ -1977,7 +1986,8 @@ module Sinatra
1977
1986
 
1978
1987
  class Wrapper
1979
1988
  def initialize(stack, instance)
1980
- @stack, @instance = stack, instance
1989
+ @stack = stack
1990
+ @instance = instance
1981
1991
  end
1982
1992
 
1983
1993
  def settings