bmizerany-sinatra 0.9.0 → 0.9.0.2

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