sinatra 1.2.9 → 1.3.0.a

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.

@@ -843,8 +843,8 @@ Session被用来在请求之间保持状态。如果被激活,每一个用户
843
843
  。简单的使用 +call+ 可以做到这一点:
844
844
 
845
845
  get '/foo' do
846
- status, headers, body = call env.merge("PATH_INFO" => '/bar')
847
- [status, headers, body.map(&:upcase)]
846
+ status, headers, body = call request.env.merge("PATH_INFO" => '/bar')
847
+ [status, body.upcase]
848
848
  end
849
849
 
850
850
  get '/bar' do
@@ -884,7 +884,7 @@ Session被用来在请求之间保持状态。如果被激活,每一个用户
884
884
  get '/foo' do
885
885
  status 418
886
886
  headers \
887
- "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
887
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN"
888
888
  "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
889
889
  body "I'm a tea pot!"
890
890
  end
@@ -948,7 +948,7 @@ Sinatra并不理解。使用 +mime_type+ 通过文件扩展名来注册它们:
948
948
 
949
949
  或者使用session:
950
950
 
951
- enable :sessions
951
+ enable :session
952
952
 
953
953
  get '/foo' do
954
954
  session[:secret] = 'foo'
@@ -1314,7 +1314,7 @@ Sinatra会自动处理range请求。
1314
1314
  自定义错误:
1315
1315
 
1316
1316
  error MyCustomError do
1317
- 'So what happened was...' + env['sinatra.error'].message
1317
+ 'So what happened was...' + request.env['sinatra.error'].message
1318
1318
  end
1319
1319
 
1320
1320
  那么,当这个发生的时候:
@@ -1500,7 +1500,7 @@ Sinatra::Base子类可用的方法实际上就是通过顶层 DSL
1500
1500
  或者使用一个 <tt>config.ru</tt>,允许你使用任何Rack处理器:
1501
1501
 
1502
1502
  # config.ru
1503
- require './my_app'
1503
+ require 'my_app'
1504
1504
  run MyApp
1505
1505
 
1506
1506
  运行:
@@ -1520,7 +1520,7 @@ Sinatra::Base子类可用的方法实际上就是通过顶层 DSL
1520
1520
 
1521
1521
  加入相应的 <tt>config.ru</tt>:
1522
1522
 
1523
- require './app'
1523
+ require 'app'
1524
1524
  run Sinatra::Application
1525
1525
 
1526
1526
  === 什么时候用 config.ru?
data/Rakefile CHANGED
@@ -3,12 +3,6 @@ require 'rake/testtask'
3
3
  require 'fileutils'
4
4
  require 'date'
5
5
 
6
- # CI Reporter is only needed for the CI
7
- begin
8
- require 'ci/reporter/rake/test_unit'
9
- rescue LoadError
10
- end
11
-
12
6
  task :default => :test
13
7
  task :spec => :test
14
8
 
@@ -43,16 +37,6 @@ Rake::TestTask.new(:test) do |t|
43
37
  t.ruby_opts << '-I.'
44
38
  end
45
39
 
46
- Rake::TestTask.new(:"test:core") do |t|
47
- core_tests = %w[base delegator encoding extensions filter
48
- helpers mapped_error middleware radius rdoc
49
- readme request response result route_added_hook
50
- routing server settings sinatra static templates]
51
- t.test_files = core_tests.map {|n| "test/#{n}_test.rb"}
52
- t.ruby_opts = ["-rubygems"] if defined? Gem
53
- t.ruby_opts << "-I."
54
- end
55
-
56
40
  # Rcov ================================================================
57
41
 
58
42
  namespace :test do
@@ -83,7 +67,7 @@ task :add_template, [:name] do |t, args|
83
67
  puts "Liquid not found in #{file}"
84
68
  else
85
69
  puts "Adding section to #{file}"
86
- template = template.gsub(/Liquid/, args.name.capitalize).gsub(/liquid/, args.name.downcase)
70
+ template = template.gsub(/Liquid/, args.name.capitalize).gsub(/liquid/, args.name.downcase)
87
71
  code.gsub! /^(\s*===.*CoffeeScript)/, "\n" << template << "\n\\1"
88
72
  File.open(file, "w") { |f| f << code }
89
73
  end
@@ -106,22 +90,18 @@ task :thanks, [:release,:backports] do |t, a|
106
90
  "(based on commits included in #{a.release}, but not in #{a.backports})"
107
91
  end
108
92
 
109
- desc "list of authors"
110
- task :authors, [:commit_range, :format, :sep] do |t, a|
111
- a.with_defaults :format => "%s (%d)", :sep => ", ", :commit_range => '--all'
93
+ task :authors, [:format, :sep] do |t, a|
94
+ a.with_defaults :format => "%s (%d)", :sep => ', '
112
95
  authors = Hash.new { |h,k| h[k] = 0 }
113
96
  blake = "Blake Mizerany"
114
- overall = 0
115
97
  mapping = {
116
98
  "blake.mizerany@gmail.com" => blake, "bmizerany" => blake,
117
99
  "a_user@mac.com" => blake, "ichverstehe" => "Harry Vangberg",
118
100
  "Wu Jiang (nouse)" => "Wu Jiang" }
119
- `git shortlog -s #{a.commit_range}`.lines.map do |line|
101
+ `git shortlog -s`.lines.map do |line|
120
102
  num, name = line.split("\t", 2).map(&:strip)
121
103
  authors[mapping[name] || name] += num.to_i
122
- overall += num.to_i
123
104
  end
124
- puts "#{overall} commits by #{authors.count} authors:"
125
105
  puts authors.sort_by { |n,c| -c }.map { |e| a.format % e }.join(a.sep)
126
106
  end
127
107
 
@@ -167,8 +147,9 @@ if defined?(Gem)
167
147
  # read spec file and split out manifest section
168
148
  spec = File.read(f.name)
169
149
  head, manifest, tail = spec.split(" # = MANIFEST =\n")
170
- # replace version
150
+ # replace version and date
171
151
  head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
152
+ head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
172
153
  # determine file list from git ls-files
173
154
  files = `git ls-files`.
174
155
  split("\n").
@@ -185,10 +166,6 @@ if defined?(Gem)
185
166
  end
186
167
 
187
168
  task 'release' => ['test', package('.gem')] do
188
- if File.read("CHANGES") =~ /= \d\.\d\.\d . not yet released$/i
189
- fail 'please update changes first'
190
- end
191
-
192
169
  sh <<-SH
193
170
  gem install #{package('.gem')} --local &&
194
171
  gem push #{package('.gem')} &&
@@ -1,3 +1,6 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
1
4
  require 'sinatra/base'
2
5
  require 'sinatra/main'
3
6
 
@@ -1,70 +1,38 @@
1
1
  require 'thread'
2
2
  require 'time'
3
3
  require 'uri'
4
- require 'rack'
5
- require 'rack/builder'
4
+ require 'sinatra/rack'
6
5
  require 'sinatra/showexceptions'
7
6
  require 'tilt'
8
- require 'backports'
9
-
10
- warn "WARNING: Sinatra 1.2.x has reached its EOL. Please upgrade."
11
7
 
12
8
  module Sinatra
13
- VERSION = '1.2.9'
9
+ VERSION = '1.3.0.a'
14
10
 
15
11
  # The request object. See Rack::Request for more info:
16
12
  # http://rack.rubyforge.org/doc/classes/Rack/Request.html
17
13
  class Request < Rack::Request
18
14
  # Returns an array of acceptable media types for the response
19
15
  def accept
20
- @env['sinatra.accept'] ||= begin
21
- entries = @env['HTTP_ACCEPT'].to_s.split(',')
22
- entries.map { |e| accept_entry(e) }.sort_by { |e| e.last }.map { |e| e.first }
23
- end
16
+ @env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.split(';')[0].strip }
24
17
  end
25
18
 
26
- def preferred_type(*types)
27
- return accept.first if types.empty?
28
- types.flatten!
29
- accept.detect do |pattern|
30
- type = types.detect { |t| File.fnmatch(pattern, t) }
31
- return type if type
32
- end
33
- end
34
-
35
- if Rack.release <= "1.2"
36
- # Whether or not the web server (or a reverse proxy in front of it) is
37
- # using SSL to communicate with the client.
38
- def secure?
39
- @env['HTTPS'] == 'on' or
40
- @env['HTTP_X_FORWARDED_PROTO'] == 'https' or
41
- @env['rack.url_scheme'] == 'https'
42
- end
43
- else
44
- alias secure? ssl?
45
- end
19
+ alias secure? ssl?
46
20
 
47
21
  def forwarded?
48
22
  @env.include? "HTTP_X_FORWARDED_HOST"
49
23
  end
50
24
 
51
25
  def route
52
- @route ||= Rack::Utils.unescape(path_info)
26
+ @route ||= begin
27
+ path = Rack::Utils.unescape(path_info)
28
+ path.empty? ? "/" : path
29
+ end
53
30
  end
54
31
 
55
32
  def path_info=(value)
56
33
  @route = nil
57
34
  super
58
35
  end
59
-
60
- private
61
-
62
- def accept_entry(entry)
63
- type, *options = entry.gsub(/\s/, '').split(';')
64
- quality = 0 # we sort smalles first
65
- options.delete_if { |e| quality = 1 - e[2..-1].to_f if e =~ /^q=/ }
66
- [type, [quality, type.count('*'), 1 - options.size]]
67
- end
68
36
  end
69
37
 
70
38
  # The response object. See Rack::Response and Rack::ResponseHelpers for
@@ -72,16 +40,16 @@ module Sinatra
72
40
  # http://rack.rubyforge.org/doc/classes/Rack/Response.html
73
41
  # http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
74
42
  class Response < Rack::Response
75
- def finish(&block)
43
+ def finish
44
+ @body = block if block_given?
76
45
  if [204, 304].include?(status.to_i)
77
46
  header.delete "Content-Type"
78
- header.delete "Content-Length"
79
47
  [status.to_i, header.to_hash, []]
80
48
  else
81
- body = block || @body || []
82
- body = [body] if String === body
83
- if Array === body
84
- header["Content-Length"] = body.
49
+ body = @body || []
50
+ body = [body] if body.respond_to? :to_str
51
+ if body.respond_to?(:to_ary)
52
+ header["Content-Length"] = body.to_ary.
85
53
  inject(0) { |len, part| len + Rack::Utils.bytesize(part) }.to_s
86
54
  end
87
55
  [status.to_i, header.to_hash, body]
@@ -130,7 +98,9 @@ module Sinatra
130
98
  return addr if addr =~ /\A[A-z][A-z0-9\+\.\-]*:/
131
99
  uri = [host = ""]
132
100
  if absolute
133
- host << "http#{'s' if request.secure?}://"
101
+ host << 'http'
102
+ host << 's' if request.secure?
103
+ host << "://"
134
104
  if request.forwarded? or request.port != (request.secure? ? 443 : 80)
135
105
  host << request.host_with_port
136
106
  else
@@ -168,6 +138,11 @@ module Sinatra
168
138
  request.session
169
139
  end
170
140
 
141
+ # Access shared logger object.
142
+ def logger
143
+ request.logger
144
+ end
145
+
171
146
  # Look up a media type by file extension in Rack's mime registry.
172
147
  def mime_type(type)
173
148
  Base.mime_type(type)
@@ -175,8 +150,7 @@ module Sinatra
175
150
 
176
151
  # Set the Content-Type of the response body given a media type or file
177
152
  # extension.
178
- def content_type(type = nil, params={})
179
- return response['Content-Type'] unless type
153
+ def content_type(type, params={})
180
154
  default = params.delete :default
181
155
  mime_type = mime_type(type) || default
182
156
  fail "Unknown media type: %p" % type if mime_type.nil?
@@ -184,11 +158,7 @@ module Sinatra
184
158
  unless params.include? :charset or settings.add_charset.all? { |p| not p === mime_type }
185
159
  params[:charset] = params.delete('charset') || settings.default_encoding
186
160
  end
187
- params.delete :charset if mime_type.include? 'charset'
188
- unless params.empty?
189
- mime_type << (mime_type.include?(';') ? ', ' : ';')
190
- mime_type << params.map { |kv| kv.join('=') }.join(', ')
191
- end
161
+ mime_type << ";#{params.map { |kv| kv.join('=') }.join(', ')}" unless params.empty?
192
162
  response['Content-Type'] = mime_type
193
163
  end
194
164
 
@@ -241,11 +211,6 @@ module Sinatra
241
211
 
242
212
  attr_accessor :range # a Range or nil
243
213
 
244
- def initialize(*args)
245
- super(*args)
246
- @range = nil
247
- end
248
-
249
214
  # Checks for byte-ranges in the request and sets self.range appropriately.
250
215
  # Returns false if the ranges are unsatisfiable and the request should return 416.
251
216
  def parse_ranges(env, size)
@@ -287,10 +252,6 @@ module Sinatra
287
252
  ranges
288
253
  end
289
254
 
290
- def close
291
- super unless closed?
292
- end
293
-
294
255
  CHUNK_SIZE = 8192
295
256
 
296
257
  def each
@@ -351,8 +312,8 @@ module Sinatra
351
312
  def expires(amount, *values)
352
313
  values << {} unless values.last.kind_of?(Hash)
353
314
 
354
- if amount.is_a? Integer
355
- time = Time.now + amount.to_i
315
+ if Integer === amount
316
+ time = Time.now + amount
356
317
  max_age = amount
357
318
  else
358
319
  time = time_for amount
@@ -377,7 +338,7 @@ module Sinatra
377
338
  time = time_for time
378
339
  response['Last-Modified'] = time.httpdate
379
340
  # compare based on seconds since epoch
380
- halt 304 if Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i
341
+ halt 304 if Time.httpdate(request.env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i
381
342
  rescue ArgumentError
382
343
  end
383
344
 
@@ -416,7 +377,7 @@ module Sinatra
416
377
  def time_for(value)
417
378
  if value.respond_to? :to_time
418
379
  value.to_time
419
- elsif value.is_a? Time
380
+ elsif Time === value
420
381
  value
421
382
  elsif value.respond_to? :new_offset
422
383
  # DateTime#to_time does the same on 1.9
@@ -426,13 +387,13 @@ module Sinatra
426
387
  elsif value.respond_to? :mday
427
388
  # Date#to_time does the same on 1.9
428
389
  Time.local(value.year, value.mon, value.mday)
429
- elsif value.is_a? Numeric
390
+ elsif Numeric === value
430
391
  Time.at value
431
392
  else
432
393
  Time.parse value.to_s
433
394
  end
434
395
  rescue ArgumentError => boom
435
- raise boom
396
+ raise boom.to_s
436
397
  rescue Exception
437
398
  raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
438
399
  end
@@ -461,11 +422,6 @@ module Sinatra
461
422
  attr_accessor :content_type
462
423
  end
463
424
 
464
- def initialize
465
- super
466
- @default_layout = :layout
467
- end
468
-
469
425
  def erb(template, options={}, locals={})
470
426
  render :erb, template, options, locals
471
427
  end
@@ -539,9 +495,8 @@ module Sinatra
539
495
  # Calls the given block for every possible template file in views,
540
496
  # named name.ext, where ext is registered on engine.
541
497
  def find_template(views, name, engine)
542
- yield ::File.join(views, "#{name}.#{@preferred_extension}")
543
- Tilt.mappings.each do |ext, engines|
544
- next unless ext != @preferred_extension and Array(engines).include? engine
498
+ Tilt.mappings.each do |ext, klass|
499
+ next unless klass == engine
545
500
  yield ::File.join(views, "#{name}.#{ext}")
546
501
  end
547
502
  end
@@ -563,6 +518,7 @@ module Sinatra
563
518
  # extract generic options
564
519
  locals = options.delete(:locals) || locals || {}
565
520
  views = options.delete(:views) || settings.views || "./views"
521
+ @default_layout = :layout if @default_layout.nil?
566
522
  layout = options.delete(:layout)
567
523
  eat_errors = layout.nil?
568
524
  layout = @default_layout if layout.nil? or layout == true
@@ -571,14 +527,11 @@ module Sinatra
571
527
  scope = options.delete(:scope) || self
572
528
 
573
529
  # compile and render template
574
- begin
575
- layout_was = @default_layout
576
- @default_layout = false
577
- template = compile_template(engine, data, options, views)
578
- output = template.render(scope, locals, &block)
579
- ensure
580
- @default_layout = layout_was
581
- end
530
+ layout_was = @default_layout
531
+ @default_layout = false
532
+ template = compile_template(engine, data, options, views)
533
+ output = template.render(scope, locals, &block)
534
+ @default_layout = layout_was
582
535
 
583
536
  # render layout
584
537
  if layout
@@ -598,13 +551,12 @@ module Sinatra
598
551
 
599
552
  case
600
553
  when data.is_a?(Symbol)
601
- body, path, line = settings.templates[data]
554
+ body, path, line = self.class.templates[data]
602
555
  if body
603
556
  body = body.call if body.respond_to?(:call)
604
557
  template.new(path, line.to_i, options) { body }
605
558
  else
606
559
  found = false
607
- @preferred_extension = engine.to_s
608
560
  find_template(views, data, template) do |file|
609
561
  path ||= file # keep the initial path rather than the last one
610
562
  if found = File.exists?(file)
@@ -617,7 +569,7 @@ module Sinatra
617
569
  end
618
570
  when data.is_a?(Proc) || data.is_a?(String)
619
571
  body = data.is_a?(String) ? Proc.new { data } : data
620
- path, line = settings.caller_locations.first
572
+ path, line = self.class.caller_locations.first
621
573
  template.new(path, line.to_i, options, &body)
622
574
  else
623
575
  raise ArgumentError
@@ -636,7 +588,6 @@ module Sinatra
636
588
  attr_reader :template_cache
637
589
 
638
590
  def initialize(app=nil)
639
- super()
640
591
  @app = app
641
592
  @template_cache = Tilt::Cache.new
642
593
  yield self if block_given?
@@ -662,14 +613,24 @@ module Sinatra
662
613
  invoke { dispatch! }
663
614
  invoke { error_block!(response.status) }
664
615
  unless @response['Content-Type']
665
- if Array === body and body.first.respond_to? :content_type
616
+ if body.respond_to?(:to_ary) and body.first.respond_to? :content_type
666
617
  content_type body.first.content_type
667
618
  else
668
619
  content_type :html
669
620
  end
670
621
  end
671
622
 
672
- @response.finish
623
+ status, header, body = @response.finish
624
+
625
+ # Never produce a body on HEAD requests. Do retain the Content-Length
626
+ # unless it's "0", in which case we assume it was calculated erroneously
627
+ # for a manual HEAD response and remove it entirely.
628
+ if @env['REQUEST_METHOD'] == 'HEAD'
629
+ body = []
630
+ header.delete('Content-Length') if header['Content-Length'] == '0'
631
+ end
632
+
633
+ [status, header, body]
673
634
  end
674
635
 
675
636
  # Access settings defined with Base.set.
@@ -704,7 +665,7 @@ module Sinatra
704
665
  # Forward the request to the downstream app -- middleware only.
705
666
  def forward
706
667
  fail "downstream app not set" unless @app.respond_to? :call
707
- status, headers, body = @app.call env
668
+ status, headers, body = @app.call(@request.env)
708
669
  @response.status = status
709
670
  @response.body = body
710
671
  @response.headers.merge! headers
@@ -713,13 +674,13 @@ module Sinatra
713
674
 
714
675
  private
715
676
  # Run filters defined on the class and all superclasses.
716
- def filter!(type, base = settings)
677
+ def filter!(type, base = self.class)
717
678
  filter! type, base.superclass if base.superclass.respond_to?(:filters)
718
679
  base.filters[type].each { |block| instance_eval(&block) }
719
680
  end
720
681
 
721
682
  # Run routes defined on the class and all superclasses.
722
- def route!(base = settings, pass_block=nil)
683
+ def route!(base=self.class, pass_block=nil)
723
684
  if routes = base.routes[@request.request_method]
724
685
  routes.each do |pattern, keys, conditions, block|
725
686
  pass_block = process_route(pattern, keys, conditions) do
@@ -749,9 +710,7 @@ module Sinatra
749
710
  # Returns pass block.
750
711
  def process_route(pattern, keys, conditions)
751
712
  @original_params ||= @params
752
- route = @request.route
753
- route = '/' if route.empty? and not settings.empty_path_info?
754
- if match = pattern.match(route)
713
+ if match = pattern.match(@request.route)
755
714
  values = match.captures.to_a
756
715
  params =
757
716
  if keys.any?
@@ -800,8 +759,7 @@ module Sinatra
800
759
  public_dir = File.expand_path(public_dir)
801
760
 
802
761
  path = File.expand_path(public_dir + unescape(request.path_info))
803
- return if path[0, public_dir.length] != public_dir
804
- return unless File.file?(path)
762
+ return unless path.start_with?(public_dir) and File.file?(path)
805
763
 
806
764
  env['sinatra.static_file'] = path
807
765
  send_file path, :disposition => nil
@@ -822,14 +780,15 @@ module Sinatra
822
780
  end
823
781
 
824
782
  # Run the block with 'throw :halt' support and apply result to the response.
825
- def invoke
826
- res = catch(:halt) { yield }
783
+ def invoke(&block)
784
+ res = catch(:halt) { instance_eval(&block) }
827
785
  return if res.nil?
828
786
 
829
787
  case
830
788
  when res.respond_to?(:to_str)
831
789
  @response.body = [res]
832
- when Array === res
790
+ when res.respond_to?(:to_ary)
791
+ res = res.to_ary
833
792
  if Fixnum === res.first
834
793
  if res.length == 3
835
794
  @response.status, headers, body = res
@@ -895,7 +854,7 @@ module Sinatra
895
854
  # Find an custom error block for the key(s) specified.
896
855
  def error_block!(*keys)
897
856
  keys.each do |key|
898
- base = settings
857
+ base = self.class
899
858
  while base.respond_to?(:errors)
900
859
  if block = base.errors[key]
901
860
  # found a handler, eval and return result
@@ -956,15 +915,14 @@ module Sinatra
956
915
 
957
916
  # Sets an option to the given value. If the value is a proc,
958
917
  # the proc will be called every time the option is accessed.
959
- def set(option, value = (not_set = true), &block)
960
- raise ArgumentError if block and !not_set
918
+ def set(option, value=self, &block)
919
+ raise ArgumentError if block && value != self
961
920
  value = block if block
962
921
  if value.kind_of?(Proc)
963
922
  metadef(option, &value)
964
923
  metadef("#{option}?") { !!__send__(option) }
965
924
  metadef("#{option}=") { |val| metadef(option, &Proc.new{val}) }
966
- elsif not_set
967
- raise ArgumentError unless option.respond_to?(:each)
925
+ elsif value == self && option.respond_to?(:each)
968
926
  option.each { |k,v| set(k, v) }
969
927
  elsif respond_to?("#{option}=")
970
928
  __send__ "#{option}=", value
@@ -1048,14 +1006,6 @@ module Sinatra
1048
1006
  Rack::Mime::MIME_TYPES[type] = value
1049
1007
  end
1050
1008
 
1051
- # provides all mime types matching type, including deprecated types:
1052
- # mime_types :html # => ['text/html']
1053
- # mime_types :js # => ['application/javascript', 'text/javascript']
1054
- def mime_types(type)
1055
- type = mime_type type
1056
- type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
1057
- end
1058
-
1059
1009
  # Define a before filter; runs before all requests within the same
1060
1010
  # context as route handlers and may access/modify the request and
1061
1011
  # response.
@@ -1086,16 +1036,7 @@ module Sinatra
1086
1036
  @conditions << block
1087
1037
  end
1088
1038
 
1089
- def public=(value)
1090
- set :public_folder, value
1091
- end
1092
-
1093
- def public(*)
1094
- super
1095
- public_folder
1096
- end
1097
-
1098
- private
1039
+ private
1099
1040
  # Condition for matching host name. Parameter might be String or Regexp.
1100
1041
  def host_name(pattern)
1101
1042
  condition { pattern === request.host }
@@ -1117,11 +1058,12 @@ module Sinatra
1117
1058
 
1118
1059
  # Condition for matching mimetypes. Accepts file extensions.
1119
1060
  def provides(*types)
1120
- types.map! { |t| mime_types(t) }
1121
- types.flatten!
1061
+ types.map! { |t| mime_type(t) }
1062
+
1122
1063
  condition do
1123
- if type = request.preferred_type(types)
1124
- content_type(type)
1064
+ matching_types = (request.accept & types)
1065
+ unless matching_types.empty?
1066
+ content_type matching_types.first
1125
1067
  true
1126
1068
  else
1127
1069
  false
@@ -1145,12 +1087,12 @@ module Sinatra
1145
1087
  def delete(path, opts={}, &bk) route 'DELETE', path, opts, &bk end
1146
1088
  def head(path, opts={}, &bk) route 'HEAD', path, opts, &bk end
1147
1089
  def options(path, opts={}, &bk) route 'OPTIONS', path, opts, &bk end
1090
+ def patch(path, opts={}, &bk) route 'PATCH', path, opts, &bk end
1148
1091
 
1149
1092
  private
1150
1093
  def route(verb, path, options={}, &block)
1151
1094
  # Because of self.options.host
1152
1095
  host_name(options.delete(:host)) if options.key?(:host)
1153
- enable :empty_path_info if path == "" and empty_path_info.nil?
1154
1096
 
1155
1097
  block, pattern, keys, conditions = compile! verb, path, block, options
1156
1098
  invoke_hook(:route_added, verb, path, block)
@@ -1212,7 +1154,7 @@ module Sinatra
1212
1154
  # Makes the methods defined in the block and in the Modules given
1213
1155
  # in `extensions` available to the handlers and templates
1214
1156
  def helpers(*extensions, &block)
1215
- class_eval(&block) if block_given?
1157
+ class_eval(&block) if block_given?
1216
1158
  include(*extensions) if extensions.any?
1217
1159
  end
1218
1160
 
@@ -1246,7 +1188,7 @@ module Sinatra
1246
1188
  def quit!(server, handler_name)
1247
1189
  # Use Thin's hard #stop! if available, otherwise just #stop.
1248
1190
  server.respond_to?(:stop!) ? server.stop! : server.stop
1249
- $stderr.puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i
1191
+ puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i
1250
1192
  end
1251
1193
 
1252
1194
  # Run the Sinatra app as a self-hosted server using
@@ -1255,14 +1197,14 @@ module Sinatra
1255
1197
  set options
1256
1198
  handler = detect_rack_handler
1257
1199
  handler_name = handler.name.gsub(/.*::/, '')
1258
- $stderr.puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
1200
+ puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
1259
1201
  "on #{port} for #{environment} with backup from #{handler_name}" unless handler_name =~/cgi/i
1260
1202
  handler.run self, :Host => bind, :Port => port do |server|
1261
1203
  [:INT, :TERM].each { |sig| trap(sig) { quit!(server, handler_name) } }
1262
1204
  set :running, true
1263
1205
  end
1264
1206
  rescue Errno::EADDRINUSE => e
1265
- $stderr.puts "== Someone is already performing on port #{port}!"
1207
+ puts "== Someone is already performing on port #{port}!"
1266
1208
  end
1267
1209
 
1268
1210
  # The prototype instance used to process requests.
@@ -1284,11 +1226,10 @@ module Sinatra
1284
1226
  # an instance of this class as end point.
1285
1227
  def build(*args, &bk)
1286
1228
  builder = Rack::Builder.new
1229
+ setup_logging builder
1230
+ setup_sessions builder
1287
1231
  builder.use Rack::MethodOverride if method_override?
1288
1232
  builder.use ShowExceptions if show_exceptions?
1289
- builder.use Rack::CommonLogger if logging?
1290
- builder.use Rack::Head
1291
- setup_sessions builder
1292
1233
  middleware.each { |c,a,b| builder.use(c, *a, &b) }
1293
1234
  builder.run new!(*args, &bk)
1294
1235
  builder
@@ -1299,16 +1240,31 @@ module Sinatra
1299
1240
  end
1300
1241
 
1301
1242
  private
1243
+ def setup_logging(builder)
1244
+ if logging?
1245
+ builder.use Rack::CommonLogger
1246
+ if logging.respond_to? :to_int
1247
+ builder.use Rack::Logger, logging
1248
+ else
1249
+ builder.use Rack::Logger
1250
+ end
1251
+ else
1252
+ builder.use Rack::NullLogger
1253
+ end
1254
+ end
1255
+
1302
1256
  def setup_sessions(builder)
1303
1257
  return unless sessions?
1304
- builder.use Rack::Session::Cookie, :secret => session_secret
1258
+ options = { :secret => session_secret }
1259
+ options.merge! sessions.to_hash if sessions.respond_to? :to_hash
1260
+ builder.use Rack::Session::Cookie, options
1305
1261
  end
1306
1262
 
1307
1263
  def detect_rack_handler
1308
1264
  servers = Array(server)
1309
1265
  servers.each do |server_name|
1310
1266
  begin
1311
- return Rack::Handler.get(server_name)
1267
+ return Rack::Handler.get(server_name.downcase)
1312
1268
  rescue LoadError
1313
1269
  rescue NameError
1314
1270
  end
@@ -1339,18 +1295,15 @@ module Sinatra
1339
1295
  CALLERS_TO_IGNORE = [ # :nodoc:
1340
1296
  /\/sinatra(\/(base|main|showexceptions))?\.rb$/, # all sinatra code
1341
1297
  /lib\/tilt.*\.rb$/, # all tilt code
1342
- /^\(.*\)$/, # generated code
1298
+ /\(.*\)/, # generated code
1343
1299
  /rubygems\/custom_require\.rb$/, # rubygems require hacks
1344
1300
  /active_support/, # active_support require hacks
1345
1301
  /bundler(\/runtime)?\.rb/, # bundler require hacks
1346
1302
  /<internal:/ # internal in ruby >= 1.9.2
1347
1303
  ]
1348
1304
 
1349
- # contrary to what the comment said previously, rubinius never supported this
1350
- if defined?(RUBY_IGNORE_CALLERS)
1351
- warn "RUBY_IGNORE_CALLERS is deprecated and will no longer be supported by Sinatra 2.0"
1352
- CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS)
1353
- end
1305
+ # add rubinius (and hopefully other VM impls) ignore patterns ...
1306
+ CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
1354
1307
 
1355
1308
  # Like Kernel#caller but excluding certain magic entries and without
1356
1309
  # line / method information; the resulting array contains filenames only.
@@ -1379,7 +1332,7 @@ module Sinatra
1379
1332
  def self.force_encoding(data, encoding = default_encoding)
1380
1333
  return if data == settings || data.is_a?(Tempfile)
1381
1334
  if data.respond_to? :force_encoding
1382
- data.force_encoding(encoding).encode!
1335
+ data.force_encoding encoding
1383
1336
  elsif data.respond_to? :each_value
1384
1337
  data.each_value { |v| force_encoding(v, encoding) }
1385
1338
  elsif data.respond_to? :each
@@ -1389,7 +1342,7 @@ module Sinatra
1389
1342
  end
1390
1343
  else
1391
1344
  def self.force_encoding(data, *) data end
1392
- end
1345
+ end
1393
1346
 
1394
1347
  reset!
1395
1348
 
@@ -1401,8 +1354,7 @@ module Sinatra
1401
1354
  set :logging, false
1402
1355
  set :method_override, false
1403
1356
  set :default_encoding, "utf-8"
1404
- set :add_charset, %w[javascript xml xhtml+xml json].map { |t| "application/#{t}" }
1405
- settings.add_charset << /^text\//
1357
+ set :add_charset, [/^text\//, 'application/javascript', 'application/xml', 'application/xhtml+xml']
1406
1358
 
1407
1359
  # explicitly generating this eagerly to play nice with preforking
1408
1360
  set :session_secret, '%x' % rand(2**255)
@@ -1420,15 +1372,14 @@ module Sinatra
1420
1372
 
1421
1373
  set :absolute_redirects, true
1422
1374
  set :prefixed_redirects, false
1423
- set :empty_path_info, nil
1424
1375
 
1425
1376
  set :app_file, nil
1426
1377
  set :root, Proc.new { app_file && File.expand_path(File.dirname(app_file)) }
1427
1378
  set :views, Proc.new { root && File.join(root, 'views') }
1428
- set :reload_templates, Proc.new { development? or RUBY_VERSION < '1.8.7' }
1379
+ set :reload_templates, Proc.new { development? }
1429
1380
  set :lock, false
1430
1381
 
1431
- set :public_folder, Proc.new { root && File.join(root, 'public') }
1382
+ set :public, Proc.new { root && File.join(root, 'public') }
1432
1383
  set :static, Proc.new { public && File.exist?(public) }
1433
1384
 
1434
1385
  error ::Exception do
@@ -1458,8 +1409,8 @@ module Sinatra
1458
1409
  </style>
1459
1410
  </head>
1460
1411
  <body>
1461
- <h2>Sinatra doesn&rsquo;t know this ditty.</h2>
1462
- <img src='#{uri "/__sinatra__/404.png"}'>
1412
+ <h2>Sinatra doesn't know this ditty.</h2>
1413
+ <img src='/__sinatra__/404.png'>
1463
1414
  <div id="c">
1464
1415
  Try this:
1465
1416
  <pre>#{request.request_method.downcase} '#{request.path_info}' do\n "Hello World"\nend</pre>
@@ -1476,13 +1427,12 @@ module Sinatra
1476
1427
  #
1477
1428
  # The Application class should not be subclassed, unless you want to
1478
1429
  # inherit all settings, routes, handlers, and error pages from the
1479
- # top-level. Subclassing Sinatra::Base is highly recommended for
1430
+ # top-level. Subclassing Sinatra::Base is heavily recommended for
1480
1431
  # modular applications.
1481
1432
  class Application < Base
1482
1433
  set :logging, Proc.new { ! test? }
1483
1434
  set :method_override, true
1484
1435
  set :run, Proc.new { ! test? }
1485
- set :session_secret, Proc.new { super() unless development? }
1486
1436
 
1487
1437
  def self.register(*extensions, &block) #:nodoc:
1488
1438
  added_methods = extensions.map {|m| m.public_instance_methods }.flatten
@@ -1495,32 +1445,18 @@ module Sinatra
1495
1445
  # methods to be delegated to the Sinatra::Application class. Used primarily
1496
1446
  # at the top-level.
1497
1447
  module Delegator #:nodoc:
1498
- TEMPLATE = <<-RUBY
1499
- def %1$s(*args, &b)
1500
- return super if respond_to? :%1$s
1501
- ::Sinatra::Delegator.target.send("%2$s", *args, &b)
1502
- end
1503
- RUBY
1504
-
1505
1448
  def self.delegate(*methods)
1506
1449
  methods.each do |method_name|
1507
- # Replaced with way shorter and better implementation in 1.3.0
1508
- # using define_method instead, however, blocks cannot take block
1509
- # arguments on 1.8.6.
1510
- begin
1511
- code = TEMPLATE % [method_name, method_name]
1512
- eval code, binding, '(__DELEGATE__)', 1
1513
- rescue SyntaxError
1514
- code = TEMPLATE % [:_delegate, method_name]
1515
- eval code, binding, '(__DELEGATE__)', 1
1516
- alias_method method_name, :_delegate
1517
- undef_method :_delegate
1518
- end
1519
- private method_name
1450
+ eval <<-RUBY, binding, '(__DELEGATE__)', 1
1451
+ def #{method_name}(*args, &b)
1452
+ ::Sinatra::Delegator.target.send(#{method_name.inspect}, *args, &b)
1453
+ end
1454
+ private #{method_name.inspect}
1455
+ RUBY
1520
1456
  end
1521
1457
  end
1522
1458
 
1523
- delegate :get, :put, :post, :delete, :head, :options, :template, :layout,
1459
+ delegate :get, :patch, :put, :post, :delete, :head, :options, :template, :layout,
1524
1460
  :before, :after, :error, :not_found, :configure, :set, :mime_type,
1525
1461
  :enable, :disable, :use, :development?, :test?, :production?,
1526
1462
  :helpers, :settings
@@ -1542,11 +1478,11 @@ module Sinatra
1542
1478
 
1543
1479
  # Extend the top-level DSL with the modules provided.
1544
1480
  def self.register(*extensions, &block)
1545
- Delegator.target.register(*extensions, &block)
1481
+ Application.register(*extensions, &block)
1546
1482
  end
1547
1483
 
1548
1484
  # Include the helper modules provided in Sinatra's request context.
1549
1485
  def self.helpers(*extensions, &block)
1550
- Delegator.target.helpers(*extensions, &block)
1486
+ Application.helpers(*extensions, &block)
1551
1487
  end
1552
1488
  end