bmizerany-sinatra 0.9.0 → 0.9.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/compat/helper.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'rubygems'
2
2
  require 'mocha'
3
3
 
4
+ # disable warnings in compat specs.
5
+ $VERBOSE = nil
6
+
4
7
  $:.unshift File.dirname(File.dirname(__FILE__)) + "/lib"
5
8
 
6
9
  ENV['RACK_ENV'] ||= 'test'
@@ -10,9 +13,18 @@ require 'sinatra/test'
10
13
  require 'sinatra/test/unit'
11
14
  require 'sinatra/test/spec'
12
15
 
16
+ module Sinatra::Test
17
+ # we need to remove the new test helper methods since they conflict with
18
+ # the top-level methods of the same name.
19
+ %w(get head post put delete).each do |verb|
20
+ remove_method verb
21
+ end
22
+ include Sinatra::Delegator
23
+ end
24
+
13
25
  class Test::Unit::TestCase
26
+ include Sinatra::Test
14
27
  def setup
15
28
  @app = lambda { |env| Sinatra::Application.call(env) }
16
29
  end
17
- include Sinatra::Test
18
30
  end
data/lib/sinatra/base.rb CHANGED
@@ -4,7 +4,7 @@ require 'rack'
4
4
  require 'rack/builder'
5
5
 
6
6
  module Sinatra
7
- VERSION = '0.9.0'
7
+ VERSION = '0.9.0.2'
8
8
 
9
9
  class Request < Rack::Request
10
10
  def user_agent
@@ -14,6 +14,13 @@ module Sinatra
14
14
  def accept
15
15
  @env['HTTP_ACCEPT'].split(',').map { |a| a.strip }
16
16
  end
17
+
18
+ # Override Rack 0.9.x's #params implementation (see #72 in lighthouse)
19
+ def params
20
+ self.GET.update(self.POST)
21
+ rescue EOFError => boom
22
+ self.GET
23
+ end
17
24
  end
18
25
 
19
26
  class Response < Rack::Response
@@ -70,7 +77,7 @@ module Sinatra
70
77
  def redirect(uri, *args)
71
78
  status 302
72
79
  response['Location'] = uri
73
- halt *args
80
+ halt(*args)
74
81
  end
75
82
 
76
83
  # Halt processing and return the error status provided.
@@ -135,7 +142,7 @@ module Sinatra
135
142
  class StaticFile < ::File #:nodoc:
136
143
  alias_method :to_path, :path
137
144
  def each
138
- while buf = read(8196)
145
+ while buf = read(8192)
139
146
  yield buf
140
147
  end
141
148
  end
@@ -210,6 +217,7 @@ module Sinatra
210
217
 
211
218
  def lookup_layout(engine, options)
212
219
  return if options[:layout] == false
220
+ options.delete(:layout) if options[:layout] == true
213
221
  template = options[:layout] || :layout
214
222
  data = lookup_template(engine, template, options)
215
223
  [template, data]
@@ -298,10 +306,10 @@ module Sinatra
298
306
  attr_accessor :env, :request, :response, :params
299
307
 
300
308
  def call!(env)
301
- @env = env
302
- @request = Request.new(env)
309
+ @env = env
310
+ @request = Request.new(env)
303
311
  @response = Response.new
304
- @params = nil
312
+ @params = nil
305
313
  error_detection { dispatch! }
306
314
  @response.finish
307
315
  end
@@ -320,13 +328,16 @@ module Sinatra
320
328
 
321
329
  private
322
330
  def dispatch!
323
- self.class.filters.each {|block| instance_eval(&block)}
331
+ self.class.filters.each do |block|
332
+ res = catch(:halt) { instance_eval(&block) ; :continue }
333
+ return unless res == :continue
334
+ end
335
+
324
336
  if routes = self.class.routes[@request.request_method]
325
337
  path = @request.path_info
326
- original_params = Hash.new{ |hash,k| hash[k.to_s] if Symbol === k }
327
- original_params.merge! @request.params
338
+ original_params = nested_params(@request.params)
328
339
 
329
- routes.each do |pattern, keys, conditions, block|
340
+ routes.each do |pattern, keys, conditions, method_name|
330
341
  if pattern =~ path
331
342
  values = $~.captures.map{|val| val && unescape(val) }
332
343
  params =
@@ -344,13 +355,12 @@ module Sinatra
344
355
  else
345
356
  {}
346
357
  end
347
- @params = original_params.dup
348
- @params.merge!(params)
358
+ @params = original_params.merge(params)
349
359
 
350
360
  catch(:pass) {
351
361
  conditions.each { |cond|
352
362
  throw :pass if instance_eval(&cond) == false }
353
- return invoke(block)
363
+ return invoke(method_name)
354
364
  }
355
365
  end
356
366
  end
@@ -358,8 +368,26 @@ module Sinatra
358
368
  raise NotFound
359
369
  end
360
370
 
371
+ def nested_params(params)
372
+ return indifferent_hash.merge(params) if !params.keys.join.include?('[')
373
+ params.inject indifferent_hash do |res, (key,val)|
374
+ if key =~ /\[.*\]/
375
+ splat = key.scan(/(^[^\[]+)|\[([^\]]+)\]/).flatten.compact
376
+ head, last = splat[0..-2], splat[-1]
377
+ head.inject(res){ |s,v| s[v] ||= indifferent_hash }[last] = val
378
+ end
379
+ res
380
+ end
381
+ end
382
+
383
+ def indifferent_hash
384
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
385
+ end
386
+
361
387
  def invoke(block)
362
388
  res = catch(:halt) { instance_eval(&block) }
389
+ return if res.nil?
390
+
363
391
  case
364
392
  when res.respond_to?(:to_str)
365
393
  @response.body = [res]
@@ -379,17 +407,12 @@ module Sinatra
379
407
  else
380
408
  @response.body = res
381
409
  end
382
- when res.kind_of?(Symbol) # TODO: deprecate this.
383
- @response.body = __send__(res)
384
410
  when res.respond_to?(:each)
385
411
  @response.body = res
386
412
  when (100...599) === res
387
413
  @response.status = res
388
- when res.nil?
389
- @response.body = []
390
- else
391
- raise TypeError, "#{res.inspect} not supported"
392
414
  end
415
+
393
416
  res
394
417
  end
395
418
 
@@ -404,6 +427,12 @@ module Sinatra
404
427
  invoke handler unless handler.nil?
405
428
  rescue ::Exception => boom
406
429
  @env['sinatra.error'] = boom
430
+
431
+ if options.dump_errors?
432
+ msg = ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
433
+ @env['rack.errors'] << msg
434
+ end
435
+
407
436
  raise boom if options.raise_errors?
408
437
  @response.status = 500
409
438
  invoke errmap[boom.class] || errmap[Exception]
@@ -456,6 +485,10 @@ module Sinatra
456
485
  end
457
486
  end
458
487
 
488
+ def not_found(&block)
489
+ error 404, &block
490
+ end
491
+
459
492
  def template(name, &block)
460
493
  templates[name] = block
461
494
  end
@@ -465,11 +498,16 @@ module Sinatra
465
498
  end
466
499
 
467
500
  def use_in_file_templates!
468
- line = caller.detect { |s| s !~ /lib\/sinatra.*\.rb/ &&
469
- s !~ /\(.*\)/ }
501
+ line = caller.detect do |s|
502
+ [
503
+ /lib\/sinatra.*\.rb/,
504
+ /\(.*\)/,
505
+ /rubygems\/custom_require\.rb/
506
+ ].all? { |x| s !~ x }
507
+ end
470
508
  file = line.sub(/:\d+.*$/, '')
471
509
  if data = ::IO.read(file).split('__END__')[1]
472
- data.gsub! /\r\n/, "\n"
510
+ data.gsub!(/\r\n/, "\n")
473
511
  template = nil
474
512
  data.each_line do |line|
475
513
  if line =~ /^@@\s*(.*)/
@@ -528,7 +566,7 @@ module Sinatra
528
566
 
529
567
  def get(path, opts={}, &block)
530
568
  conditions = @conditions.dup
531
- route 'GET', path, opts, &block
569
+ route('GET', path, opts, &block)
532
570
 
533
571
  @conditions = conditions
534
572
  head(path, opts) { invoke(block) ; [] }
@@ -540,15 +578,20 @@ module Sinatra
540
578
  def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk; end
541
579
 
542
580
  private
543
- def route(method, path, opts={}, &block)
581
+ def route(verb, path, opts={}, &block)
544
582
  host_name opts[:host] if opts.key?(:host)
545
583
  user_agent opts[:agent] if opts.key?(:agent)
546
584
  accept_mime_types opts[:provides] if opts.key?(:provides)
547
585
 
548
586
  pattern, keys = compile(path)
549
587
  conditions, @conditions = @conditions, []
550
- (routes[method] ||= []).
551
- push [pattern, keys, conditions, block]
588
+
589
+ define_method "#{verb} #{path}", &block
590
+ unbound_method = instance_method("#{verb} #{path}")
591
+ block = lambda { unbound_method.bind(self).call }
592
+
593
+ (routes[verb] ||= []).
594
+ push([pattern, keys, conditions, block]).last
552
595
  end
553
596
 
554
597
  def compile(path)
@@ -647,6 +690,7 @@ module Sinatra
647
690
  end
648
691
 
649
692
  set :raise_errors, true
693
+ set :dump_errors, false
650
694
  set :sessions, false
651
695
  set :logging, false
652
696
  set :methodoverride, false
@@ -740,6 +784,7 @@ module Sinatra
740
784
 
741
785
  class Default < Base
742
786
  set :raise_errors, false
787
+ set :dump_errors, true
743
788
  set :sessions, false
744
789
  set :logging, true
745
790
  set :methodoverride, true
@@ -763,6 +808,7 @@ module Sinatra
763
808
  def self.reload!
764
809
  @reloading = true
765
810
  superclass.send :inherited, self
811
+ $LOADED_FEATURES.delete("sinatra.rb")
766
812
  ::Kernel.load app_file
767
813
  @reloading = false
768
814
  end
@@ -1,58 +1,102 @@
1
+ # Sinatra 0.3.x compatibility module.
2
+ #
3
+ # The following code makes Sinatra 0.9.x compatible with Sinatra 0.3.x to
4
+ # ease the transition to the final 1.0 release. Everything defined in this
5
+ # file will be removed for the 1.0 release.
6
+
1
7
  require 'ostruct'
2
8
  require 'sinatra/base'
3
9
  require 'sinatra/main'
4
10
 
5
- # Deprecated. Do we still need this?
11
+ # Like Kernel#warn but outputs the location that triggered the warning.
12
+ def sinatra_warn(*message)
13
+ line = caller.
14
+ detect { |line| line !~ /(?:lib\/sinatra\/|__DELEGATE__)/ }.
15
+ sub(/:in .*/, '')
16
+ warn "#{line}: warning: #{message.join(' ')}"
17
+ end
18
+
19
+ # Rack now supports evented and swiftiplied mongrels through separate
20
+ # handler.
6
21
  if ENV['SWIFT']
22
+ sinatra_warn 'the SWIFT environment variable is deprecated;',
23
+ 'use Rack::Handler::SwiftipliedMongrel instead.'
7
24
  require 'swiftcore/swiftiplied_mongrel'
8
25
  puts "Using Swiftiplied Mongrel"
9
26
  elsif ENV['EVENT']
27
+ sinatra_warn 'the EVENT environment variable is deprecated;',
28
+ 'use Rack::Handler::EventedMongrel instead.'
10
29
  require 'swiftcore/evented_mongrel'
11
30
  puts "Using Evented Mongrel"
12
31
  end
13
32
 
14
- # Deprecated. Make Rack 0.9.0 backward compatibile with 0.4.0
15
- # mime types
33
+ # Make Rack 0.9.0 backward compatibile with 0.4.0 mime types. This isn't
34
+ # technically a Sinatra issue but many Sinatra apps access the old
35
+ # MIME_TYPES constants due to Sinatra example code.
16
36
  require 'rack/file'
17
37
  class Rack::File
18
- unless defined? MIME_TYPES
19
- MIME_TYPES = Hash.new {|hash,key|
20
- Rack::Mime::MIME_TYPES[".#{key}"] }
38
+ def self.const_missing(const_name)
39
+ if const_name == :MIME_TYPES
40
+ hash = Hash.new { |hash,key| Rack::Mime::MIME_TYPES[".#{key}"] }
41
+ const_set :MIME_TYPES, hash
42
+ sinatra_warn 'Rack::File::MIME_TYPES is deprecated; use Rack::Mime instead.'
43
+ hash
44
+ else
45
+ super
46
+ end
21
47
  end
22
48
  end
23
49
 
24
- # Deprecated. Rack::Utils will not extend itself in the future. Sinatra::Base
25
- # includes Rack::Utils, however.
26
- module Rack::Utils ; extend self ; end
27
-
28
50
  module Sinatra
29
51
  module Compat
30
52
  end
31
53
 
32
- # Deprecated. Use: error
54
+ # The ServerError exception is deprecated. Any exception is considered an
55
+ # internal server error.
33
56
  class ServerError < RuntimeError
57
+ def initialize(*args, &block)
58
+ sinatra_warn 'Sinatra::ServerError is deprecated;',
59
+ 'use another exception, error, or Kernel#fail instead.'
60
+ end
34
61
  def code ; 500 ; end
35
62
  end
36
63
 
37
64
  class Default < Base
38
- # Deprecated.
39
- FORWARD_METHODS = Sinatra::Delegator::METHODS
65
+ def self.const_missing(const_name)
66
+ if const_name == :FORWARD_METHODS
67
+ sinatra_warn 'Sinatra::Application::FORWARD_METHODS is deprecated;',
68
+ 'use Sinatra::Delegator::METHODS instead.'
69
+ const_set :FORWARD_METHODS, Sinatra::Delegator::METHODS
70
+ Sinatra::Delegator::METHODS
71
+ else
72
+ super
73
+ end
74
+ end
40
75
 
41
76
  # Deprecated. Use: response['Header-Name']
42
77
  def headers(header=nil)
78
+ sinatra_warn "The 'headers' method is deprecated; use 'response' instead."
43
79
  response.headers.merge!(header) if header
44
80
  response.headers
45
81
  end
46
82
  alias :header :headers
47
83
 
48
84
  # Deprecated. Use: halt
49
- alias :stop :halt
85
+ def stop(*args, &block)
86
+ sinatra_warn "The 'stop' method is deprecated; use 'halt' instead."
87
+ halt(*args, &block)
88
+ end
50
89
 
51
90
  # Deprecated. Use: etag
52
- alias :entity_tag :etag
91
+ def entity_tag(*args, &block)
92
+ sinatra_warn "The 'entity_tag' method is deprecated; use 'etag' instead."
93
+ etag(*args, &block)
94
+ end
53
95
 
54
96
  # The :disposition option is deprecated; use: #attachment. This method
55
97
  # setting the Content-Transfer-Encoding header is deprecated.
98
+ #--
99
+ # TODO deprecation warning for :disposition argument.
56
100
  def send_file(path, opts={})
57
101
  opts[:disposition] = 'attachment' if !opts.key?(:disposition)
58
102
  attachment opts[:filename] || path if opts[:filename] || opts[:disposition]
@@ -60,48 +104,89 @@ module Sinatra
60
104
  super(path, opts)
61
105
  end
62
106
 
63
- def options ; self.class.options ; end
107
+ # Throwing halt with a Symbol and the to_result convention are
108
+ # deprecated. Override the invoke method to detect those types of return
109
+ # values.
110
+ def invoke(handler)
111
+ res = super
112
+ case
113
+ when res.kind_of?(Symbol)
114
+ sinatra_warn "Invoking the :#{res} helper by returning a Symbol is deprecated;",
115
+ "call the helper directly instead."
116
+ @response.body = __send__(res)
117
+ when res.respond_to?(:to_result)
118
+ sinatra_warn "The to_result convention is deprecated."
119
+ @response.body = res.to_result(self)
120
+ end
121
+ res
122
+ end
123
+
124
+ def options
125
+ Options.new(self.class)
126
+ end
127
+
128
+ class Options < Struct.new(:target) #:nodoc:
129
+ def method_missing(name, *args, &block)
130
+ if target.respond_to?(name)
131
+ target.__send__(name, *args, &block)
132
+ elsif args.empty? && name.to_s !~ /=$/
133
+ sinatra_warn 'accessing undefined options will raise a NameError in Sinatra 1.0'
134
+ nil
135
+ else
136
+ super
137
+ end
138
+ end
139
+ end
64
140
 
65
141
  class << self
66
142
  # Deprecated. Options are stored directly on the class object.
67
- def options ; Options.new(self) ; end
68
-
69
- class Options < Struct.new(:target) #:nodoc:
70
- def method_missing(name, *args, &block)
71
- if target.respond_to?(name)
72
- target.__send__(name, *args, &block)
73
- elsif args.empty? && name.to_s !~ /=$/
74
- nil
75
- else
76
- super
77
- end
78
- end
143
+ def options
144
+ sinatra_warn "The 'options' class method is deprecated; use 'self' instead."
145
+ Options.new(self)
79
146
  end
80
147
 
81
148
  # Deprecated. Use: configure
82
- alias :configures :configure
149
+ def configures(*args, &block)
150
+ sinatra_warn "The 'configures' method is deprecated; use 'configure' instead."
151
+ configure(*args, &block)
152
+ end
83
153
 
84
154
  # Deprecated. Use: set
85
155
  def default_options
156
+ sinatra_warn "Sinatra::Application.default_options is deprecated; use 'set' instead."
86
157
  fake = lambda { |options| set(options) }
87
158
  def fake.merge!(options) ; call(options) ; end
88
159
  fake
89
160
  end
90
161
 
91
162
  # Deprecated. Use: set
92
- alias :set_option :set
93
- alias :set_options :set
163
+ def set_option(*args, &block)
164
+ sinatra_warn "The 'set_option' method is deprecated; use 'set' instead."
165
+ set(*args, &block)
166
+ end
167
+
168
+ def set_options(*args, &block)
169
+ sinatra_warn "The 'set_options' method is deprecated; use 'set' instead."
170
+ set(*args, &block)
171
+ end
94
172
 
95
173
  # Deprecated. Use: set :environment, ENV
96
174
  def env=(value)
175
+ sinatra_warn "The :env option is deprecated; use :environment instead."
97
176
  set :environment, value
98
177
  end
99
- alias :env :environment
178
+
179
+ # Deprecated. Use: options.environment
180
+ def env
181
+ sinatra_warn "The :env option is deprecated; use :environment instead."
182
+ environment
183
+ end
100
184
  end
101
185
 
102
186
  # Deprecated. Missing messages are no longer delegated to @response.
103
187
  def method_missing(name, *args, &b)
104
188
  if @response.respond_to?(name)
189
+ sinatra_warn "The '#{name}' method is deprecated; use 'response.#{name}' instead."
105
190
  @response.send(name, *args, &b)
106
191
  else
107
192
  super
@@ -112,30 +197,43 @@ module Sinatra
112
197
  class << self
113
198
  # Deprecated. Use: Sinatra::Application
114
199
  def application
200
+ sinatra_warn "Sinatra.application is deprecated; use Sinatra::Application instead."
115
201
  Sinatra::Application
116
202
  end
117
203
 
118
- # Deprecated. Use: error 404
119
- def not_found(&block)
120
- error 404, &block
121
- end
122
-
123
204
  # Deprecated. Use: Sinatra::Application.reset!
124
205
  def application=(value)
125
206
  raise ArgumentError unless value.nil?
207
+ sinatra_warn "Setting Sinatra.application to nil is deprecated; create a new instance instead."
126
208
  Sinatra.class_eval do
127
209
  remove_const :Application
128
210
  const_set :Application, Class.new(Sinatra::Default)
129
211
  end
130
212
  end
131
213
 
132
- # Deprecated. Use: Sinatra::Application
133
- alias :build_application :application
214
+ def build_application
215
+ sinatra_warn "Sinatra.build_application is deprecated; use Sinatra::Application instead."
216
+ Sinatra::Application
217
+ end
134
218
 
135
- # Deprecated.
136
- def options ; Sinatra::Application.options ; end
137
- def port ; options.port ; end
138
- def host ; options.host ; end
139
- def env ; options.environment ; end
219
+ def options
220
+ sinatra_warn "Sinatra.options is deprecated; use Sinatra::Application.option_name instead."
221
+ Sinatra::Application.options
222
+ end
223
+
224
+ def port
225
+ sinatra_warn "Sinatra.port is deprecated; use Sinatra::Application.port instead."
226
+ options.port
227
+ end
228
+
229
+ def host
230
+ sinatra_warn "Sinatra.host is deprecated; use Sinatra::Application.host instead."
231
+ options.host
232
+ end
233
+
234
+ def env
235
+ sinatra_warn "Sinatra.env is deprecated; use Sinatra::Application.environment instead."
236
+ options.environment
237
+ end
140
238
  end
141
239
  end
@@ -0,0 +1,17 @@
1
+ require 'bacon'
2
+ require 'sinatra/test'
3
+
4
+ Sinatra::Default.set(
5
+ :env => :test,
6
+ :run => false,
7
+ :raise_errors => true,
8
+ :logging => false
9
+ )
10
+
11
+ module Sinatra::Test
12
+ def should
13
+ @response.should
14
+ end
15
+ end
16
+
17
+ Bacon::Context.send(:include, Sinatra::Test)
@@ -1,2 +1,9 @@
1
1
  require 'sinatra/test'
2
2
  require 'spec/interop/test'
3
+
4
+ Sinatra::Default.set(
5
+ :env => :test,
6
+ :run => false,
7
+ :raise_errors => true,
8
+ :logging => false
9
+ )
@@ -1,2 +1,9 @@
1
1
  require 'test/spec'
2
2
  require 'sinatra/test'
3
+ require 'sinatra/test/unit'
4
+
5
+ module Sinatra::Test
6
+ def should
7
+ @response.should
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
- require 'test/unit'
2
1
  require 'sinatra/test'
2
+ require 'test/unit'
3
3
 
4
4
  Test::Unit::TestCase.send :include, Sinatra::Test
5
5