sinatra 2.2.0 → 3.0.2

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

Potentially problematic release.


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

data/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'
@@ -385,23 +400,23 @@ module Sinatra
385
400
  # instructing the user agents to prompt to save.
386
401
  def attachment(filename = nil, disposition = :attachment)
387
402
  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
403
+ return unless filename
404
+
405
+ params = format('; filename="%s"', File.basename(filename))
406
+ response['Content-Disposition'] << params
407
+ ext = File.extname(filename)
408
+ content_type(ext) unless response['Content-Type'] || ext.empty?
394
409
  end
395
410
 
396
411
  # Use the contents of the file at +path+ as the response body.
397
412
  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'
413
+ if opts[:type] || !response['Content-Type']
414
+ content_type opts[:type] || File.extname(path), default: 'application/octet-stream'
400
415
  end
401
416
 
402
417
  disposition = opts[:disposition]
403
418
  filename = opts[:filename]
404
- disposition = :attachment if disposition.nil? and filename
419
+ disposition = :attachment if disposition.nil? && filename
405
420
  filename = path if filename.nil?
406
421
  attachment(filename, disposition) if disposition
407
422
 
@@ -410,7 +425,7 @@ module Sinatra
410
425
  file = Rack::File.new(File.dirname(settings.app_file))
411
426
  result = file.serving(request, path)
412
427
 
413
- result[1].each { |k,v| headers[k] ||= v }
428
+ result[1].each { |k, v| headers[k] ||= v }
414
429
  headers['Content-Length'] = result[1]['Content-Length']
415
430
  opts[:status] &&= Integer(opts[:status])
416
431
  halt (opts[:status] || result[0]), result[2]
@@ -431,12 +446,16 @@ module Sinatra
431
446
  def self.defer(*) yield end
432
447
 
433
448
  def initialize(scheduler = self.class, keep_open = false, &back)
434
- @back, @scheduler, @keep_open = back.to_proc, scheduler, keep_open
435
- @callbacks, @closed = [], false
449
+ @back = back.to_proc
450
+ @scheduler = scheduler
451
+ @keep_open = keep_open
452
+ @callbacks = []
453
+ @closed = false
436
454
  end
437
455
 
438
456
  def close
439
457
  return if closed?
458
+
440
459
  @closed = true
441
460
  @scheduler.schedule { @callbacks.each { |c| c.call } }
442
461
  end
@@ -460,6 +479,7 @@ module Sinatra
460
479
 
461
480
  def callback(&block)
462
481
  return yield if closed?
482
+
463
483
  @callbacks << block
464
484
  end
465
485
 
@@ -493,18 +513,18 @@ module Sinatra
493
513
  # See RFC 2616 / 14.9 for more on standard cache control directives:
494
514
  # http://tools.ietf.org/html/rfc2616#section-14.9.1
495
515
  def cache_control(*values)
496
- if values.last.kind_of?(Hash)
516
+ if values.last.is_a?(Hash)
497
517
  hash = values.pop
498
- hash.reject! { |k, v| v == false }
518
+ hash.reject! { |_k, v| v == false }
499
519
  hash.reject! { |k, v| values << k if v == true }
500
520
  else
501
521
  hash = {}
502
522
  end
503
523
 
504
- values.map! { |value| value.to_s.tr('_','-') }
524
+ values.map! { |value| value.to_s.tr('_', '-') }
505
525
  hash.each do |key, value|
506
526
  key = key.to_s.tr('_', '-')
507
- value = value.to_i if ['max-age', 's-maxage'].include? key
527
+ value = value.to_i if %w[max-age s-maxage].include? key
508
528
  values << "#{key}=#{value}"
509
529
  end
510
530
 
@@ -521,7 +541,7 @@ module Sinatra
521
541
  # => Expires: Mon, 08 Jun 2009 08:50:17 GMT
522
542
  #
523
543
  def expires(amount, *values)
524
- values << {} unless values.last.kind_of?(Hash)
544
+ values << {} unless values.last.is_a?(Hash)
525
545
 
526
546
  if amount.is_a? Integer
527
547
  time = Time.now + amount.to_i
@@ -531,7 +551,7 @@ module Sinatra
531
551
  max_age = time - Time.now
532
552
  end
533
553
 
534
- values.last.merge!(:max_age => max_age)
554
+ values.last.merge!(max_age: max_age) { |_key, v1, v2| v1 || v2 }
535
555
  cache_control(*values)
536
556
 
537
557
  response['Expires'] = time.httpdate
@@ -546,17 +566,18 @@ module Sinatra
546
566
  # with a '304 Not Modified' response.
547
567
  def last_modified(time)
548
568
  return unless time
569
+
549
570
  time = time_for time
550
571
  response['Last-Modified'] = time.httpdate
551
572
  return if env['HTTP_IF_NONE_MATCH']
552
573
 
553
- if status == 200 and env['HTTP_IF_MODIFIED_SINCE']
574
+ if (status == 200) && env['HTTP_IF_MODIFIED_SINCE']
554
575
  # compare based on seconds since epoch
555
576
  since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i
556
577
  halt 304 if since >= time.to_i
557
578
  end
558
579
 
559
- if (success? or status == 412) and env['HTTP_IF_UNMODIFIED_SINCE']
580
+ if (success? || (status == 412)) && env['HTTP_IF_UNMODIFIED_SINCE']
560
581
  # compare based on seconds since epoch
561
582
  since = Time.httpdate(env['HTTP_IF_UNMODIFIED_SINCE']).to_i
562
583
  halt 412 if since < time.to_i
@@ -564,7 +585,7 @@ module Sinatra
564
585
  rescue ArgumentError
565
586
  end
566
587
 
567
- ETAG_KINDS = [:strong, :weak]
588
+ ETAG_KINDS = %i[strong weak].freeze
568
589
  # Set the response entity tag (HTTP 'ETag' header) and halt if conditional
569
590
  # GET matches. The +value+ argument is an identifier that uniquely
570
591
  # identifies the current version of the resource. The +kind+ argument
@@ -576,27 +597,31 @@ module Sinatra
576
597
  # GET or HEAD, a '304 Not Modified' response is sent.
577
598
  def etag(value, options = {})
578
599
  # Before touching this code, please double check RFC 2616 14.24 and 14.26.
579
- options = {:kind => options} unless Hash === options
600
+ options = { kind: options } unless Hash === options
580
601
  kind = options[:kind] || :strong
581
602
  new_resource = options.fetch(:new_resource) { request.post? }
582
603
 
583
604
  unless ETAG_KINDS.include?(kind)
584
- raise ArgumentError, ":strong or :weak expected"
605
+ raise ArgumentError, ':strong or :weak expected'
585
606
  end
586
607
 
587
- value = '"%s"' % value
608
+ value = format('"%s"', value)
588
609
  value = "W/#{value}" if kind == :weak
589
610
  response['ETag'] = value
590
611
 
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
612
+ return unless success? || status == 304
595
613
 
596
- if env['HTTP_IF_MATCH']
597
- halt 412 unless etag_matches? env['HTTP_IF_MATCH'], new_resource
598
- end
614
+ if etag_matches?(env['HTTP_IF_NONE_MATCH'], new_resource)
615
+ halt(request.safe? ? 304 : 412)
599
616
  end
617
+
618
+ if env['HTTP_IF_MATCH']
619
+ return if etag_matches?(env['HTTP_IF_MATCH'], new_resource)
620
+
621
+ halt 412
622
+ end
623
+
624
+ nil
600
625
  end
601
626
 
602
627
  # Sugar for redirect (example: redirect back)
@@ -649,8 +674,8 @@ module Sinatra
649
674
  else
650
675
  value.to_time
651
676
  end
652
- rescue ArgumentError => boom
653
- raise boom
677
+ rescue ArgumentError => e
678
+ raise e
654
679
  rescue Exception
655
680
  raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
656
681
  end
@@ -660,11 +685,13 @@ module Sinatra
660
685
  # Helper method checking if a ETag value list includes the current ETag.
661
686
  def etag_matches?(list, new_resource = request.post?)
662
687
  return !new_resource if list == '*'
688
+
663
689
  list.to_s.split(/\s*,\s*/).include? response['ETag']
664
690
  end
665
691
 
666
692
  def with_params(temp_params)
667
- original, @params = @params, temp_params
693
+ original = @params
694
+ @params = temp_params
668
695
  yield
669
696
  ensure
670
697
  @params = original if original
@@ -682,7 +709,7 @@ module Sinatra
682
709
  # Possible options are:
683
710
  # :content_type The content type to use, same arguments as content_type.
684
711
  # :layout If set to something falsy, no layout is rendered, otherwise
685
- # the specified layout is used (Ignored for `sass` and `less`)
712
+ # the specified layout is used
686
713
  # :layout_engine Engine to use for rendering the layout.
687
714
  # :locals A hash with local variables that should be available
688
715
  # in the template
@@ -704,36 +731,10 @@ module Sinatra
704
731
  render(:erb, template, options, locals, &block)
705
732
  end
706
733
 
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
734
  def haml(template, options = {}, locals = {}, &block)
714
735
  render(:haml, template, options, locals, &block)
715
736
  end
716
737
 
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
738
  def builder(template = nil, options = {}, locals = {}, &block)
738
739
  options[:default_content_type] = :xml
739
740
  render_ruby(:builder, template, options, locals, &block)
@@ -748,10 +749,6 @@ module Sinatra
748
749
  render :markdown, template, options, locals
749
750
  end
750
751
 
751
- def textile(template, options = {}, locals = {})
752
- render :textile, template, options, locals
753
- end
754
-
755
752
  def rdoc(template, options = {}, locals = {})
756
753
  render :rdoc, template, options, locals
757
754
  end
@@ -760,19 +757,10 @@ module Sinatra
760
757
  render :asciidoc, template, options, locals
761
758
  end
762
759
 
763
- def radius(template, options = {}, locals = {})
764
- render :radius, template, options, locals
765
- end
766
-
767
760
  def markaby(template = nil, options = {}, locals = {}, &block)
768
761
  render_ruby(:mab, template, options, locals, &block)
769
762
  end
770
763
 
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
764
  def nokogiri(template = nil, options = {}, locals = {}, &block)
777
765
  options[:default_content_type] = :xml
778
766
  render_ruby(:nokogiri, template, options, locals, &block)
@@ -782,18 +770,6 @@ module Sinatra
782
770
  render(:slim, template, options, locals, &block)
783
771
  end
784
772
 
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
773
  def yajl(template, options = {}, locals = {})
798
774
  options[:default_content_type] = :json
799
775
  render :yajl, template, options, locals
@@ -818,24 +794,27 @@ module Sinatra
818
794
 
819
795
  # logic shared between builder and nokogiri
820
796
  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?
797
+ if template.is_a?(Hash)
798
+ options = template
799
+ template = nil
800
+ end
801
+ template = proc { block } if template.nil?
823
802
  render engine, template, options, locals
824
803
  end
825
804
 
826
805
  def render(engine, data, options = {}, locals = {}, &block)
827
806
  # merge app-level options
828
807
  engine_options = settings.respond_to?(engine) ? settings.send(engine) : {}
829
- options.merge!(engine_options) { |key, v1, v2| v1 }
808
+ options.merge!(engine_options) { |_key, v1, _v2| v1 }
830
809
 
831
810
  # extract generic options
832
811
  locals = options.delete(:locals) || locals || {}
833
- views = options.delete(:views) || settings.views || "./views"
812
+ views = options.delete(:views) || settings.views || './views'
834
813
  layout = options[:layout]
835
814
  layout = false if layout.nil? && options.include?(:layout)
836
815
  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
816
+ layout = engine_options[:layout] if layout.nil? || (layout == true && engine_options[:layout] != false)
817
+ layout = @default_layout if layout.nil? || (layout == true)
839
818
  layout_options = options.delete(:layout_options) || {}
840
819
  content_type = options.delete(:default_content_type)
841
820
  content_type = options.delete(:content_type) || content_type
@@ -860,8 +839,9 @@ module Sinatra
860
839
 
861
840
  # render layout
862
841
  if layout
863
- options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope).
864
- merge!(layout_options)
842
+ extra_options = { views: views, layout: false, eat_errors: eat_errors, scope: scope }
843
+ options = options.merge(extra_options).merge!(layout_options)
844
+
865
845
  catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
866
846
  end
867
847
 
@@ -886,12 +866,13 @@ module Sinatra
886
866
  @preferred_extension = engine.to_s
887
867
  find_template(views, data, template) do |file|
888
868
  path ||= file # keep the initial path rather than the last one
889
- if found = File.exist?(file)
869
+ found = File.exist?(file)
870
+ if found
890
871
  path = file
891
872
  break
892
873
  end
893
874
  end
894
- throw :layout_missing if eat_errors and not found
875
+ throw :layout_missing if eat_errors && !found
895
876
  template.new(path, 1, options)
896
877
  end
897
878
  end
@@ -907,9 +888,11 @@ module Sinatra
907
888
  end
908
889
 
909
890
  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]
891
+ first_location = caller_locations.first
892
+ path = first_location.path
893
+ line = first_location.lineno
894
+ path = options[:path] || path
895
+ line = options[:line] || line
913
896
  template.new(path, line.to_i, options, &body)
914
897
  end
915
898
  end
@@ -925,7 +908,7 @@ module Sinatra
925
908
  attr_accessor :app, :env, :request, :response, :params
926
909
  attr_reader :template_cache
927
910
 
928
- def initialize(app = nil, **kwargs)
911
+ def initialize(app = nil, **_kwargs)
929
912
  super()
930
913
  @app = app
931
914
  @template_cache = Tilt::Cache.new
@@ -952,7 +935,7 @@ module Sinatra
952
935
  unless @response['Content-Type']
953
936
  if Array === body && body[0].respond_to?(:content_type)
954
937
  content_type body[0].content_type
955
- elsif default = settings.default_content_type
938
+ elsif (default = settings.default_content_type)
956
939
  content_type default
957
940
  end
958
941
  end
@@ -970,12 +953,6 @@ module Sinatra
970
953
  self.class.settings
971
954
  end
972
955
 
973
- def options
974
- warn "Sinatra::Base#options is deprecated and will be removed, " \
975
- "use #settings instead."
976
- settings
977
- end
978
-
979
956
  # Exit the current block, halts any further processing
980
957
  # of the request, and returns the specified response.
981
958
  def halt(*response)
@@ -992,7 +969,8 @@ module Sinatra
992
969
 
993
970
  # Forward the request to the downstream app -- middleware only.
994
971
  def forward
995
- fail "downstream app not set" unless @app.respond_to? :call
972
+ raise 'downstream app not set' unless @app.respond_to? :call
973
+
996
974
  status, headers, body = @app.call env
997
975
  @response.status = status
998
976
  @response.body = body
@@ -1014,18 +992,18 @@ module Sinatra
1014
992
 
1015
993
  # Run routes defined on the class and all superclasses.
1016
994
  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
995
+ routes = base.routes[@request.request_method]
1020
996
 
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
997
+ routes&.each do |pattern, conditions, block|
998
+ response.delete_header('Content-Type') unless @pinned_response
1025
999
 
1026
- # don't wipe out pass_block in superclass
1027
- pass_block = returned_pass_block if returned_pass_block
1000
+ returned_pass_block = process_route(pattern, conditions) do |*args|
1001
+ env['sinatra.route'] = "#{@request.request_method} #{pattern}"
1002
+ route_eval { block[*args] }
1028
1003
  end
1004
+
1005
+ # don't wipe out pass_block in superclass
1006
+ pass_block = returned_pass_block if returned_pass_block
1029
1007
  end
1030
1008
 
1031
1009
  # Run routes defined in superclass.
@@ -1049,15 +1027,17 @@ module Sinatra
1049
1027
  # Returns pass block.
1050
1028
  def process_route(pattern, conditions, block = nil, values = [])
1051
1029
  route = @request.path_info
1052
- route = '/' if route.empty? and not settings.empty_path_info?
1030
+ route = '/' if route.empty? && !settings.empty_path_info?
1053
1031
  route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/')
1054
- return unless params = pattern.params(route)
1055
1032
 
1056
- params.delete("ignore") # TODO: better params handling, maybe turn it into "smart" object or detect changes
1033
+ params = pattern.params(route)
1034
+ return unless params
1035
+
1036
+ params.delete('ignore') # TODO: better params handling, maybe turn it into "smart" object or detect changes
1057
1037
  force_encoding(params)
1058
- @params = @params.merge(params) if params.any?
1038
+ @params = @params.merge(params) { |_k, v1, v2| v2 || v1 } if params.any?
1059
1039
 
1060
- regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? {|subpattern| subpattern.is_a?(Mustermann::Regular)} )
1040
+ regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? { |subpattern| subpattern.is_a?(Mustermann::Regular) })
1061
1041
  if regexp_exists
1062
1042
  captures = pattern.match(route).captures.map { |c| URI_INSTANCE.unescape(c) if c }
1063
1043
  values += captures
@@ -1070,7 +1050,7 @@ module Sinatra
1070
1050
  conditions.each { |c| throw :pass if c.bind(self).call == false }
1071
1051
  block ? block[self, values] : yield(self, values)
1072
1052
  end
1073
- rescue
1053
+ rescue StandardError
1074
1054
  @env['sinatra.error.params'] = @params
1075
1055
  raise
1076
1056
  ensure
@@ -1084,35 +1064,35 @@ module Sinatra
1084
1064
  # a NotFound exception. Subclasses can override this method to perform
1085
1065
  # custom route miss logic.
1086
1066
  def route_missing
1087
- if @app
1088
- forward
1089
- else
1090
- raise NotFound, "#{request.request_method} #{request.path_info}"
1091
- end
1067
+ raise NotFound unless @app
1068
+
1069
+ forward
1092
1070
  end
1093
1071
 
1094
1072
  # Attempt to serve static files from public directory. Throws :halt when
1095
1073
  # a matching file is found, returns nil otherwise.
1096
1074
  def static!(options = {})
1097
1075
  return if (public_dir = settings.public_folder).nil?
1076
+
1098
1077
  path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}"
1099
1078
  return unless valid_path?(path)
1100
1079
 
1101
1080
  path = File.expand_path(path)
1102
- return unless path.start_with?(File.expand_path(public_dir) + '/')
1081
+ return unless path.start_with?("#{File.expand_path(public_dir)}/")
1082
+
1103
1083
  return unless File.file?(path)
1104
1084
 
1105
1085
  env['sinatra.static_file'] = path
1106
1086
  cache_control(*settings.static_cache_control) if settings.static_cache_control?
1107
- send_file path, options.merge(:disposition => nil)
1087
+ send_file path, options.merge(disposition: nil)
1108
1088
  end
1109
1089
 
1110
1090
  # Run the block with 'throw :halt' support and apply result to the response.
1111
- def invoke
1112
- res = catch(:halt) { yield }
1091
+ def invoke(&block)
1092
+ res = catch(:halt, &block)
1113
1093
 
1114
- res = [res] if Integer === res or String === res
1115
- if Array === res and Integer === res.first
1094
+ res = [res] if (Integer === res) || (String === res)
1095
+ if (Array === res) && (Integer === res.first)
1116
1096
  res = res.dup
1117
1097
  status(res.shift)
1118
1098
  body(res.pop)
@@ -1128,6 +1108,7 @@ module Sinatra
1128
1108
  # Avoid passing frozen string in force_encoding
1129
1109
  @params.merge!(@request.params).each do |key, val|
1130
1110
  next unless val.respond_to?(:force_encoding)
1111
+
1131
1112
  val = val.dup if val.frozen?
1132
1113
  @params[key] = force_encoding(val)
1133
1114
  end
@@ -1139,39 +1120,43 @@ module Sinatra
1139
1120
  end
1140
1121
  route!
1141
1122
  end
1142
- rescue ::Exception => boom
1143
- invoke { handle_exception!(boom) }
1123
+ rescue ::Exception => e
1124
+ invoke { handle_exception!(e) }
1144
1125
  ensure
1145
1126
  begin
1146
1127
  filter! :after unless env['sinatra.static_file']
1147
- rescue ::Exception => boom
1148
- invoke { handle_exception!(boom) } unless @env['sinatra.error']
1128
+ rescue ::Exception => e
1129
+ invoke { handle_exception!(e) } unless @env['sinatra.error']
1149
1130
  end
1150
1131
  end
1151
1132
 
1152
1133
  # Error handling during requests.
1153
1134
  def handle_exception!(boom)
1154
- if error_params = @env['sinatra.error.params']
1155
- @params = @params.merge(error_params)
1156
- end
1135
+ error_params = @env['sinatra.error.params']
1136
+
1137
+ @params = @params.merge(error_params) if error_params
1138
+
1157
1139
  @env['sinatra.error'] = boom
1158
1140
 
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
1141
+ http_status = if boom.is_a? Sinatra::Error
1142
+ if boom.respond_to? :http_status
1143
+ boom.http_status
1144
+ elsif settings.use_code? && boom.respond_to?(:code)
1145
+ boom.code
1146
+ end
1147
+ end
1148
+
1149
+ http_status = 500 unless http_status&.between?(400, 599)
1150
+ status(http_status)
1166
1151
 
1167
1152
  if server_error?
1168
1153
  dump_errors! boom if settings.dump_errors?
1169
- raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
1154
+ raise boom if settings.show_exceptions? && (settings.show_exceptions != :after_handler)
1170
1155
  elsif not_found?
1171
1156
  headers['X-Cascade'] = 'pass' if settings.x_cascade?
1172
1157
  end
1173
1158
 
1174
- if res = error_block!(boom.class, boom) || error_block!(status, boom)
1159
+ if (res = error_block!(boom.class, boom) || error_block!(status, boom))
1175
1160
  return res
1176
1161
  end
1177
1162
 
@@ -1180,12 +1165,14 @@ module Sinatra
1180
1165
  body Rack::Utils.escape_html(boom.message)
1181
1166
  else
1182
1167
  content_type 'text/html'
1183
- body '<h1>' + (not_found? ? 'Not Found' : 'Bad Request') + '</h1>'
1168
+ body "<h1>#{not_found? ? 'Not Found' : 'Bad Request'}</h1>"
1184
1169
  end
1185
1170
  end
1186
1171
 
1187
1172
  return unless server_error?
1188
- raise boom if settings.raise_errors? or settings.show_exceptions?
1173
+
1174
+ raise boom if settings.raise_errors? || settings.show_exceptions?
1175
+
1189
1176
  error_block! Exception, boom
1190
1177
  end
1191
1178
 
@@ -1193,7 +1180,10 @@ module Sinatra
1193
1180
  def error_block!(key, *block_params)
1194
1181
  base = settings
1195
1182
  while base.respond_to?(:errors)
1196
- next base = base.superclass unless args_array = base.errors[key]
1183
+ args_array = base.errors[key]
1184
+
1185
+ next base = base.superclass unless args_array
1186
+
1197
1187
  args_array.reverse_each do |args|
1198
1188
  first = args == args_array.first
1199
1189
  args += [block_params]
@@ -1201,32 +1191,26 @@ module Sinatra
1201
1191
  return resp unless resp.nil? && !first
1202
1192
  end
1203
1193
  end
1204
- return false unless key.respond_to? :superclass and key.superclass < Exception
1194
+ return false unless key.respond_to?(:superclass) && (key.superclass < Exception)
1195
+
1205
1196
  error_block!(key.superclass, *block_params)
1206
1197
  end
1207
1198
 
1208
1199
  def dump_errors!(boom)
1209
- msg = ["#{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1200
+ msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1210
1201
  @env['rack.errors'].puts(msg)
1211
1202
  end
1212
1203
 
1213
1204
  class << self
1214
1205
  CALLERS_TO_IGNORE = [ # :nodoc:
1215
- /\/sinatra(\/(base|main|show_exceptions))?\.rb$/, # all sinatra code
1216
- /lib\/tilt.*\.rb$/, # all tilt code
1206
+ %r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code
1207
+ %r{lib/tilt.*\.rb$}, # all tilt code
1217
1208
  /^\(.*\)$/, # generated code
1218
- /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
1209
+ %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1219
1210
  /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
1211
+ %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
1212
+ /<internal:/ # internal in ruby >= 1.9.2
1213
+ ].freeze
1230
1214
 
1231
1215
  attr_reader :routes, :filters, :templates, :errors
1232
1216
 
@@ -1235,17 +1219,17 @@ module Sinatra
1235
1219
  def reset!
1236
1220
  @conditions = []
1237
1221
  @routes = {}
1238
- @filters = {:before => [], :after => []}
1222
+ @filters = { before: [], after: [] }
1239
1223
  @errors = {}
1240
1224
  @middleware = []
1241
1225
  @prototype = nil
1242
1226
  @extensions = []
1243
1227
 
1244
- if superclass.respond_to?(:templates)
1245
- @templates = Hash.new { |hash, key| superclass.templates[key] }
1246
- else
1247
- @templates = {}
1248
- end
1228
+ @templates = if superclass.respond_to?(:templates)
1229
+ Hash.new { |_hash, key| superclass.templates[key] }
1230
+ else
1231
+ {}
1232
+ end
1249
1233
  end
1250
1234
 
1251
1235
  # Extension modules registered on this class and all superclasses.
@@ -1269,16 +1253,21 @@ module Sinatra
1269
1253
  # Sets an option to the given value. If the value is a proc,
1270
1254
  # the proc will be called every time the option is accessed.
1271
1255
  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
1256
+ raise ArgumentError if block && !not_set
1257
+
1258
+ if block
1259
+ value = block
1260
+ not_set = false
1261
+ end
1274
1262
 
1275
1263
  if not_set
1276
1264
  raise ArgumentError unless option.respond_to?(:each)
1277
- option.each { |k,v| set(k, v) }
1265
+
1266
+ option.each { |k, v| set(k, v) }
1278
1267
  return self
1279
1268
  end
1280
1269
 
1281
- if respond_to?("#{option}=") and not ignore_setter
1270
+ if respond_to?("#{option}=") && !ignore_setter
1282
1271
  return __send__("#{option}=", value)
1283
1272
  end
1284
1273
 
@@ -1317,7 +1306,7 @@ module Sinatra
1317
1306
  # class, or an HTTP status code to specify which errors should be
1318
1307
  # handled.
1319
1308
  def error(*codes, &block)
1320
- args = compile! "ERROR", /.*/, block
1309
+ args = compile! 'ERROR', /.*/, block
1321
1310
  codes = codes.flat_map(&method(:Array))
1322
1311
  codes << Exception if codes.empty?
1323
1312
  codes << Sinatra::NotFound if codes.include?(404)
@@ -1343,7 +1332,7 @@ module Sinatra
1343
1332
  # Load embedded templates from the file; uses the caller's __FILE__
1344
1333
  # when no file is specified.
1345
1334
  def inline_templates=(file = nil)
1346
- file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file
1335
+ file = (caller_files.first || File.expand_path($0)) if file.nil? || file == true
1347
1336
 
1348
1337
  begin
1349
1338
  io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
@@ -1352,23 +1341,24 @@ module Sinatra
1352
1341
  app, data = nil
1353
1342
  end
1354
1343
 
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
1344
+ return unless data
1345
+
1346
+ encoding = if app && app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
1347
+ $2
1348
+ else
1349
+ settings.default_encoding
1350
+ end
1351
+
1352
+ lines = app.count("\n") + 1
1353
+ template = nil
1354
+ force_encoding data, encoding
1355
+ data.each_line do |line|
1356
+ lines += 1
1357
+ if line =~ /^@@\s*(.*\S)\s*$/
1358
+ template = force_encoding(String.new, encoding)
1359
+ templates[$1.to_sym] = [template, file, lines]
1360
+ elsif template
1361
+ template << line
1372
1362
  end
1373
1363
  end
1374
1364
  end
@@ -1377,8 +1367,10 @@ module Sinatra
1377
1367
  def mime_type(type, value = nil)
1378
1368
  return type if type.nil?
1379
1369
  return type.to_s if type.to_s.include?('/')
1380
- type = ".#{type}" unless type.to_s[0] == ?.
1370
+
1371
+ type = ".#{type}" unless type.to_s[0] == '.'
1381
1372
  return Rack::Mime.mime_type(type, nil) unless value
1373
+
1382
1374
  Rack::Mime::MIME_TYPES[type] = value
1383
1375
  end
1384
1376
 
@@ -1387,7 +1379,7 @@ module Sinatra
1387
1379
  # mime_types :js # => ['application/javascript', 'text/javascript']
1388
1380
  def mime_types(type)
1389
1381
  type = mime_type type
1390
- type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
1382
+ type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
1391
1383
  end
1392
1384
 
1393
1385
  # Define a before filter; runs before all requests within the same
@@ -1416,7 +1408,7 @@ module Sinatra
1416
1408
  end
1417
1409
 
1418
1410
  def public=(value)
1419
- warn ":public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead"
1411
+ warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
1420
1412
  set(:public_folder, value)
1421
1413
  end
1422
1414
 
@@ -1438,14 +1430,21 @@ module Sinatra
1438
1430
  route('HEAD', path, opts, &block)
1439
1431
  end
1440
1432
 
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
1433
+ def put(path, opts = {}, &block) route 'PUT', path, opts, &block end
1434
+
1435
+ def post(path, opts = {}, &block) route 'POST', path, opts, &block end
1436
+
1437
+ def delete(path, opts = {}, &block) route 'DELETE', path, opts, &block end
1438
+
1439
+ def head(path, opts = {}, &block) route 'HEAD', path, opts, &block end
1440
+
1441
+ def options(path, opts = {}, &block) route 'OPTIONS', path, opts, &block end
1442
+
1443
+ def patch(path, opts = {}, &block) route 'PATCH', path, opts, &block end
1444
+
1445
+ def link(path, opts = {}, &block) route 'LINK', path, opts, &block end
1446
+
1447
+ def unlink(path, opts = {}, &block) route 'UNLINK', path, opts, &block end
1449
1448
 
1450
1449
  # Makes the methods defined in the block and in the Modules given
1451
1450
  # in `extensions` available to the handlers and templates
@@ -1485,37 +1484,39 @@ module Sinatra
1485
1484
  # Stop the self-hosted server if running.
1486
1485
  def quit!
1487
1486
  return unless running?
1487
+
1488
1488
  # Use Thin's hard #stop! if available, otherwise just #stop.
1489
1489
  running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
1490
- $stderr.puts "== Sinatra has ended his set (crowd applauds)" unless suppress_messages?
1490
+ warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
1491
1491
  set :running_server, nil
1492
1492
  set :handler_name, nil
1493
1493
  end
1494
1494
 
1495
- alias_method :stop!, :quit!
1495
+ alias stop! quit!
1496
1496
 
1497
1497
  # Run the Sinatra app as a self-hosted server using
1498
- # Puma, Mongrel, or WEBrick (in that order). If given a block, will call
1498
+ # Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call
1499
1499
  # with the constructed handler once we have taken the stage.
1500
1500
  def run!(options = {}, &block)
1501
1501
  return if running?
1502
+
1502
1503
  set options
1503
1504
  handler = Rack::Handler.pick(server)
1504
1505
  handler_name = handler.name.gsub(/.*::/, '')
1505
1506
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
1506
- server_settings.merge!(:Port => port, :Host => bind)
1507
+ server_settings.merge!(Port: port, Host: bind)
1507
1508
 
1508
1509
  begin
1509
1510
  start_server(handler, server_settings, handler_name, &block)
1510
1511
  rescue Errno::EADDRINUSE
1511
- $stderr.puts "== Someone is already performing on port #{port}!"
1512
+ warn "== Someone is already performing on port #{port}!"
1512
1513
  raise
1513
1514
  ensure
1514
1515
  quit!
1515
1516
  end
1516
1517
  end
1517
1518
 
1518
- alias_method :start!, :run!
1519
+ alias start! run!
1519
1520
 
1520
1521
  # Check whether the self-hosted server is running or not.
1521
1522
  def running?
@@ -1533,10 +1534,11 @@ module Sinatra
1533
1534
  # Create a new instance of the class fronted by its middleware
1534
1535
  # pipeline. The object is guaranteed to respond to #call but may not be
1535
1536
  # an instance of the class new was called on.
1536
- def new(*args, **kwargs, &bk)
1537
- instance = new!(*args, **kwargs, &bk)
1537
+ def new(*args, &block)
1538
+ instance = new!(*args, &block)
1538
1539
  Wrapper.new(build(instance).to_app, instance)
1539
1540
  end
1541
+ ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
1540
1542
 
1541
1543
  # Creates a Rack::Builder instance with all the middleware set up and
1542
1544
  # the given +app+ as end point.
@@ -1558,12 +1560,6 @@ module Sinatra
1558
1560
  cleaned_caller(1).flatten
1559
1561
  end
1560
1562
 
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
1563
  private
1568
1564
 
1569
1565
  # Starts the server by running the Rack Handler.
@@ -1574,7 +1570,7 @@ module Sinatra
1574
1570
  # Run the instance we created:
1575
1571
  handler.run(self, **server_settings) do |server|
1576
1572
  unless suppress_messages?
1577
- $stderr.puts "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
1573
+ warn "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
1578
1574
  end
1579
1575
 
1580
1576
  setup_traps
@@ -1591,18 +1587,18 @@ module Sinatra
1591
1587
  end
1592
1588
 
1593
1589
  def setup_traps
1594
- if traps?
1595
- at_exit { quit! }
1590
+ return unless traps?
1596
1591
 
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
1592
+ at_exit { quit! }
1603
1593
 
1604
- set :traps, false
1594
+ %i[INT TERM].each do |signal|
1595
+ old_handler = trap(signal) do
1596
+ quit!
1597
+ old_handler.call if old_handler.respond_to?(:call)
1598
+ end
1605
1599
  end
1600
+
1601
+ set :traps, false
1606
1602
  end
1607
1603
 
1608
1604
  # Dynamically defines a method on settings.
@@ -1630,18 +1626,21 @@ module Sinatra
1630
1626
  end
1631
1627
  end
1632
1628
  end
1633
- alias_method :agent, :user_agent
1629
+ alias agent user_agent
1634
1630
 
1635
1631
  # Condition for matching mimetypes. Accepts file extensions.
1636
1632
  def provides(*types)
1637
1633
  types.map! { |t| mime_types(t) }
1638
1634
  types.flatten!
1639
1635
  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)
1636
+ response_content_type = response['Content-Type']
1637
+ preferred_type = request.preferred_type(types)
1638
+
1639
+ if response_content_type
1640
+ types.include?(response_content_type) || types.include?(response_content_type[/^[^;]+/])
1641
+ elsif preferred_type
1642
+ params = (preferred_type.respond_to?(:params) ? preferred_type.params : {})
1643
+ content_type(preferred_type, params)
1645
1644
  true
1646
1645
  else
1647
1646
  false
@@ -1650,7 +1649,7 @@ module Sinatra
1650
1649
  end
1651
1650
 
1652
1651
  def route(verb, path, options = {}, &block)
1653
- enable :empty_path_info if path == "" and empty_path_info.nil?
1652
+ enable :empty_path_info if path == '' && empty_path_info.nil?
1654
1653
  signature = compile!(verb, path, block, **options)
1655
1654
  (@routes[verb] ||= []) << signature
1656
1655
  invoke_hook(:route_added, verb, path, block)
@@ -1679,12 +1678,13 @@ module Sinatra
1679
1678
  pattern = compile(path, route_mustermann_opts)
1680
1679
  method_name = "#{verb} #{path}"
1681
1680
  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 }
1681
+ conditions = @conditions
1682
+ @conditions = []
1683
+ wrapper = block.arity.zero? ?
1684
+ proc { |a, _p| unbound_method.bind(a).call } :
1685
+ proc { |a, p| unbound_method.bind(a).call(*p) }
1686
1686
 
1687
- [ pattern, conditions, wrapper ]
1687
+ [pattern, conditions, wrapper]
1688
1688
  end
1689
1689
 
1690
1690
  def compile(path, route_mustermann_opts = {})
@@ -1702,7 +1702,7 @@ module Sinatra
1702
1702
  end
1703
1703
 
1704
1704
  def setup_middleware(builder)
1705
- middleware.each { |c,a,b| builder.use(c, *a, &b) }
1705
+ middleware.each { |c, a, b| builder.use(c, *a, &b) }
1706
1706
  end
1707
1707
 
1708
1708
  def setup_logging(builder)
@@ -1732,9 +1732,10 @@ module Sinatra
1732
1732
 
1733
1733
  def setup_protection(builder)
1734
1734
  return unless protection?
1735
+
1735
1736
  options = Hash === protection ? protection.dup : {}
1736
1737
  options = {
1737
- img_src: "'self' data:",
1738
+ img_src: "'self' data:",
1738
1739
  font_src: "'self'"
1739
1740
  }.merge options
1740
1741
 
@@ -1748,6 +1749,7 @@ module Sinatra
1748
1749
 
1749
1750
  def setup_sessions(builder)
1750
1751
  return unless sessions?
1752
+
1751
1753
  options = {}
1752
1754
  options[:secret] = session_secret if session_secret?
1753
1755
  options.merge! sessions.to_hash if sessions.respond_to? :to_hash
@@ -1770,15 +1772,15 @@ module Sinatra
1770
1772
  end
1771
1773
 
1772
1774
  # used for deprecation warnings
1773
- def warn(message)
1774
- super message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1775
+ def warn_for_deprecation(message)
1776
+ warn message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1775
1777
  end
1776
1778
 
1777
1779
  # Like Kernel#caller but excluding certain magic entries
1778
1780
  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 } }
1781
+ caller(1)
1782
+ .map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] }
1783
+ .reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1782
1784
  end
1783
1785
  end
1784
1786
 
@@ -1786,6 +1788,7 @@ module Sinatra
1786
1788
  # which is UTF-8 by default
1787
1789
  def self.force_encoding(data, encoding = default_encoding)
1788
1790
  return if data == settings || data.is_a?(Tempfile)
1791
+
1789
1792
  if data.respond_to? :force_encoding
1790
1793
  data.force_encoding(encoding).encode!
1791
1794
  elsif data.respond_to? :each_value
@@ -1796,24 +1799,26 @@ module Sinatra
1796
1799
  data
1797
1800
  end
1798
1801
 
1799
- def force_encoding(*args) settings.force_encoding(*args) end
1802
+ def force_encoding(*args)
1803
+ settings.force_encoding(*args)
1804
+ end
1800
1805
 
1801
1806
  reset!
1802
1807
 
1803
1808
  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? }
1809
+ set :raise_errors, proc { test? }
1810
+ set :dump_errors, proc { !test? }
1811
+ set :show_exceptions, proc { development? }
1807
1812
  set :sessions, false
1808
- set :session_store, Rack::Session::Cookie
1813
+ set :session_store, Rack::Protection::EncryptedCookie
1809
1814
  set :logging, false
1810
1815
  set :protection, true
1811
1816
  set :method_override, false
1812
1817
  set :use_code, false
1813
- set :default_encoding, "utf-8"
1818
+ set :default_encoding, 'utf-8'
1814
1819
  set :x_cascade, true
1815
1820
  set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
1816
- settings.add_charset << /^text\//
1821
+ settings.add_charset << %r{^text/}
1817
1822
  set :mustermann_opts, {}
1818
1823
  set :default_content_type, 'text/html'
1819
1824
 
@@ -1823,12 +1828,12 @@ module Sinatra
1823
1828
  set :session_secret, SecureRandom.hex(64)
1824
1829
  rescue LoadError, NotImplementedError
1825
1830
  # SecureRandom raises a NotImplementedError if no random device is available
1826
- set :session_secret, "%064x" % Kernel.rand(2**256-1)
1831
+ set :session_secret, format('%064x', Kernel.rand((2**256) - 1))
1827
1832
  end
1828
1833
 
1829
1834
  class << self
1830
- alias_method :methodoverride?, :method_override?
1831
- alias_method :methodoverride=, :method_override=
1835
+ alias methodoverride? method_override?
1836
+ alias methodoverride= method_override=
1832
1837
  end
1833
1838
 
1834
1839
  set :run, false # start server via at-exit hook?
@@ -1836,21 +1841,17 @@ module Sinatra
1836
1841
  set :handler_name, nil
1837
1842
  set :traps, true
1838
1843
  set :server, %w[HTTP webrick]
1839
- set :bind, Proc.new { development? ? 'localhost' : '0.0.0.0' }
1844
+ set :bind, proc { development? ? 'localhost' : '0.0.0.0' }
1840
1845
  set :port, Integer(ENV['PORT'] && !ENV['PORT'].empty? ? ENV['PORT'] : 4567)
1841
1846
  set :quiet, false
1842
1847
 
1843
1848
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1844
1849
 
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
1850
+ server.unshift 'puma'
1851
+ server.unshift 'falcon' if ruby_engine != 'jruby'
1852
+ server.unshift 'mongrel' if ruby_engine.nil?
1853
+ server.unshift 'thin' if ruby_engine != 'jruby'
1854
+ server.unshift 'trinidad' if ruby_engine == 'jruby'
1854
1855
 
1855
1856
  set :absolute_redirects, true
1856
1857
  set :prefixed_redirects, false
@@ -1858,14 +1859,14 @@ module Sinatra
1858
1859
  set :strict_paths, true
1859
1860
 
1860
1861
  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? }
1862
+ set :root, proc { app_file && File.expand_path(File.dirname(app_file)) }
1863
+ set :views, proc { root && File.join(root, 'views') }
1864
+ set :reload_templates, proc { development? }
1864
1865
  set :lock, false
1865
1866
  set :threaded, true
1866
1867
 
1867
- set :public_folder, Proc.new { root && File.join(root, 'public') }
1868
- set :static, Proc.new { public_folder && File.exist?(public_folder) }
1868
+ set :public_folder, proc { root && File.join(root, 'public') }
1869
+ set :static, proc { public_folder && File.exist?(public_folder) }
1869
1870
  set :static_cache_control, false
1870
1871
 
1871
1872
  error ::Exception do
@@ -1884,7 +1885,7 @@ module Sinatra
1884
1885
  error NotFound do
1885
1886
  content_type 'text/html'
1886
1887
 
1887
- if self.class == Sinatra::Application
1888
+ if instance_of?(Sinatra::Application)
1888
1889
  code = <<-RUBY.gsub(/^ {12}/, '')
1889
1890
  #{request.request_method.downcase} '#{request.path_info}' do
1890
1891
  "Hello World"
@@ -1899,11 +1900,11 @@ module Sinatra
1899
1900
  end
1900
1901
  RUBY
1901
1902
 
1902
- file = settings.app_file.to_s.sub(settings.root.to_s, '').sub(/^\//, '')
1903
+ file = settings.app_file.to_s.sub(settings.root.to_s, '').sub(%r{^/}, '')
1903
1904
  code = "# in #{file}\n#{code}" unless file.empty?
1904
1905
  end
1905
1906
 
1906
- (<<-HTML).gsub(/^ {10}/, '')
1907
+ <<-HTML.gsub(/^ {10}/, '')
1907
1908
  <!DOCTYPE html>
1908
1909
  <html>
1909
1910
  <head>
@@ -1915,7 +1916,7 @@ module Sinatra
1915
1916
  </head>
1916
1917
  <body>
1917
1918
  <h2>Sinatra doesn’t know this ditty.</h2>
1918
- <img src='#{uri "/__sinatra__/404.png"}'>
1919
+ <img src='#{uri '/__sinatra__/404.png'}'>
1919
1920
  <div id="c">
1920
1921
  Try this:
1921
1922
  <pre>#{Rack::Utils.escape_html(code)}</pre>
@@ -1935,12 +1936,12 @@ module Sinatra
1935
1936
  # top-level. Subclassing Sinatra::Base is highly recommended for
1936
1937
  # modular applications.
1937
1938
  class Application < Base
1938
- set :logging, Proc.new { !test? }
1939
+ set :logging, proc { !test? }
1939
1940
  set :method_override, true
1940
- set :run, Proc.new { !test? }
1941
+ set :run, proc { !test? }
1941
1942
  set :app_file, nil
1942
1943
 
1943
- def self.register(*extensions, &block) #:nodoc:
1944
+ def self.register(*extensions, &block) # :nodoc:
1944
1945
  added_methods = extensions.flat_map(&:public_instance_methods)
1945
1946
  Delegator.delegate(*added_methods)
1946
1947
  super(*extensions, &block)
@@ -1950,11 +1951,12 @@ module Sinatra
1950
1951
  # Sinatra delegation mixin. Mixing this module into an object causes all
1951
1952
  # methods to be delegated to the Sinatra::Application class. Used primarily
1952
1953
  # at the top-level.
1953
- module Delegator #:nodoc:
1954
+ module Delegator # :nodoc:
1954
1955
  def self.delegate(*methods)
1955
1956
  methods.each do |method_name|
1956
1957
  define_method(method_name) do |*args, &block|
1957
1958
  return super(*args, &block) if respond_to? method_name
1959
+
1958
1960
  Delegator.target.send(method_name, *args, &block)
1959
1961
  end
1960
1962
  # ensure keyword argument passing is compatible with ruby >= 2.7
@@ -1977,7 +1979,8 @@ module Sinatra
1977
1979
 
1978
1980
  class Wrapper
1979
1981
  def initialize(stack, instance)
1980
- @stack, @instance = stack, instance
1982
+ @stack = stack
1983
+ @instance = instance
1981
1984
  end
1982
1985
 
1983
1986
  def settings