bmizerany-sinatra 0.9.0.4 → 0.9.0.5

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/AUTHORS CHANGED
@@ -1,7 +1,7 @@
1
1
  Sinatra was designed and developed by Blake Mizerany (bmizerany) in
2
2
  California. Continued development would not be possible without the ongoing
3
3
  financial support provided by [Heroku](http://heroku.com) and the emotional
4
- support provided by Adam Wiggins (adamwiggins), Chris Wanstrath (defunkt),
4
+ support provided by Adam Wiggins (adamwiggins) of Heroku, Chris Wanstrath (defunkt),
5
5
  PJ Hyett (pjhyett), and the rest of the GitHub crew.
6
6
 
7
7
  Special thanks to the following extraordinary individuals, who-out which
data/CHANGES CHANGED
@@ -1,3 +1,47 @@
1
+ = 0.9.1 / unreleased
2
+
3
+ * Sinatra now runs under Ruby 1.9.1 [#61]
4
+ * Route patterns (splats, :named, or Regexp captures) are now
5
+ passed as arguments to the block. [#140]
6
+ * The "helpers" method now takes a variable number of modules
7
+ along with the normal block syntax. [#133]
8
+ * New simple API for extensions/plugins to add DSL-level and
9
+ request-level methods. Use Sinatra.register(mixin) to extend
10
+ the DSL with all public methods defined in the mixin module;
11
+ use Sinatra.helpers(mixin) to make all public methods defined
12
+ in the mixin module available at the request level. [#138]
13
+ * Added "redirect back" to redirect to the referring URL.
14
+ * Added a new "clean_trace" option that causes backtraces dumped
15
+ to rack.errors and displayed on the development error page to
16
+ omit framework and core library backtrace lines. The option is
17
+ enabled by default. [#77]
18
+ * Fix :provides causing crash on any request when request has no
19
+ Accept header [#139]
20
+ * Fix that ERB templates were evaluated twice per "erb" call.
21
+
22
+ = 0.9.0.4 / 2009-01-25
23
+
24
+ * Using halt with more than 1 args causes ArgumentError [#131]
25
+ * using halt in a before filter doesn't modify response [#127]
26
+ * Add deprecated Sinatra::EventContext to unbreak plugins [#130]
27
+ * Give access to GET/POST params in filters [#129]
28
+ * Preserve non-nested params in nested params hash [#117]
29
+ * Fix backtrace dump with Rack::Lint [#116]
30
+
31
+ = 0.9.0.3 / 2009-01-21
32
+
33
+ * Fall back on mongrel then webrick when thin not found. [#75]
34
+ * Use :environment instead of :env in test helpers to
35
+ fix deprecation warnings coming from framework.
36
+ * Make sinatra/test/rspec work again [#113]
37
+ * Fix app_file detection on windows [#118]
38
+ * Fix static files with Rack::Lint in pipeline [#121]
39
+
40
+ = 0.9.0.2 / 2009-01-18
41
+
42
+ * Halting a before block should stop processing of routes [#85]
43
+ * Fix redirect/halt in before filters [#85]
44
+
1
45
  = 0.9.0 / 2009-01-18
2
46
 
3
47
  * Works with and requires Rack >= 0.9.1
data/README.rdoc CHANGED
@@ -50,6 +50,12 @@ Route patterns may include named parameters, accessible via the
50
50
  "Hello #{params[:name]}!"
51
51
  end
52
52
 
53
+ You can also access named parameters via block parameters:
54
+
55
+ get '/hello/:name' do |n|
56
+ "Hello #{n}!"
57
+ end
58
+
53
59
  Route patterns may also include splat (or wildcard) parameters, accessible
54
60
  via the <tt>params[:splat]</tt> array.
55
61
 
@@ -69,6 +75,12 @@ Route matching with Regular Expressions:
69
75
  "Hello, #{params[:captures].first}!"
70
76
  end
71
77
 
78
+ Or with a block parameter:
79
+
80
+ get %r{/hello/([\w]+)} do |c|
81
+ "Hello, #{c}!"
82
+ end
83
+
72
84
  Routes may include a variety of matching conditions, such as the user agent:
73
85
 
74
86
  get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake/clean'
2
2
  require 'rake/testtask'
3
3
  require 'fileutils'
4
4
 
5
- task :default => :test
5
+ task :default => [:test]
6
6
  task :spec => :test
7
7
 
8
8
  # SPECS ===============================================================
@@ -45,6 +45,7 @@ task :install => package('.gem') do
45
45
  end
46
46
 
47
47
  directory 'dist/'
48
+ CLOBBER.include('dist')
48
49
 
49
50
  file package('.gem') => %w[dist/ sinatra.gemspec] + spec.files do |f|
50
51
  sh "gem build sinatra.gemspec"
data/compat/app_test.rb CHANGED
@@ -8,8 +8,9 @@ context "Sinatra" do
8
8
 
9
9
  specify "should put all DSL methods on (main)" do
10
10
  object = Object.new
11
- Sinatra::Application::FORWARD_METHODS.each do |method|
12
- object.private_methods.should.include(method)
11
+ methods = %w[get put post head delete configure template helpers set]
12
+ methods.each do |method|
13
+ object.private_methods.map { |m| m.to_sym }.should.include(method.to_sym)
13
14
  end
14
15
  end
15
16
 
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ context "Compat" do
4
+ setup do
5
+ Sinatra.application = nil
6
+ @app = Sinatra.application
7
+ end
8
+
9
+ specify "makes EventContext available" do
10
+ assert_same Sinatra::Default, Sinatra::EventContext
11
+ end
12
+ end
data/lib/sinatra/base.rb CHANGED
@@ -1,18 +1,21 @@
1
+ require 'thread'
1
2
  require 'time'
2
3
  require 'uri'
3
4
  require 'rack'
4
5
  require 'rack/builder'
5
6
 
6
7
  module Sinatra
7
- VERSION = '0.9.0.2'
8
+ VERSION = '0.9.0.5'
8
9
 
10
+ # The request object. See Rack::Request for more info:
11
+ # http://rack.rubyforge.org/doc/classes/Rack/Request.html
9
12
  class Request < Rack::Request
10
13
  def user_agent
11
14
  @env['HTTP_USER_AGENT']
12
15
  end
13
16
 
14
17
  def accept
15
- @env['HTTP_ACCEPT'].split(',').map { |a| a.strip }
18
+ @env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.strip }
16
19
  end
17
20
 
18
21
  # Override Rack 0.9.x's #params implementation (see #72 in lighthouse)
@@ -23,6 +26,10 @@ module Sinatra
23
26
  end
24
27
  end
25
28
 
29
+ # The response object. See Rack::Response and Rack::ResponseHelpers for
30
+ # more info:
31
+ # http://rack.rubyforge.org/doc/classes/Rack/Response.html
32
+ # http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
26
33
  class Response < Rack::Response
27
34
  def initialize
28
35
  @status, @body = 200, []
@@ -44,17 +51,18 @@ module Sinatra
44
51
  body = [body] if body.respond_to? :to_str
45
52
  if header["Content-Length"].nil? && body.respond_to?(:to_ary)
46
53
  header["Content-Length"] = body.to_ary.
47
- inject(0) { |len, part| len + part.length }.to_s
54
+ inject(0) { |len, part| len + part.bytesize }.to_s
48
55
  end
49
56
  [status.to_i, header.to_hash, body]
50
57
  end
51
58
  end
52
59
  end
53
60
 
54
- class NotFound < NameError # :)
61
+ class NotFound < NameError #:nodoc:
55
62
  def code ; 404 ; end
56
63
  end
57
64
 
65
+ # Methods available to routes, before filters, and views.
58
66
  module Helpers
59
67
  # Set or retrieve the response status code.
60
68
  def status(value=nil)
@@ -82,7 +90,7 @@ module Sinatra
82
90
 
83
91
  # Halt processing and return the error status provided.
84
92
  def error(code, body=nil)
85
- code, body = 500, code.to_str if code.respond_to? :to_str
93
+ code, body = 500, code.to_str if code.respond_to? :to_str
86
94
  response.body = body unless body.nil?
87
95
  halt code
88
96
  end
@@ -194,11 +202,42 @@ module Sinatra
194
202
  halt 304 if etags.include?(value) || etags.include?('*')
195
203
  end
196
204
  end
205
+
206
+ ## Sugar for redirect (example: redirect back)
207
+ def back ; request.referer ; end
208
+
197
209
  end
198
210
 
211
+ # Template rendering methods. Each method takes a the name of a template
212
+ # to render as a Symbol and returns a String with the rendered output.
199
213
  module Templates
200
- def render(engine, template, options={})
201
- data = lookup_template(engine, template, options)
214
+ def erb(template, options={})
215
+ require 'erb' unless defined? ::ERB
216
+ render :erb, template, options
217
+ end
218
+
219
+ def haml(template, options={})
220
+ require 'haml' unless defined? ::Haml
221
+ options[:options] ||= self.class.haml if self.class.respond_to? :haml
222
+ render :haml, template, options
223
+ end
224
+
225
+ def sass(template, options={}, &block)
226
+ require 'sass' unless defined? ::Sass
227
+ options[:layout] = false
228
+ render :sass, template, options
229
+ end
230
+
231
+ def builder(template=nil, options={}, &block)
232
+ require 'builder' unless defined? ::Builder
233
+ options, template = template, nil if template.is_a?(Hash)
234
+ template = lambda { block } if template.nil?
235
+ render :builder, template, options
236
+ end
237
+
238
+ private
239
+ def render(engine, template, options={}) #:nodoc:
240
+ data = lookup_template(engine, template, options)
202
241
  output = __send__("render_#{engine}", template, data, options)
203
242
  layout, data = lookup_layout(engine, options)
204
243
  if layout
@@ -229,7 +268,7 @@ module Sinatra
229
268
  return if options[:layout] == false
230
269
  options.delete(:layout) if options[:layout] == true
231
270
  template = options[:layout] || :layout
232
- data = lookup_template(engine, template, options)
271
+ data = lookup_template(engine, template, options)
233
272
  [template, data]
234
273
  rescue Errno::ENOENT
235
274
  nil
@@ -241,11 +280,6 @@ module Sinatra
241
280
  "#{views_dir}/#{template}.#{engine}"
242
281
  end
243
282
 
244
- def erb(template, options={})
245
- require 'erb' unless defined? ::ERB
246
- render :erb, template, options
247
- end
248
-
249
283
  def render_erb(template, data, options, &block)
250
284
  data = data.call if data.kind_of? Proc
251
285
  instance = ::ERB.new(data)
@@ -253,13 +287,6 @@ module Sinatra
253
287
  locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
254
288
  src = "#{locals_assigns.join("\n")}\n#{instance.src}"
255
289
  eval src, binding, '(__ERB__)', locals_assigns.length + 1
256
- instance.result(binding)
257
- end
258
-
259
- def haml(template, options={})
260
- require 'haml' unless defined? ::Haml
261
- options[:options] ||= self.class.haml if self.class.respond_to? :haml
262
- render :haml, template, options
263
290
  end
264
291
 
265
292
  def render_haml(template, data, options, &block)
@@ -267,24 +294,11 @@ module Sinatra
267
294
  engine.render(self, options[:locals] || {}, &block)
268
295
  end
269
296
 
270
- def sass(template, options={}, &block)
271
- require 'sass' unless defined? ::Sass
272
- options[:layout] = false
273
- render :sass, template, options
274
- end
275
-
276
297
  def render_sass(template, data, options, &block)
277
298
  engine = ::Sass::Engine.new(data, options[:sass] || {})
278
299
  engine.render
279
300
  end
280
301
 
281
- def builder(template=nil, options={}, &block)
282
- require 'builder' unless defined? ::Builder
283
- options, template = template, nil if template.is_a?(Hash)
284
- template = lambda { block } if template.nil?
285
- render :builder, template, options
286
- end
287
-
288
302
  def render_builder(template, data, options, &block)
289
303
  xml = ::Builder::XmlMarkup.new(:indent => 2)
290
304
  if data.respond_to?(:to_str)
@@ -294,9 +308,9 @@ module Sinatra
294
308
  end
295
309
  xml.target!
296
310
  end
297
-
298
311
  end
299
312
 
313
+ # Base class for all Sinatra applications and middleware.
300
314
  class Base
301
315
  include Rack::Utils
302
316
  include Helpers
@@ -309,6 +323,7 @@ module Sinatra
309
323
  yield self if block_given?
310
324
  end
311
325
 
326
+ # Rack call interface.
312
327
  def call(env)
313
328
  dup.call!(env)
314
329
  end
@@ -324,19 +339,24 @@ module Sinatra
324
339
  invoke { dispatch! }
325
340
  invoke { error_block!(response.status) }
326
341
 
342
+ # never respond with a body on HEAD requests
327
343
  @response.body = [] if @env['REQUEST_METHOD'] == 'HEAD'
344
+
328
345
  @response.finish
329
346
  end
330
347
 
348
+ # Access options defined with Base.set.
331
349
  def options
332
350
  self.class
333
351
  end
334
352
 
353
+ # Exit the current block and halt the response.
335
354
  def halt(*response)
336
355
  response = response.first if response.length == 1
337
356
  throw :halt, response
338
357
  end
339
358
 
359
+ # Pass control to the next matching route.
340
360
  def pass
341
361
  throw :pass
342
362
  end
@@ -352,7 +372,7 @@ module Sinatra
352
372
  # routes
353
373
  if routes = self.class.routes[@request.request_method]
354
374
  original_params = @params
355
- path = @request.path_info
375
+ path = @request.path_info
356
376
 
357
377
  routes.each do |pattern, keys, conditions, block|
358
378
  if match = pattern.match(path)
@@ -373,6 +393,7 @@ module Sinatra
373
393
  {}
374
394
  end
375
395
  @params = original_params.merge(params)
396
+ @block_params = values
376
397
 
377
398
  catch(:pass) do
378
399
  conditions.each { |cond|
@@ -421,7 +442,7 @@ module Sinatra
421
442
  headers.each { |k, v| @response.headers[k] = v } if headers
422
443
  elsif res.length == 2
423
444
  @response.status = res.first
424
- @response.body = res.last
445
+ @response.body = res.last
425
446
  else
426
447
  raise TypeError, "#{res.inspect} not supported"
427
448
  end
@@ -441,21 +462,24 @@ module Sinatra
441
462
  def dispatch!
442
463
  route!
443
464
  rescue NotFound => boom
465
+ handle_not_found!(boom)
466
+ rescue ::Exception => boom
467
+ handle_exception!(boom)
468
+ end
469
+
470
+ def handle_not_found!(boom)
444
471
  @env['sinatra.error'] = boom
445
- @response.status = 404
446
- @response.body = ['<h1>Not Found</h1>']
472
+ @response.status = 404
473
+ @response.body = ['<h1>Not Found</h1>']
447
474
  error_block! boom.class, NotFound
475
+ end
448
476
 
449
- rescue ::Exception => boom
477
+ def handle_exception!(boom)
450
478
  @env['sinatra.error'] = boom
451
479
 
452
- if options.dump_errors?
453
- backtrace = clean_backtrace(boom.backtrace)
454
- msg = ["#{boom.class} - #{boom.message}:", *backtrace].join("\n ")
455
- @env['rack.errors'].write(msg)
456
- end
480
+ dump_errors!(boom) if options.dump_errors?
481
+ raise boom if options.raise_errors?
457
482
 
458
- raise boom if options.raise_errors?
459
483
  @response.status = 500
460
484
  error_block! boom.class, Exception
461
485
  end
@@ -472,6 +496,13 @@ module Sinatra
472
496
  nil
473
497
  end
474
498
 
499
+ def dump_errors!(boom)
500
+ backtrace = clean_backtrace(boom.backtrace)
501
+ msg = ["#{boom.class} - #{boom.message}:",
502
+ *backtrace].join("\n ")
503
+ @env['rack.errors'].write(msg)
504
+ end
505
+
475
506
  def clean_backtrace(trace)
476
507
  return trace unless options.clean_trace?
477
508
 
@@ -493,13 +524,14 @@ module Sinatra
493
524
  attr_accessor :routes, :filters, :conditions, :templates,
494
525
  :middleware, :errors
495
526
 
527
+ public
496
528
  def set(option, value=self)
497
529
  if value.kind_of?(Proc)
498
530
  metadef(option, &value)
499
531
  metadef("#{option}?") { !!__send__(option) }
500
532
  metadef("#{option}=") { |val| set(option, Proc.new{val}) }
501
533
  elsif value == self && option.respond_to?(:to_hash)
502
- option.to_hash.each(&method(:set))
534
+ option.to_hash.each { |k,v| set(k, v) }
503
535
  elsif respond_to?("#{option}=")
504
536
  __send__ "#{option}=", value
505
537
  else
@@ -537,14 +569,10 @@ module Sinatra
537
569
  end
538
570
 
539
571
  def use_in_file_templates!
540
- line = caller.detect do |s|
541
- [
542
- /lib\/sinatra.*\.rb/,
543
- /\(.*\)/,
544
- /rubygems\/custom_require\.rb/
545
- ].all? { |x| s !~ x }
546
- end
547
- file = line.sub(/:\d+.*$/, '')
572
+ ignore = [/lib\/sinatra.*\.rb/, /\(.*\)/, /rubygems\/custom_require\.rb/]
573
+ file = caller.
574
+ map { |line| line.sub(/:\d+.*$/, '') }.
575
+ find { |line| ignore.all? { |pattern| line !~ pattern } }
548
576
  if data = ::IO.read(file).split('__END__')[1]
549
577
  data.gsub!(/\r\n/, "\n")
550
578
  template = nil
@@ -573,6 +601,7 @@ module Sinatra
573
601
  @conditions << block
574
602
  end
575
603
 
604
+ private
576
605
  def host_name(pattern)
577
606
  condition { pattern === request.host }
578
607
  end
@@ -603,6 +632,7 @@ module Sinatra
603
632
  }
604
633
  end
605
634
 
635
+ public
606
636
  def get(path, opts={}, &block)
607
637
  conditions = @conditions.dup
608
638
  route('GET', path, opts, &block)
@@ -627,7 +657,12 @@ module Sinatra
627
657
 
628
658
  define_method "#{verb} #{path}", &block
629
659
  unbound_method = instance_method("#{verb} #{path}")
630
- block = lambda { unbound_method.bind(self).call }
660
+ block =
661
+ if block.arity != 0
662
+ lambda { unbound_method.bind(self).call(*@block_params) }
663
+ else
664
+ lambda { unbound_method.bind(self).call }
665
+ end
631
666
 
632
667
  (routes[verb] ||= []).
633
668
  push([pattern, keys, conditions, block]).last
@@ -659,11 +694,22 @@ module Sinatra
659
694
  end
660
695
 
661
696
  public
697
+ def helpers(*extensions, &block)
698
+ class_eval(&block) if block_given?
699
+ include *extensions
700
+ end
701
+
702
+ def register(*extensions, &block)
703
+ extensions << Module.new(&block) if block
704
+ extend *extensions
705
+ end
706
+
662
707
  def development? ; environment == :development ; end
663
708
  def test? ; environment == :test ; end
664
709
  def production? ; environment == :production ; end
665
710
 
666
711
  def configure(*envs, &block)
712
+ return if reloading?
667
713
  yield if envs.empty? || envs.include?(environment.to_sym)
668
714
  end
669
715
 
@@ -674,7 +720,7 @@ module Sinatra
674
720
 
675
721
  def run!(options={})
676
722
  set options
677
- handler = detect_rack_handler
723
+ handler = detect_rack_handler
678
724
  handler_name = handler.name.gsub(/.*::/, '')
679
725
  puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
680
726
  "on #{port} for #{environment} with backup from #{handler_name}"
@@ -690,8 +736,19 @@ module Sinatra
690
736
  end
691
737
 
692
738
  def call(env)
693
- construct_middleware if @callsite.nil?
694
- @callsite.call(env)
739
+ synchronize do
740
+ reload! if reload?
741
+ construct_middleware if @callsite.nil?
742
+ @callsite.call(env)
743
+ end
744
+ end
745
+
746
+ def reload!
747
+ @reloading = true
748
+ superclass.send :reset!, self
749
+ $LOADED_FEATURES.delete("sinatra.rb")
750
+ ::Kernel.load app_file
751
+ @reloading = false
695
752
  end
696
753
 
697
754
  private
@@ -720,17 +777,34 @@ module Sinatra
720
777
  @callsite = nil
721
778
  end
722
779
 
723
- def inherited(subclass)
724
- subclass.routes = dupe_routes
725
- subclass.templates = templates.dup
780
+ def reset!(subclass = self)
781
+ subclass.routes = dupe_routes
782
+ subclass.templates = templates.dup
726
783
  subclass.conditions = []
727
- subclass.filters = filters.dup
728
- subclass.errors = errors.dup
784
+ subclass.filters = filters.dup
785
+ subclass.errors = errors.dup
729
786
  subclass.middleware = middleware.dup
730
787
  subclass.send :reset_middleware
788
+ end
789
+
790
+ def inherited(subclass)
791
+ reset!(subclass)
731
792
  super
732
793
  end
733
794
 
795
+ def reloading?
796
+ @reloading ||= false
797
+ end
798
+
799
+ @@mutex = Mutex.new
800
+ def synchronize(&block)
801
+ if lock?
802
+ @@mutex.synchronize(&block)
803
+ else
804
+ yield
805
+ end
806
+ end
807
+
734
808
  def dupe_routes
735
809
  routes.inject({}) do |hash,(request_method,routes)|
736
810
  hash[request_method] = routes.dup
@@ -762,6 +836,8 @@ module Sinatra
762
836
  set :root, Proc.new { app_file && File.expand_path(File.dirname(app_file)) }
763
837
  set :views, Proc.new { root && File.join(root, 'views') }
764
838
  set :public, Proc.new { root && File.join(root, 'public') }
839
+ set :reload, Proc.new { app_file? && app_file !~ /\.ru$/i && development? }
840
+ set :lock, Proc.new { reload? }
765
841
 
766
842
  # static files route
767
843
  get(/.*[^\/]$/) do
@@ -838,6 +914,7 @@ module Sinatra
838
914
  end
839
915
  end
840
916
 
917
+ # Base class for classic style (top-level) applications.
841
918
  class Default < Base
842
919
  set :raise_errors, false
843
920
  set :dump_errors, true
@@ -846,61 +923,35 @@ module Sinatra
846
923
  set :methodoverride, true
847
924
  set :static, true
848
925
  set :run, false
849
- set :reload, Proc.new { app_file? && app_file !~ /\.ru$/i && development? }
850
- set :lock, Proc.new { reload? }
851
926
 
852
- def self.reloading?
853
- @reloading ||= false
854
- end
855
-
856
- def self.configure(*envs)
857
- super unless reloading?
858
- end
859
-
860
- def self.call(env)
861
- synchronize do
862
- reload! if reload?
863
- super
864
- end
865
- end
866
-
867
- def self.reload!
868
- @reloading = true
869
- superclass.send :inherited, self
870
- $LOADED_FEATURES.delete("sinatra.rb")
871
- ::Kernel.load app_file
872
- @reloading = false
873
- end
874
-
875
- private
876
- @@mutex = Mutex.new
877
- def self.synchronize(&block)
878
- if lock?
879
- @@mutex.synchronize(&block)
880
- else
881
- yield
882
- end
927
+ def self.register(*extensions, &block) #:nodoc:
928
+ added_methods = extensions.map {|m| m.public_instance_methods }.flatten
929
+ Delegator.delegate *added_methods
930
+ super(*extensions, &block)
883
931
  end
884
932
  end
885
933
 
934
+ # The top-level Application. All DSL methods executed on main are delegated
935
+ # to this class.
886
936
  class Application < Default
887
937
  end
888
938
 
889
- module Delegator
890
- METHODS = %w[
891
- get put post delete head template layout before error not_found
892
- configures configure set set_option set_options enable disable use
893
- development? test? production? use_in_file_templates!
894
- ]
895
-
896
- METHODS.each do |method_name|
897
- eval <<-RUBY, binding, '(__DELEGATE__)', 1
898
- def #{method_name}(*args, &b)
899
- ::Sinatra::Application.#{method_name}(*args, &b)
900
- end
901
- private :#{method_name}
902
- RUBY
939
+ module Delegator #:nodoc:
940
+ def self.delegate(*methods)
941
+ methods.each do |method_name|
942
+ eval <<-RUBY, binding, '(__DELEGATE__)', 1
943
+ def #{method_name}(*args, &b)
944
+ ::Sinatra::Application.#{method_name}(*args, &b)
945
+ end
946
+ private :#{method_name}
947
+ RUBY
948
+ end
903
949
  end
950
+
951
+ delegate :get, :put, :post, :delete, :head, :template, :layout, :before,
952
+ :error, :not_found, :configures, :configure, :set, :set_option,
953
+ :set_options, :enable, :disable, :use, :development?, :test?,
954
+ :production?, :use_in_file_templates!, :helpers
904
955
  end
905
956
 
906
957
  def self.new(base=Base, options={}, &block)
@@ -908,4 +959,47 @@ module Sinatra
908
959
  base.send :class_eval, &block if block_given?
909
960
  base
910
961
  end
962
+
963
+ # Extend the top-level DSL with the modules provided.
964
+ def self.register(*extensions, &block)
965
+ Default.register(*extensions, &block)
966
+ end
967
+
968
+ # Include the helper modules provided in Sinatra's request context.
969
+ def self.helpers(*extensions, &block)
970
+ Default.helpers(*extensions, &block)
971
+ end
972
+ end
973
+
974
+ class String #:nodoc:
975
+ # Define String#each under 1.9 for Rack compatibility. This should be
976
+ # removed once Rack is fully 1.9 compatible.
977
+ alias_method :each, :each_line unless ''.respond_to? :each
978
+
979
+ # Define String#bytesize as an alias to String#length for Ruby 1.8.6 and
980
+ # earlier.
981
+ alias_method :bytesize, :length unless ''.respond_to? :bytesize
982
+ end
983
+
984
+ class Rack::Builder
985
+ ## Sugar to include a classic style app in a rackup.
986
+ ##
987
+ ## This will eval the source into a Sinatra::Default class
988
+ ## Example:
989
+ ##
990
+ ## require 'sinatra/base'
991
+ ##
992
+ ## map '/foo' do
993
+ ## run Sinatra("foo.rb")
994
+ ## end
995
+ ##
996
+ ## run Sinatra("bar.rb")
997
+ ##
998
+ def Sinatra(file, base=Sinatra::Default)
999
+ Sinatra.new(base) do
1000
+ expanded = File.expand_path(file)
1001
+ self.class_eval { set :app_file, expanded }
1002
+ self.class_eval(File.read(expanded), expanded)
1003
+ end
1004
+ end
911
1005
  end