sinatra 2.2.0 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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