sinatra-sinatra 0.9.1.2 → 0.9.1.3

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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 Blake Mizerany
1
+ Copyright (c) 2007, 2008, 2009 Blake Mizerany
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
@@ -109,18 +109,41 @@ directory. To use a different views directory:
109
109
 
110
110
  set :views, File.dirname(__FILE__) + '/templates'
111
111
 
112
+ One important thing to remember is that you always have to reference
113
+ templates with symbols, even if they're in a subdirectory (in this
114
+ case use <tt>:'subdir/template'</tt>). Rendering methods will render
115
+ any strings passed to them directly.
116
+
112
117
  === Haml Templates
113
118
 
114
119
  The haml gem/library is required to render HAML templates:
115
120
 
121
+ ## You'll need to require haml in your app
122
+ require 'haml'
123
+
116
124
  get '/' do
117
125
  haml :index
118
126
  end
119
127
 
120
128
  Renders <tt>./views/index.haml</tt>.
121
129
 
130
+ {Haml's options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html]
131
+ can be set globally through Sinatra's configurations,
132
+ see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
133
+ and overridden on an individual basis.
134
+
135
+ set :haml, {:format => :html5 } # default Haml format is :xhtml
136
+
137
+ get '/' do
138
+ haml :index, :haml_options => {:format => :html4 } # overridden
139
+ end
140
+
141
+
122
142
  === Erb Templates
123
143
 
144
+ ## You'll need to require erb in your app
145
+ require 'erb'
146
+
124
147
  get '/' do
125
148
  erb :index
126
149
  end
@@ -131,6 +154,9 @@ Renders <tt>./views/index.erb</tt>
131
154
 
132
155
  The builder gem/library is required to render builder templates:
133
156
 
157
+ ## You'll need to require builder in your app
158
+ require 'builder'
159
+
134
160
  get '/' do
135
161
  content_type 'application/xml', :charset => 'utf-8'
136
162
  builder :index
@@ -142,6 +168,9 @@ Renders <tt>./views/index.builder</tt>.
142
168
 
143
169
  The sass gem/library is required to render Sass templates:
144
170
 
171
+ ## You'll need to require haml or sass in your app
172
+ require 'sass'
173
+
145
174
  get '/stylesheet.css' do
146
175
  content_type 'text/css', :charset => 'utf-8'
147
176
  sass :stylesheet
@@ -149,6 +178,19 @@ The sass gem/library is required to render Sass templates:
149
178
 
150
179
  Renders <tt>./views/stylesheet.sass</tt>.
151
180
 
181
+ {Sass' options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html]
182
+ can be set globally through Sinatra's configurations,
183
+ see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
184
+ and overridden on an individual basis.
185
+
186
+ set :sass, {:style => :compact } # default Sass style is :nested
187
+
188
+ get '/stylesheet.css' do
189
+ content_type 'text/css', :charset => 'utf-8'
190
+ sass :stylesheet, :sass_options => {:style => :expanded } # overridden
191
+ end
192
+
193
+
152
194
  === Inline Templates
153
195
 
154
196
  get '/' 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, :compat]
6
6
  task :spec => :test
7
7
 
8
8
  # SPECS ===============================================================
@@ -12,8 +12,20 @@ Rake::TestTask.new(:test) do |t|
12
12
  t.ruby_opts = ['-rubygems'] if defined? Gem
13
13
  end
14
14
 
15
- desc 'Run compatibility specs (requires test/spec)'
16
- task :compat do |t|
15
+ desc "Run < 0.9.x compatibility specs"
16
+ task :compat do
17
+ begin
18
+ require 'mocha'
19
+ rescue LoadError
20
+ puts 'WARN: skipping compat tests. mocha gem required.'
21
+ next
22
+ end
23
+
24
+ if ! system('specrb --help &>/dev/null')
25
+ puts 'WARN: skipping compat tests. test-spec gem required.'
26
+ next
27
+ end
28
+
17
29
  pattern = ENV['TEST'] || '.*'
18
30
  sh "specrb --testcase '#{pattern}' -Ilib:test compat/*_test.rb"
19
31
  end
@@ -183,13 +183,14 @@ context "Haml" do
183
183
  Sinatra.application = nil
184
184
  end
185
185
 
186
- specify 'are empty be default' do
186
+ specify 'default to filename and line of caller' do
187
187
 
188
188
  get '/' do
189
189
  haml 'foo'
190
190
  end
191
191
 
192
- Haml::Engine.expects(:new).with('foo', {}).returns(stub(:render => 'foo'))
192
+ Haml::Engine.expects(:new).with('foo', {:filename => __FILE__,
193
+ :line => (__LINE__-4)}).returns(stub(:render => 'foo'))
193
194
 
194
195
  get_it '/'
195
196
  should.be.ok
@@ -202,7 +203,8 @@ context "Haml" do
202
203
  haml 'foo', :options => {:format => :html4}
203
204
  end
204
205
 
205
- Haml::Engine.expects(:new).with('foo', {:format => :html4}).returns(stub(:render => 'foo'))
206
+ Haml::Engine.expects(:new).with('foo', {:filename => __FILE__,
207
+ :line => (__LINE__-4), :format => :html4}).returns(stub(:render => 'foo'))
206
208
 
207
209
  get_it '/'
208
210
  should.be.ok
@@ -220,7 +222,8 @@ context "Haml" do
220
222
  haml 'foo'
221
223
  end
222
224
 
223
- Haml::Engine.expects(:new).with('foo', {:format => :html4,
225
+ Haml::Engine.expects(:new).with('foo', {:filename => __FILE__,
226
+ :line => (__LINE__-4), :format => :html4,
224
227
  :escape_html => true}).returns(stub(:render => 'foo'))
225
228
 
226
229
  get_it '/'
@@ -1,6 +1,10 @@
1
1
  require 'rubygems'
2
2
  require 'mocha'
3
3
 
4
+ require 'haml'
5
+ require 'sass'
6
+ require 'builder'
7
+
4
8
  # disable warnings in compat specs.
5
9
  $VERBOSE = nil
6
10
 
@@ -52,6 +52,16 @@ context "Sass" do
52
52
  body.should.equal "#sass {\n background_color: #FFF; }\n"
53
53
  end
54
54
 
55
+ it "passes :sass option to the Sass engine" do
56
+ get '/' do
57
+ sass "#sass\n :background-color #FFF\n :color #000\n", :sass => {:style => :compact}
58
+ end
59
+
60
+ get_it '/'
61
+ should.be.ok
62
+ body.should.equal "#sass { background-color: #FFF; color: #000; }\n"
63
+ end
64
+
55
65
  end
56
66
 
57
67
  end
@@ -3,9 +3,10 @@ require 'time'
3
3
  require 'uri'
4
4
  require 'rack'
5
5
  require 'rack/builder'
6
+ require 'sinatra/showexceptions'
6
7
 
7
8
  module Sinatra
8
- VERSION = '0.9.1.1'
9
+ VERSION = '0.9.1.3'
9
10
 
10
11
  # The request object. See Rack::Request for more info:
11
12
  # http://rack.rubyforge.org/doc/classes/Rack/Request.html
@@ -32,16 +33,6 @@ module Sinatra
32
33
  # http://rack.rubyforge.org/doc/classes/Rack/Response.html
33
34
  # http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
34
35
  class Response < Rack::Response
35
- def initialize
36
- @status, @body = 200, []
37
- @header = Rack::Utils::HeaderHash.new({'Content-Type' => 'text/html'})
38
- end
39
-
40
- def write(str)
41
- @body << str.to_s
42
- str
43
- end
44
-
45
36
  def finish
46
37
  @body = block if block_given?
47
38
  if [204, 304].include?(status.to_i)
@@ -231,103 +222,110 @@ module Sinatra
231
222
  # :locals A hash with local variables that should be available
232
223
  # in the template
233
224
  module Templates
234
- def erb(template, options={})
235
- require 'erb' unless defined? ::ERB
236
- render :erb, template, options
225
+ def erb(template, options={}, locals={})
226
+ render :erb, template, options, locals
237
227
  end
238
228
 
239
- def haml(template, options={})
240
- require 'haml' unless defined? ::Haml::Engine
241
- options[:options] ||= self.class.haml if self.class.respond_to? :haml
242
- render :haml, template, options
229
+ def haml(template, options={}, locals={})
230
+ render :haml, template, options, locals
243
231
  end
244
232
 
245
- def sass(template, options={}, &block)
246
- require 'sass' unless defined? ::Sass::Engine
233
+ def sass(template, options={}, locals={})
247
234
  options[:layout] = false
248
- render :sass, template, options
235
+ render :sass, template, options, locals
249
236
  end
250
237
 
251
- def builder(template=nil, options={}, &block)
252
- require 'builder' unless defined? ::Builder
238
+ def builder(template=nil, options={}, locals={}, &block)
253
239
  options, template = template, nil if template.is_a?(Hash)
254
240
  template = lambda { block } if template.nil?
255
- render :builder, template, options
241
+ render :builder, template, options, locals
256
242
  end
257
243
 
258
244
  private
259
- def render(engine, template, options={}) #:nodoc:
260
- data = lookup_template(engine, template, options)
261
- output = __send__("render_#{engine}", template, data, options)
262
- layout, data = lookup_layout(engine, options)
245
+ def render(engine, template, options={}, locals={})
246
+ # merge app-level options
247
+ options = self.class.send(engine).merge(options) if self.class.respond_to?(engine)
248
+
249
+ # extract generic options
250
+ layout = options.delete(:layout)
251
+ layout = :layout if layout.nil? || layout == true
252
+ views = options.delete(:views) || self.class.views || "./views"
253
+ locals = options.delete(:locals) || locals || {}
254
+
255
+ # render template
256
+ data, options[:filename], options[:line] = lookup_template(engine, template, views)
257
+ output = __send__("render_#{engine}", template, data, options, locals)
258
+
259
+ # render layout
263
260
  if layout
264
- __send__("render_#{engine}", layout, data, options) { output }
265
- else
266
- output
261
+ data, options[:filename], options[:line] = lookup_layout(engine, layout, views)
262
+ if data
263
+ output = __send__("render_#{engine}", layout, data, options, {}) { output }
264
+ end
267
265
  end
266
+
267
+ output
268
268
  end
269
269
 
270
- def lookup_template(engine, template, options={})
270
+ def lookup_template(engine, template, views_dir, filename = nil, line = nil)
271
271
  case template
272
272
  when Symbol
273
273
  if cached = self.class.templates[template]
274
- lookup_template(engine, cached, options)
274
+ lookup_template(engine, cached[:template], views_dir, cached[:filename], cached[:line])
275
275
  else
276
- ::File.read(template_path(engine, template, options))
276
+ path = ::File.join(views_dir, "#{template}.#{engine}")
277
+ [ ::File.read(path), path, 1 ]
277
278
  end
278
279
  when Proc
279
- template.call
280
+ filename, line = self.class.caller_locations.first if filename.nil?
281
+ [ template.call, filename, line.to_i ]
280
282
  when String
281
- template
283
+ filename, line = self.class.caller_locations.first if filename.nil?
284
+ [ template, filename, line.to_i ]
282
285
  else
283
286
  raise ArgumentError
284
287
  end
285
288
  end
286
289
 
287
- def lookup_layout(engine, options)
288
- return if options[:layout] == false
289
- options.delete(:layout) if options[:layout] == true
290
- template = options[:layout] || :layout
291
- data = lookup_template(engine, template, options)
292
- [template, data]
290
+ def lookup_layout(engine, template, views_dir)
291
+ lookup_template(engine, template, views_dir)
293
292
  rescue Errno::ENOENT
294
293
  nil
295
294
  end
296
295
 
297
- def template_path(engine, template, options={})
298
- views_dir =
299
- options[:views_directory] || self.options.views || "./views"
300
- "#{views_dir}/#{template}.#{engine}"
301
- end
302
-
303
- def render_erb(template, data, options, &block)
296
+ def render_erb(template, data, options, locals, &block)
304
297
  original_out_buf = @_out_buf
305
298
  data = data.call if data.kind_of? Proc
306
299
 
307
300
  instance = ::ERB.new(data, nil, nil, '@_out_buf')
308
- locals = options[:locals] || {}
309
301
  locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
310
302
 
311
- src = "#{locals_assigns.join("\n")}\n#{instance.src}"
312
- eval src, binding, '(__ERB__)', locals_assigns.length + 1
303
+ filename = options.delete(:filename) || '(__ERB__)'
304
+ line = options.delete(:line) || 1
305
+ line -= 1 if instance.src =~ /^#coding:/
306
+
307
+ render_binding = binding
308
+ eval locals_assigns.join("\n"), render_binding
309
+ eval instance.src, render_binding, filename, line
313
310
  @_out_buf, result = original_out_buf, @_out_buf
314
311
  result
315
312
  end
316
313
 
317
- def render_haml(template, data, options, &block)
318
- engine = ::Haml::Engine.new(data, options[:options] || {})
319
- engine.render(self, options[:locals] || {}, &block)
314
+ def render_haml(template, data, options, locals, &block)
315
+ ::Haml::Engine.new(data, options).render(self, locals, &block)
320
316
  end
321
317
 
322
- def render_sass(template, data, options, &block)
323
- engine = ::Sass::Engine.new(data, options[:sass] || {})
324
- engine.render
318
+ def render_sass(template, data, options, locals, &block)
319
+ ::Sass::Engine.new(data, options).render
325
320
  end
326
321
 
327
- def render_builder(template, data, options, &block)
328
- xml = ::Builder::XmlMarkup.new(:indent => 2)
322
+ def render_builder(template, data, options, locals, &block)
323
+ options = { :indent => 2 }.merge(options)
324
+ filename = options.delete(:filename) || '<BUILDER>'
325
+ line = options.delete(:line) || 1
326
+ xml = ::Builder::XmlMarkup.new(options)
329
327
  if data.respond_to?(:to_str)
330
- eval data.to_str, binding, '<BUILDER>', 1
328
+ eval data.to_str, binding, filename, line
331
329
  elsif data.kind_of?(Proc)
332
330
  data.call(xml)
333
331
  end
@@ -409,7 +407,13 @@ module Sinatra
409
407
  private
410
408
  # Run before filters and then locate and run a matching route.
411
409
  def route!
412
- @params = nested_params(@request.params)
410
+ # enable nested params in Rack < 1.0; allow indifferent access
411
+ @params =
412
+ if Rack::Utils.respond_to?(:parse_nested_query)
413
+ indifferent_params(@request.params)
414
+ else
415
+ nested_params(@request.params)
416
+ end
413
417
 
414
418
  # before filters
415
419
  self.class.filters.each { |block| instance_eval(&block) }
@@ -443,24 +447,45 @@ module Sinatra
443
447
  catch(:pass) do
444
448
  conditions.each { |cond|
445
449
  throw :pass if instance_eval(&cond) == false }
446
- throw :halt, instance_eval(&block)
450
+ route_eval(&block)
447
451
  end
448
452
  end
449
453
  end
450
454
  end
451
455
 
452
- # No matching route found or all routes passed -- forward downstream
453
- # when running as middleware; 404 when running as normal app.
456
+ route_missing
457
+ end
458
+
459
+ # Run a route block and throw :halt with the result.
460
+ def route_eval(&block)
461
+ throw :halt, instance_eval(&block)
462
+ end
463
+
464
+ # No matching route was found or all routes passed. The default
465
+ # implementation is to forward the request downstream when running
466
+ # as middleware (@app is non-nil); when no downstream app is set, raise
467
+ # a NotFound exception. Subclasses can override this method to perform
468
+ # custom route miss logic.
469
+ def route_missing
454
470
  if @app
455
- # Call bypassed method before forward to catch behavior that should
456
- # happen even if no routes are hit.
457
- bypassed if respond_to?(:bypassed)
458
471
  forward
459
472
  else
460
473
  raise NotFound
461
474
  end
462
475
  end
463
476
 
477
+ # Enable string or symbol key access to the nested params hash.
478
+ def indifferent_params(params)
479
+ params = indifferent_hash.merge(params)
480
+ params.each do |key, value|
481
+ next unless value.is_a?(Hash)
482
+ params[key] = indifferent_params(value)
483
+ end
484
+ end
485
+
486
+ # Recursively replace the params hash with a nested indifferent
487
+ # hash. Rack 1.0 has a built in implementation of this method - remove
488
+ # this once Rack 1.0 is required.
464
489
  def nested_params(params)
465
490
  return indifferent_hash.merge(params) if !params.keys.join.include?('[')
466
491
  params.inject indifferent_hash do |res, (key,val)|
@@ -532,7 +557,7 @@ module Sinatra
532
557
  @env['sinatra.error'] = boom
533
558
 
534
559
  dump_errors!(boom) if options.dump_errors?
535
- raise boom if options.raise_errors?
560
+ raise boom if options.raise_errors? || options.show_exceptions?
536
561
 
537
562
  @response.status = 500
538
563
  error_block! boom.class, Exception
@@ -624,7 +649,8 @@ module Sinatra
624
649
 
625
650
  # Define a named template. The block must return the template source.
626
651
  def template(name, &block)
627
- templates[name] = block
652
+ filename, line = caller_locations.first
653
+ templates[name] = { :filename => filename, :line => line, :template => block }
628
654
  end
629
655
 
630
656
  # Define the layout template. The block must return the template source.
@@ -636,12 +662,18 @@ module Sinatra
636
662
  # when no file is specified.
637
663
  def use_in_file_templates!(file=nil)
638
664
  file ||= caller_files.first
639
- if data = ::IO.read(file).split('__END__')[1]
665
+ app, data =
666
+ ::IO.read(file).split(/^__END__$/, 2) rescue nil
667
+
668
+ if data
640
669
  data.gsub!(/\r\n/, "\n")
670
+ lines = app.count("\n") + 1
641
671
  template = nil
642
672
  data.each_line do |line|
673
+ lines += 1
643
674
  if line =~ /^@@\s*(.*)/
644
- template = templates[$1.to_sym] = ''
675
+ template = ''
676
+ templates[$1.to_sym] = { :filename => file, :line => lines, :template => template }
645
677
  elsif template
646
678
  template << line
647
679
  end
@@ -711,10 +743,10 @@ module Sinatra
711
743
  route('HEAD', path, opts, &block)
712
744
  end
713
745
 
714
- def put(path, opts={}, &bk); route 'PUT', path, opts, &bk; end
715
- def post(path, opts={}, &bk); route 'POST', path, opts, &bk; end
716
- def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk; end
717
- def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk; end
746
+ def put(path, opts={}, &bk); route 'PUT', path, opts, &bk end
747
+ def post(path, opts={}, &bk); route 'POST', path, opts, &bk end
748
+ def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk end
749
+ def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk end
718
750
 
719
751
  private
720
752
  def route(verb, path, opts={}, &block)
@@ -734,7 +766,7 @@ module Sinatra
734
766
  lambda { unbound_method.bind(self).call }
735
767
  end
736
768
 
737
- invoke_hook(:route_added, verb, path)
769
+ invoke_hook(:route_added, verb, path, block)
738
770
 
739
771
  (routes[verb] ||= []).
740
772
  push([pattern, keys, conditions, block]).last
@@ -790,14 +822,14 @@ module Sinatra
790
822
  end
791
823
  end
792
824
 
793
- def development? ; environment == :development ; end
794
- def test? ; environment == :test ; end
795
- def production? ; environment == :production ; end
825
+ def development?; environment == :development end
826
+ def production?; environment == :production end
827
+ def test?; environment == :test end
796
828
 
797
829
  # Set configuration options for Sinatra and/or the app.
798
830
  # Allows scoping of settings for certain environments.
799
831
  def configure(*envs, &block)
800
- yield if envs.empty? || envs.include?(environment.to_sym)
832
+ yield self if envs.empty? || envs.include?(environment.to_sym)
801
833
  end
802
834
 
803
835
  # Use the specified Rack middleware
@@ -836,8 +868,10 @@ module Sinatra
836
868
  def new(*args, &bk)
837
869
  builder = Rack::Builder.new
838
870
  builder.use Rack::Session::Cookie if sessions? && !test?
839
- builder.use Rack::CommonLogger if logging?
840
- builder.use Rack::MethodOverride if methodoverride?
871
+ builder.use Rack::CommonLogger if logging?
872
+ builder.use Rack::MethodOverride if methodoverride?
873
+ builder.use ShowExceptions if show_exceptions?
874
+
841
875
  @middleware.each { |c,a,b| builder.use(c, *a, &b) }
842
876
  builder.run super
843
877
  builder.to_app
@@ -871,7 +905,7 @@ module Sinatra
871
905
  servers = Array(self.server)
872
906
  servers.each do |server_name|
873
907
  begin
874
- return Rack::Handler.get(server_name)
908
+ return Rack::Handler.get(server_name.capitalize)
875
909
  rescue LoadError
876
910
  rescue NameError
877
911
  end
@@ -898,24 +932,32 @@ module Sinatra
898
932
  send :define_method, message, &block
899
933
  end
900
934
 
935
+ public
936
+ CALLERS_TO_IGNORE = [
937
+ /lib\/sinatra.*\.rb$/, # all sinatra code
938
+ /\(.*\)/, # generated code
939
+ /custom_require\.rb$/, # rubygems require hacks
940
+ /active_support/, # active_support require hacks
941
+ ] unless self.const_defined?('CALLERS_TO_IGNORE')
942
+
901
943
  # Like Kernel#caller but excluding certain magic entries and without
902
944
  # line / method information; the resulting array contains filenames only.
903
945
  def caller_files
904
- ignore = [
905
- /lib\/sinatra.*\.rb$/, # all sinatra code
906
- /\(.*\)/, # generated code
907
- /custom_require\.rb$/, # rubygems require hacks
908
- /active_support/, # active_support require hacks
909
- ]
946
+ caller_locations.
947
+ map { |file,line| file }
948
+ end
949
+
950
+ def caller_locations
910
951
  caller(1).
911
- map { |line| line.split(/:\d/, 2).first }.
912
- reject { |file| ignore.any? { |pattern| file =~ pattern } }
952
+ map { |line| line.split(/:(?=\d|in )/)[0,2] }.
953
+ reject { |file,line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
913
954
  end
914
955
  end
915
956
 
916
957
  set :raise_errors, true
917
958
  set :dump_errors, false
918
959
  set :clean_trace, true
960
+ set :show_exceptions, Proc.new { development? }
919
961
  set :sessions, false
920
962
  set :logging, false
921
963
  set :methodoverride, false
@@ -957,6 +999,8 @@ module Sinatra
957
999
  end
958
1000
 
959
1001
  error NotFound do
1002
+ content_type 'text/html'
1003
+
960
1004
  (<<-HTML).gsub(/^ {8}/, '')
961
1005
  <!DOCTYPE html>
962
1006
  <html>
@@ -978,35 +1022,6 @@ module Sinatra
978
1022
  </html>
979
1023
  HTML
980
1024
  end
981
-
982
- error do
983
- next unless err = request.env['sinatra.error']
984
- heading = err.class.name + ' - ' + err.message.to_s
985
- (<<-HTML).gsub(/^ {8}/, '')
986
- <!DOCTYPE html>
987
- <html>
988
- <head>
989
- <style type="text/css">
990
- body {font-family:verdana;color:#333}
991
- #c {margin-left:20px}
992
- h1 {color:#1D6B8D;margin:0;margin-top:-30px}
993
- h2 {color:#1D6B8D;font-size:18px}
994
- pre {border-left:2px solid #ddd;padding-left:10px;color:#000}
995
- img {margin-top:10px}
996
- </style>
997
- </head>
998
- <body>
999
- <div id="c">
1000
- <img src="/__sinatra__/500.png">
1001
- <h1>#{escape_html(heading)}</h1>
1002
- <pre>#{escape_html(clean_backtrace(err.backtrace) * "\n")}</pre>
1003
- <h2>Params</h2>
1004
- <pre>#{escape_html(params.inspect)}</pre>
1005
- </div>
1006
- </body>
1007
- </html>
1008
- HTML
1009
- end
1010
1025
  end
1011
1026
  end
1012
1027