sinatra 0.9.1.1 → 0.9.2
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.
- data/CHANGES +81 -0
- data/LICENSE +1 -1
- data/README.rdoc +63 -23
- data/Rakefile +25 -23
- data/compat/haml_test.rb +7 -4
- data/compat/helper.rb +3 -0
- data/compat/sass_test.rb +10 -0
- data/lib/sinatra/base.rb +240 -148
- data/lib/sinatra/compat.rb +16 -0
- data/lib/sinatra/main.rb +2 -14
- data/lib/sinatra/showexceptions.rb +303 -0
- data/lib/sinatra/test.rb +2 -0
- data/sinatra.gemspec +13 -4
- data/test/base_test.rb +123 -93
- data/test/builder_test.rb +2 -1
- data/test/contest.rb +64 -0
- data/test/erb_test.rb +1 -1
- data/test/extensions_test.rb +17 -1
- data/test/filter_test.rb +1 -1
- data/test/haml_test.rb +25 -3
- data/test/helper.rb +43 -48
- data/test/helpers_test.rb +446 -440
- data/test/mapped_error_test.rb +138 -143
- data/test/middleware_test.rb +2 -2
- data/test/options_test.rb +241 -248
- data/test/render_backtrace_test.rb +145 -0
- data/test/request_test.rb +1 -1
- data/test/response_test.rb +2 -2
- data/test/result_test.rb +1 -1
- data/test/route_added_hook_test.rb +59 -0
- data/test/routing_test.rb +94 -22
- data/test/sass_test.rb +44 -1
- data/test/server_test.rb +5 -3
- data/test/sinatra_test.rb +1 -1
- data/test/static_test.rb +2 -2
- data/test/templates_test.rb +16 -4
- data/test/test_test.rb +15 -7
- data/test/views/error.builder +3 -0
- data/test/views/error.erb +3 -0
- data/test/views/error.haml +3 -0
- data/test/views/error.sass +2 -0
- metadata +32 -4
- data/test/reload_test.rb +0 -68
data/CHANGES
CHANGED
@@ -1,3 +1,84 @@
|
|
1
|
+
= 0.9.2 / unreleased
|
2
|
+
|
3
|
+
* This version is compatible with Rack 1.0. [Rein Henrichs]
|
4
|
+
|
5
|
+
* The development-mode unhandled exception / error page has been
|
6
|
+
greatly enhanced, functionally and aesthetically. The error
|
7
|
+
page is used when the :show_exceptions option is enabled and an
|
8
|
+
exception propagates outside of a route handler or before filter.
|
9
|
+
[Simon Rozet / Matte Noble / Ryan Tomayko]
|
10
|
+
|
11
|
+
* Backtraces that move through templates now include filenames and
|
12
|
+
line numbers where possible. [#51 / S. Brent Faulkner]
|
13
|
+
|
14
|
+
* All templates now have an app-level option for setting default
|
15
|
+
template options (:haml, :sass, :erb, :builder). The app-level
|
16
|
+
option value must be a Hash if set and is merged with the
|
17
|
+
template options specified to the render method (Base#haml,
|
18
|
+
Base#erb, Base#builder). [S. Brent Faulkner, Ryan Tomayko]
|
19
|
+
|
20
|
+
* The method signature for all template rendering methods has
|
21
|
+
been unified: "def engine(template, options={}, locals={})".
|
22
|
+
The options Hash now takes the generic :views, :layout, and
|
23
|
+
:locals options but also any template-specific options. The
|
24
|
+
generic options are removed before calling the template specific
|
25
|
+
render method. Locals may be specified using either the
|
26
|
+
:locals key in the options hash or a second Hash option to the
|
27
|
+
rendering method. [#191 / Ryan Tomayko]
|
28
|
+
|
29
|
+
* The receiver is now passed to "configure" blocks. This
|
30
|
+
allows for the following idiom in top-level apps:
|
31
|
+
configure { |app| set :foo, app.root + '/foo' }
|
32
|
+
[TJ Holowaychuck / Ryan Tomayko]
|
33
|
+
|
34
|
+
* The "sinatra/test" lib is deprecated and will be removed in
|
35
|
+
Sinatra 1.0. This includes the Sinatra::Test module and
|
36
|
+
Sinatra::TestHarness class in addition to all the framework
|
37
|
+
test helpers that were deprecated in 0.9.1. The Rack::Test
|
38
|
+
lib should be used instead: http://gitrdoc.com/brynary/rack-test
|
39
|
+
[#176 / Simon Rozet]
|
40
|
+
|
41
|
+
* Development mode source file reloading has been removed. The
|
42
|
+
"shotgun" (http://rtomayko.github.com/shotgun/) program can be
|
43
|
+
used to achieve the same basic functionality in most situations.
|
44
|
+
Passenger users should use the "tmp/always_restart.txt"
|
45
|
+
file (http://tinyurl.com/c67o4h). [#166 / Ryan Tomayko]
|
46
|
+
|
47
|
+
* Auto-requiring template libs in the erb, builder, haml, and
|
48
|
+
sass methods is deprecated due to thread-safety issues. You must
|
49
|
+
require the template libs explicitly in your app file. [Simon Rozet]
|
50
|
+
|
51
|
+
* A new Sinatra::Base#route_missing method was added. route_missing
|
52
|
+
is sent when no route matches the request or all route handlers
|
53
|
+
pass. The default implementation forwards the request to the
|
54
|
+
downstream app when running as middleware (i.e., "@app" is
|
55
|
+
non-nil), or raises a NotFound exception when no downstream app
|
56
|
+
is defined. Subclasses can override this method to perform custom
|
57
|
+
route miss logic. [Jon Crosby]
|
58
|
+
|
59
|
+
* A new Sinatra::Base#route_eval method was added. The method
|
60
|
+
yields to the block and throws :halt with the result. Subclasses
|
61
|
+
can override this method to tap into the route execution logic.
|
62
|
+
[TJ Holowaychuck]
|
63
|
+
|
64
|
+
* Fix the "-x" (enable request mutex / locking) command line
|
65
|
+
argument. Passing -x now properly sets the :lock option.
|
66
|
+
[S. Brent Faulkner, Ryan Tomayko]
|
67
|
+
|
68
|
+
* Fix writer ("foo=") and predicate ("foo?") methods in extension
|
69
|
+
modules not being added to the registering class.
|
70
|
+
[#172 / Pat Nakajima]
|
71
|
+
|
72
|
+
* Fix in-file templates when running alongside activesupport and
|
73
|
+
fatal errors when requiring activesupport before sinatra
|
74
|
+
[#178 / Brian Candler]
|
75
|
+
|
76
|
+
* Fix various issues running on Google AppEngine.
|
77
|
+
[Samuel Goebert, Simon Rozet]
|
78
|
+
|
79
|
+
* Fix in-file templates __END__ detection when __END__ exists with
|
80
|
+
other stuff on a line [Yoji Shidara]
|
81
|
+
|
1
82
|
= 0.9.1.1 / 2009-03-09
|
2
83
|
|
3
84
|
* Fix directory traversal vulnerability in default static files
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -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
|
@@ -285,13 +327,7 @@ A route can punt processing to the next matching route using <tt>pass</tt>:
|
|
285
327
|
The route block is immediately exited and control continues with the next
|
286
328
|
matching route. If no matching route is found, a 404 is returned.
|
287
329
|
|
288
|
-
== Configuration
|
289
|
-
|
290
|
-
Sinatra supports multiple environments and reloading. Reloading happens
|
291
|
-
before each request when running under the <tt>:development</tt>
|
292
|
-
environment. Wrap your configurations (e.g., database connections, constants,
|
293
|
-
etc.) in <tt>configure</tt> blocks to protect them from reloading or to
|
294
|
-
target specific environments.
|
330
|
+
== Configuration
|
295
331
|
|
296
332
|
Run once, at startup, in any environment:
|
297
333
|
|
@@ -300,14 +336,14 @@ Run once, at startup, in any environment:
|
|
300
336
|
end
|
301
337
|
|
302
338
|
Run only when the environment (RACK_ENV environment variable) is set to
|
303
|
-
<tt>:production</tt
|
339
|
+
<tt>:production</tt>:
|
304
340
|
|
305
341
|
configure :production do
|
306
342
|
...
|
307
343
|
end
|
308
344
|
|
309
|
-
Run when the environment
|
310
|
-
|
345
|
+
Run when the environment is set to either <tt>:production</tt> or
|
346
|
+
<tt>:test</tt>:
|
311
347
|
|
312
348
|
configure :production, :test do
|
313
349
|
...
|
@@ -401,34 +437,38 @@ typically don't have to +use+ them explicitly.
|
|
401
437
|
|
402
438
|
== Testing
|
403
439
|
|
404
|
-
|
405
|
-
|
440
|
+
Sinatra tests can be written using any Rack-based testing library
|
441
|
+
or framework. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] is
|
442
|
+
recommended:
|
406
443
|
|
407
444
|
require 'my_sinatra_app'
|
408
|
-
require 'test
|
409
|
-
require 'sinatra/test'
|
445
|
+
require 'rack/test'
|
410
446
|
|
411
447
|
class MyAppTest < Test::Unit::TestCase
|
412
|
-
include
|
448
|
+
include Rack::Test::Methods
|
449
|
+
|
450
|
+
def app
|
451
|
+
Sinatra::Application
|
452
|
+
end
|
413
453
|
|
414
454
|
def test_my_default
|
415
455
|
get '/'
|
416
|
-
assert_equal 'Hello World!',
|
456
|
+
assert_equal 'Hello World!', last_response.body
|
417
457
|
end
|
418
458
|
|
419
459
|
def test_with_params
|
420
|
-
get '/meet',
|
421
|
-
assert_equal 'Hello Frank!',
|
460
|
+
get '/meet', :name => 'Frank'
|
461
|
+
assert_equal 'Hello Frank!', last_response.body
|
422
462
|
end
|
423
463
|
|
424
464
|
def test_with_rack_env
|
425
|
-
get '/', {},
|
426
|
-
assert_equal "You're using Songbird!",
|
465
|
+
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
|
466
|
+
assert_equal "You're using Songbird!", last_response.body
|
427
467
|
end
|
428
468
|
end
|
429
469
|
|
430
|
-
|
431
|
-
|
470
|
+
NOTE: The built-in Sinatra::Test module and Sinatra::TestHarness class
|
471
|
+
are deprecated as of the 0.9.2 release.
|
432
472
|
|
433
473
|
== Command line
|
434
474
|
|
@@ -454,7 +494,7 @@ clone and run your app with the <tt>sinatra/lib</tt> directory on the
|
|
454
494
|
git clone git://github.com/sinatra/sinatra.git
|
455
495
|
ruby -Isinatra/lib myapp.rb
|
456
496
|
|
457
|
-
Alternatively, you can add the <tt>sinatra/lib
|
497
|
+
Alternatively, you can add the <tt>sinatra/lib</tt> directory to the
|
458
498
|
<tt>LOAD_PATH</tt> in your application:
|
459
499
|
|
460
500
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
|
data/Rakefile
CHANGED
@@ -2,20 +2,33 @@ 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 ===============================================================
|
9
9
|
|
10
|
+
task(:test) { puts "==> Running main test suite" }
|
11
|
+
|
10
12
|
Rake::TestTask.new(:test) do |t|
|
11
13
|
t.test_files = FileList['test/*_test.rb']
|
12
14
|
t.ruby_opts = ['-rubygems'] if defined? Gem
|
13
15
|
end
|
14
16
|
|
15
|
-
desc
|
16
|
-
task :compat do
|
17
|
-
|
18
|
-
|
17
|
+
desc "Run < 0.9.x compatibility specs"
|
18
|
+
task :compat do
|
19
|
+
begin
|
20
|
+
require 'mocha'
|
21
|
+
require 'test/spec'
|
22
|
+
at_exit { exit 0 } # disable test-spec at_exit runner
|
23
|
+
|
24
|
+
puts "==> Running compat test suite"
|
25
|
+
Rake::TestTask.new(:compat) do |t|
|
26
|
+
t.test_files = FileList['compat/*_test.rb']
|
27
|
+
t.ruby_opts = ['-rubygems'] if defined? Gem
|
28
|
+
end
|
29
|
+
rescue LoadError
|
30
|
+
warn 'Skipping compat tests. mocha and/or test-spec gems not installed.'
|
31
|
+
end
|
19
32
|
end
|
20
33
|
|
21
34
|
# PACKAGING ============================================================
|
@@ -33,7 +46,7 @@ def spec
|
|
33
46
|
end
|
34
47
|
|
35
48
|
def package(ext='')
|
36
|
-
"
|
49
|
+
"pkg/sinatra-#{spec.version}" + ext
|
37
50
|
end
|
38
51
|
|
39
52
|
desc 'Build packages'
|
@@ -44,15 +57,15 @@ task :install => package('.gem') do
|
|
44
57
|
sh "gem install #{package('.gem')}"
|
45
58
|
end
|
46
59
|
|
47
|
-
directory '
|
48
|
-
CLOBBER.include('
|
60
|
+
directory 'pkg/'
|
61
|
+
CLOBBER.include('pkg')
|
49
62
|
|
50
|
-
file package('.gem') => %w[
|
63
|
+
file package('.gem') => %w[pkg/ sinatra.gemspec] + spec.files do |f|
|
51
64
|
sh "gem build sinatra.gemspec"
|
52
65
|
mv File.basename(f.name), f.name
|
53
66
|
end
|
54
67
|
|
55
|
-
file package('.tar.gz') => %w[
|
68
|
+
file package('.tar.gz') => %w[pkg/] + spec.files do |f|
|
56
69
|
sh <<-SH
|
57
70
|
git archive \
|
58
71
|
--prefix=sinatra-#{source_version}/ \
|
@@ -64,7 +77,7 @@ end
|
|
64
77
|
# Rubyforge Release / Publish Tasks ==================================
|
65
78
|
|
66
79
|
desc 'Publish gem and tarball to rubyforge'
|
67
|
-
task '
|
80
|
+
task 'release' => [package('.gem'), package('.tar.gz')] do |t|
|
68
81
|
sh <<-end
|
69
82
|
rubyforge add_release sinatra sinatra #{spec.version} #{package('.gem')} &&
|
70
83
|
rubyforge add_file sinatra sinatra #{spec.version} #{package('.tar.gz')}
|
@@ -95,12 +108,6 @@ file 'doc/api/index.html' => FileList['lib/**/*.rb','README.rdoc'] do |f|
|
|
95
108
|
end
|
96
109
|
CLEAN.include 'doc/api'
|
97
110
|
|
98
|
-
def rdoc_to_html(file_name)
|
99
|
-
require 'rdoc/markup/to_html'
|
100
|
-
rdoc = RDoc::Markup::ToHtml.new
|
101
|
-
rdoc.convert(File.read(file_name))
|
102
|
-
end
|
103
|
-
|
104
111
|
# Gemspec Helpers ====================================================
|
105
112
|
|
106
113
|
def source_version
|
@@ -108,12 +115,7 @@ def source_version
|
|
108
115
|
line.match(/.*VERSION = '(.*)'/)[1]
|
109
116
|
end
|
110
117
|
|
111
|
-
|
112
|
-
FileList[
|
113
|
-
'{lib,test,compat,images}/**',
|
114
|
-
'Rakefile', 'CHANGES', 'README.rdoc'
|
115
|
-
]
|
116
|
-
file 'sinatra.gemspec' => project_files do |f|
|
118
|
+
task 'sinatra.gemspec' => FileList['{lib,test,compat}/**','Rakefile','CHANGES','*.rdoc'] do |f|
|
117
119
|
# read spec file and split out manifest section
|
118
120
|
spec = File.read(f.name)
|
119
121
|
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
data/compat/haml_test.rb
CHANGED
@@ -183,13 +183,14 @@ context "Haml" do
|
|
183
183
|
Sinatra.application = nil
|
184
184
|
end
|
185
185
|
|
186
|
-
specify '
|
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', {
|
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', {:
|
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', {:
|
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 '/'
|
data/compat/helper.rb
CHANGED
data/compat/sass_test.rb
CHANGED
@@ -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
|
data/lib/sinatra/base.rb
CHANGED
@@ -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.
|
9
|
+
VERSION = '0.9.2'
|
9
10
|
|
10
11
|
# The request object. See Rack::Request for more info:
|
11
12
|
# http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
@@ -14,6 +15,7 @@ module Sinatra
|
|
14
15
|
@env['HTTP_USER_AGENT']
|
15
16
|
end
|
16
17
|
|
18
|
+
# Returns an array of acceptable media types for the response
|
17
19
|
def accept
|
18
20
|
@env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.strip }
|
19
21
|
end
|
@@ -31,16 +33,6 @@ module Sinatra
|
|
31
33
|
# http://rack.rubyforge.org/doc/classes/Rack/Response.html
|
32
34
|
# http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
|
33
35
|
class Response < Rack::Response
|
34
|
-
def initialize
|
35
|
-
@status, @body = 200, []
|
36
|
-
@header = Rack::Utils::HeaderHash.new({'Content-Type' => 'text/html'})
|
37
|
-
end
|
38
|
-
|
39
|
-
def write(str)
|
40
|
-
@body << str.to_s
|
41
|
-
str
|
42
|
-
end
|
43
|
-
|
44
36
|
def finish
|
45
37
|
@body = block if block_given?
|
46
38
|
if [204, 304].include?(status.to_i)
|
@@ -162,6 +154,8 @@ module Sinatra
|
|
162
154
|
not_found
|
163
155
|
end
|
164
156
|
|
157
|
+
# Rack response body used to deliver static files. The file contents are
|
158
|
+
# generated iteratively in 8K chunks.
|
165
159
|
class StaticFile < ::File #:nodoc:
|
166
160
|
alias_method :to_path, :path
|
167
161
|
def each
|
@@ -215,110 +209,141 @@ module Sinatra
|
|
215
209
|
end
|
216
210
|
|
217
211
|
# Template rendering methods. Each method takes a the name of a template
|
218
|
-
# to render as a Symbol and returns a String with the rendered output
|
212
|
+
# to render as a Symbol and returns a String with the rendered output,
|
213
|
+
# as well as an optional hash with additional options.
|
214
|
+
#
|
215
|
+
# `template` is either the name or path of the template as symbol
|
216
|
+
# (Use `:'subdir/myview'` for views in subdirectories), or a string
|
217
|
+
# that will be rendered.
|
218
|
+
#
|
219
|
+
# Possible options are:
|
220
|
+
# :layout If set to false, no layout is rendered, otherwise
|
221
|
+
# the specified layout is used (Ignored for `sass`)
|
222
|
+
# :locals A hash with local variables that should be available
|
223
|
+
# in the template
|
219
224
|
module Templates
|
220
|
-
def erb(template, options={})
|
221
|
-
|
222
|
-
|
225
|
+
def erb(template, options={}, locals={})
|
226
|
+
require_warn('ERB') unless defined?(::ERB)
|
227
|
+
|
228
|
+
render :erb, template, options, locals
|
223
229
|
end
|
224
230
|
|
225
|
-
def haml(template, options={})
|
226
|
-
|
227
|
-
|
228
|
-
render :haml, template, options
|
231
|
+
def haml(template, options={}, locals={})
|
232
|
+
require_warn('Haml') unless defined?(::Haml::Engine)
|
233
|
+
|
234
|
+
render :haml, template, options, locals
|
229
235
|
end
|
230
236
|
|
231
|
-
def sass(template, options={},
|
232
|
-
|
237
|
+
def sass(template, options={}, locals={})
|
238
|
+
require_warn('Sass') unless defined?(::Sass::Engine)
|
239
|
+
|
233
240
|
options[:layout] = false
|
234
|
-
render :sass, template, options
|
241
|
+
render :sass, template, options, locals
|
235
242
|
end
|
236
243
|
|
237
|
-
def builder(template=nil, options={}, &block)
|
238
|
-
|
244
|
+
def builder(template=nil, options={}, locals={}, &block)
|
245
|
+
require_warn('Builder') unless defined?(::Builder)
|
246
|
+
|
239
247
|
options, template = template, nil if template.is_a?(Hash)
|
240
248
|
template = lambda { block } if template.nil?
|
241
|
-
render :builder, template, options
|
249
|
+
render :builder, template, options, locals
|
242
250
|
end
|
243
251
|
|
244
252
|
private
|
245
|
-
def render(engine, template, options={})
|
246
|
-
|
247
|
-
|
248
|
-
|
253
|
+
def render(engine, template, options={}, locals={})
|
254
|
+
# merge app-level options
|
255
|
+
options = self.class.send(engine).merge(options) if self.class.respond_to?(engine)
|
256
|
+
|
257
|
+
# extract generic options
|
258
|
+
layout = options.delete(:layout)
|
259
|
+
layout = :layout if layout.nil? || layout == true
|
260
|
+
views = options.delete(:views) || self.class.views || "./views"
|
261
|
+
locals = options.delete(:locals) || locals || {}
|
262
|
+
|
263
|
+
# render template
|
264
|
+
data, options[:filename], options[:line] = lookup_template(engine, template, views)
|
265
|
+
output = __send__("render_#{engine}", template, data, options, locals)
|
266
|
+
|
267
|
+
# render layout
|
249
268
|
if layout
|
250
|
-
|
251
|
-
|
252
|
-
|
269
|
+
data, options[:filename], options[:line] = lookup_layout(engine, layout, views)
|
270
|
+
if data
|
271
|
+
output = __send__("render_#{engine}", layout, data, options, {}) { output }
|
272
|
+
end
|
253
273
|
end
|
274
|
+
|
275
|
+
output
|
254
276
|
end
|
255
277
|
|
256
|
-
def lookup_template(engine, template,
|
278
|
+
def lookup_template(engine, template, views_dir, filename = nil, line = nil)
|
257
279
|
case template
|
258
280
|
when Symbol
|
259
281
|
if cached = self.class.templates[template]
|
260
|
-
lookup_template(engine, cached,
|
282
|
+
lookup_template(engine, cached[:template], views_dir, cached[:filename], cached[:line])
|
261
283
|
else
|
262
|
-
::File.
|
284
|
+
path = ::File.join(views_dir, "#{template}.#{engine}")
|
285
|
+
[ ::File.read(path), path, 1 ]
|
263
286
|
end
|
264
287
|
when Proc
|
265
|
-
|
288
|
+
filename, line = self.class.caller_locations.first if filename.nil?
|
289
|
+
[ template.call, filename, line.to_i ]
|
266
290
|
when String
|
267
|
-
|
291
|
+
filename, line = self.class.caller_locations.first if filename.nil?
|
292
|
+
[ template, filename, line.to_i ]
|
268
293
|
else
|
269
294
|
raise ArgumentError
|
270
295
|
end
|
271
296
|
end
|
272
297
|
|
273
|
-
def lookup_layout(engine,
|
274
|
-
|
275
|
-
options.delete(:layout) if options[:layout] == true
|
276
|
-
template = options[:layout] || :layout
|
277
|
-
data = lookup_template(engine, template, options)
|
278
|
-
[template, data]
|
298
|
+
def lookup_layout(engine, template, views_dir)
|
299
|
+
lookup_template(engine, template, views_dir)
|
279
300
|
rescue Errno::ENOENT
|
280
301
|
nil
|
281
302
|
end
|
282
303
|
|
283
|
-
def
|
284
|
-
|
285
|
-
options[:views_directory] || self.options.views || "./views"
|
286
|
-
"#{views_dir}/#{template}.#{engine}"
|
287
|
-
end
|
288
|
-
|
289
|
-
def render_erb(template, data, options, &block)
|
290
|
-
original_out_buf = @_out_buf
|
304
|
+
def render_erb(template, data, options, locals, &block)
|
305
|
+
original_out_buf = defined?(@_out_buf) && @_out_buf
|
291
306
|
data = data.call if data.kind_of? Proc
|
292
307
|
|
293
308
|
instance = ::ERB.new(data, nil, nil, '@_out_buf')
|
294
|
-
locals = options[:locals] || {}
|
295
309
|
locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
|
296
310
|
|
297
|
-
|
298
|
-
|
311
|
+
filename = options.delete(:filename) || '(__ERB__)'
|
312
|
+
line = options.delete(:line) || 1
|
313
|
+
line -= 1 if instance.src =~ /^#coding:/
|
314
|
+
|
315
|
+
render_binding = binding
|
316
|
+
eval locals_assigns.join("\n"), render_binding
|
317
|
+
eval instance.src, render_binding, filename, line
|
299
318
|
@_out_buf, result = original_out_buf, @_out_buf
|
300
319
|
result
|
301
320
|
end
|
302
321
|
|
303
|
-
def render_haml(template, data, options, &block)
|
304
|
-
|
305
|
-
engine.render(self, options[:locals] || {}, &block)
|
322
|
+
def render_haml(template, data, options, locals, &block)
|
323
|
+
::Haml::Engine.new(data, options).render(self, locals, &block)
|
306
324
|
end
|
307
325
|
|
308
|
-
def render_sass(template, data, options, &block)
|
309
|
-
|
310
|
-
engine.render
|
326
|
+
def render_sass(template, data, options, locals, &block)
|
327
|
+
::Sass::Engine.new(data, options).render
|
311
328
|
end
|
312
329
|
|
313
|
-
def render_builder(template, data, options, &block)
|
314
|
-
|
330
|
+
def render_builder(template, data, options, locals, &block)
|
331
|
+
options = { :indent => 2 }.merge(options)
|
332
|
+
filename = options.delete(:filename) || '<BUILDER>'
|
333
|
+
line = options.delete(:line) || 1
|
334
|
+
xml = ::Builder::XmlMarkup.new(options)
|
315
335
|
if data.respond_to?(:to_str)
|
316
|
-
eval data.to_str, binding,
|
336
|
+
eval data.to_str, binding, filename, line
|
317
337
|
elsif data.kind_of?(Proc)
|
318
338
|
data.call(xml)
|
319
339
|
end
|
320
340
|
xml.target!
|
321
341
|
end
|
342
|
+
|
343
|
+
def require_warn(engine)
|
344
|
+
warn "Auto-require of #{engine} is deprecated; add require '#{engine}' to your app."
|
345
|
+
require engine.downcase
|
346
|
+
end
|
322
347
|
end
|
323
348
|
|
324
349
|
# Base class for all Sinatra applications and middleware.
|
@@ -368,13 +393,16 @@ module Sinatra
|
|
368
393
|
self.class
|
369
394
|
end
|
370
395
|
|
371
|
-
# Exit the current block
|
396
|
+
# Exit the current block, halts any further processing
|
397
|
+
# of the request, and returns the specified response.
|
372
398
|
def halt(*response)
|
373
399
|
response = response.first if response.length == 1
|
374
400
|
throw :halt, response
|
375
401
|
end
|
376
402
|
|
377
403
|
# Pass control to the next matching route.
|
404
|
+
# If there are no more matching routes, Sinatra will
|
405
|
+
# return a 404 response.
|
378
406
|
def pass
|
379
407
|
throw :pass
|
380
408
|
end
|
@@ -392,7 +420,13 @@ module Sinatra
|
|
392
420
|
private
|
393
421
|
# Run before filters and then locate and run a matching route.
|
394
422
|
def route!
|
395
|
-
|
423
|
+
# enable nested params in Rack < 1.0; allow indifferent access
|
424
|
+
@params =
|
425
|
+
if Rack::Utils.respond_to?(:parse_nested_query)
|
426
|
+
indifferent_params(@request.params)
|
427
|
+
else
|
428
|
+
nested_params(@request.params)
|
429
|
+
end
|
396
430
|
|
397
431
|
# before filters
|
398
432
|
self.class.filters.each { |block| instance_eval(&block) }
|
@@ -426,14 +460,26 @@ module Sinatra
|
|
426
460
|
catch(:pass) do
|
427
461
|
conditions.each { |cond|
|
428
462
|
throw :pass if instance_eval(&cond) == false }
|
429
|
-
|
463
|
+
route_eval(&block)
|
430
464
|
end
|
431
465
|
end
|
432
466
|
end
|
433
467
|
end
|
434
468
|
|
435
|
-
|
436
|
-
|
469
|
+
route_missing
|
470
|
+
end
|
471
|
+
|
472
|
+
# Run a route block and throw :halt with the result.
|
473
|
+
def route_eval(&block)
|
474
|
+
throw :halt, instance_eval(&block)
|
475
|
+
end
|
476
|
+
|
477
|
+
# No matching route was found or all routes passed. The default
|
478
|
+
# implementation is to forward the request downstream when running
|
479
|
+
# as middleware (@app is non-nil); when no downstream app is set, raise
|
480
|
+
# a NotFound exception. Subclasses can override this method to perform
|
481
|
+
# custom route miss logic.
|
482
|
+
def route_missing
|
437
483
|
if @app
|
438
484
|
forward
|
439
485
|
else
|
@@ -441,6 +487,18 @@ module Sinatra
|
|
441
487
|
end
|
442
488
|
end
|
443
489
|
|
490
|
+
# Enable string or symbol key access to the nested params hash.
|
491
|
+
def indifferent_params(params)
|
492
|
+
params = indifferent_hash.merge(params)
|
493
|
+
params.each do |key, value|
|
494
|
+
next unless value.is_a?(Hash)
|
495
|
+
params[key] = indifferent_params(value)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
# Recursively replace the params hash with a nested indifferent
|
500
|
+
# hash. Rack 1.0 has a built in implementation of this method - remove
|
501
|
+
# this once Rack 1.0 is required.
|
444
502
|
def nested_params(params)
|
445
503
|
return indifferent_hash.merge(params) if !params.keys.join.include?('[')
|
446
504
|
params.inject indifferent_hash do |res, (key,val)|
|
@@ -512,7 +570,7 @@ module Sinatra
|
|
512
570
|
@env['sinatra.error'] = boom
|
513
571
|
|
514
572
|
dump_errors!(boom) if options.dump_errors?
|
515
|
-
raise boom if options.raise_errors?
|
573
|
+
raise boom if options.raise_errors? || options.show_exceptions?
|
516
574
|
|
517
575
|
@response.status = 500
|
518
576
|
error_block! boom.class, Exception
|
@@ -553,12 +611,14 @@ module Sinatra
|
|
553
611
|
@middleware = []
|
554
612
|
@errors = {}
|
555
613
|
@prototype = nil
|
614
|
+
@extensions = []
|
556
615
|
|
557
616
|
class << self
|
558
617
|
attr_accessor :routes, :filters, :conditions, :templates,
|
559
618
|
:middleware, :errors
|
560
619
|
|
561
|
-
|
620
|
+
# Sets an option to the given value. If the value is a proc,
|
621
|
+
# the proc will be called every time the option is accessed.
|
562
622
|
def set(option, value=self)
|
563
623
|
if value.kind_of?(Proc)
|
564
624
|
metadef(option, &value)
|
@@ -574,14 +634,19 @@ module Sinatra
|
|
574
634
|
self
|
575
635
|
end
|
576
636
|
|
637
|
+
# Same as calling `set :option, true` for each of the given options.
|
577
638
|
def enable(*opts)
|
578
639
|
opts.each { |key| set(key, true) }
|
579
640
|
end
|
580
641
|
|
642
|
+
# Same as calling `set :option, false` for each of the given options.
|
581
643
|
def disable(*opts)
|
582
644
|
opts.each { |key| set(key, false) }
|
583
645
|
end
|
584
646
|
|
647
|
+
# Define a custom error handler. Optionally takes either an Exception
|
648
|
+
# class, or an HTTP status code to specify which errors should be
|
649
|
+
# handled.
|
585
650
|
def error(codes=Exception, &block)
|
586
651
|
if codes.respond_to? :each
|
587
652
|
codes.each { |err| error(err, &block) }
|
@@ -590,29 +655,38 @@ module Sinatra
|
|
590
655
|
end
|
591
656
|
end
|
592
657
|
|
658
|
+
# Sugar for `error(404) { ... }`
|
593
659
|
def not_found(&block)
|
594
660
|
error 404, &block
|
595
661
|
end
|
596
662
|
|
663
|
+
# Define a named template. The block must return the template source.
|
597
664
|
def template(name, &block)
|
598
|
-
|
665
|
+
filename, line = caller_locations.first
|
666
|
+
templates[name] = { :filename => filename, :line => line, :template => block }
|
599
667
|
end
|
600
668
|
|
669
|
+
# Define the layout template. The block must return the template source.
|
601
670
|
def layout(name=:layout, &block)
|
602
671
|
template name, &block
|
603
672
|
end
|
604
673
|
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
674
|
+
# Load embeded templates from the file; uses the caller's __FILE__
|
675
|
+
# when no file is specified.
|
676
|
+
def use_in_file_templates!(file=nil)
|
677
|
+
file ||= caller_files.first
|
678
|
+
app, data =
|
679
|
+
::IO.read(file).split(/^__END__$/, 2) rescue nil
|
680
|
+
|
681
|
+
if data
|
611
682
|
data.gsub!(/\r\n/, "\n")
|
683
|
+
lines = app.count("\n") + 1
|
612
684
|
template = nil
|
613
685
|
data.each_line do |line|
|
686
|
+
lines += 1
|
614
687
|
if line =~ /^@@\s*(.*)/
|
615
|
-
template =
|
688
|
+
template = ''
|
689
|
+
templates[$1.to_sym] = { :filename => file, :line => lines, :template => template }
|
616
690
|
elsif template
|
617
691
|
template << line
|
618
692
|
end
|
@@ -627,10 +701,15 @@ module Sinatra
|
|
627
701
|
Rack::Mime.mime_type(type, nil)
|
628
702
|
end
|
629
703
|
|
704
|
+
# Define a before filter. Filters are run before all requests
|
705
|
+
# within the same context as route handlers and may access/modify the
|
706
|
+
# request and response.
|
630
707
|
def before(&block)
|
631
708
|
@filters << block
|
632
709
|
end
|
633
710
|
|
711
|
+
# Add a route condition. The route is considered non-matching when the
|
712
|
+
# block returns false.
|
634
713
|
def condition(&block)
|
635
714
|
@conditions << block
|
636
715
|
end
|
@@ -650,8 +729,9 @@ module Sinatra
|
|
650
729
|
end
|
651
730
|
}
|
652
731
|
end
|
732
|
+
alias_method :agent, :user_agent
|
653
733
|
|
654
|
-
def
|
734
|
+
def provides(*types)
|
655
735
|
types = [types] unless types.kind_of? Array
|
656
736
|
types.map!{|t| media_type(t)}
|
657
737
|
|
@@ -667,6 +747,8 @@ module Sinatra
|
|
667
747
|
end
|
668
748
|
|
669
749
|
public
|
750
|
+
# Defining a `GET` handler also automatically defines
|
751
|
+
# a `HEAD` handler.
|
670
752
|
def get(path, opts={}, &block)
|
671
753
|
conditions = @conditions.dup
|
672
754
|
route('GET', path, opts, &block)
|
@@ -675,16 +757,17 @@ module Sinatra
|
|
675
757
|
route('HEAD', path, opts, &block)
|
676
758
|
end
|
677
759
|
|
678
|
-
def put(path, opts={}, &bk);
|
679
|
-
def post(path, opts={}, &bk);
|
680
|
-
def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk
|
681
|
-
def head(path, opts={}, &bk);
|
760
|
+
def put(path, opts={}, &bk); route 'PUT', path, opts, &bk end
|
761
|
+
def post(path, opts={}, &bk); route 'POST', path, opts, &bk end
|
762
|
+
def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk end
|
763
|
+
def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk end
|
682
764
|
|
683
765
|
private
|
684
|
-
def route(verb, path,
|
685
|
-
|
686
|
-
|
687
|
-
|
766
|
+
def route(verb, path, options={}, &block)
|
767
|
+
# Because of self.options.host
|
768
|
+
host_name(options.delete(:host)) if options.key?(:host)
|
769
|
+
|
770
|
+
options.each {|option, args| send(option, *args)}
|
688
771
|
|
689
772
|
pattern, keys = compile(path)
|
690
773
|
conditions, @conditions = @conditions, []
|
@@ -698,16 +781,22 @@ module Sinatra
|
|
698
781
|
lambda { unbound_method.bind(self).call }
|
699
782
|
end
|
700
783
|
|
784
|
+
invoke_hook(:route_added, verb, path, block)
|
785
|
+
|
701
786
|
(routes[verb] ||= []).
|
702
787
|
push([pattern, keys, conditions, block]).last
|
703
788
|
end
|
704
789
|
|
790
|
+
def invoke_hook(name, *args)
|
791
|
+
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
792
|
+
end
|
793
|
+
|
705
794
|
def compile(path)
|
706
795
|
keys = []
|
707
796
|
if path.respond_to? :to_str
|
708
797
|
special_chars = %w{. + ( )}
|
709
798
|
pattern =
|
710
|
-
path.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
|
799
|
+
path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
|
711
800
|
case match
|
712
801
|
when "*"
|
713
802
|
keys << 'splat'
|
@@ -720,6 +809,8 @@ module Sinatra
|
|
720
809
|
end
|
721
810
|
end
|
722
811
|
[/^#{pattern}$/, keys]
|
812
|
+
elsif path.respond_to?(:keys) && path.respond_to?(:match)
|
813
|
+
[path, path.keys]
|
723
814
|
elsif path.respond_to? :match
|
724
815
|
[path, keys]
|
725
816
|
else
|
@@ -728,33 +819,44 @@ module Sinatra
|
|
728
819
|
end
|
729
820
|
|
730
821
|
public
|
822
|
+
# Makes the methods defined in the block and in the Modules given
|
823
|
+
# in `extensions` available to the handlers and templates
|
731
824
|
def helpers(*extensions, &block)
|
732
825
|
class_eval(&block) if block_given?
|
733
|
-
include
|
826
|
+
include(*extensions) if extensions.any?
|
827
|
+
end
|
828
|
+
|
829
|
+
def extensions
|
830
|
+
(@extensions + (superclass.extensions rescue [])).uniq
|
734
831
|
end
|
735
832
|
|
736
833
|
def register(*extensions, &block)
|
737
834
|
extensions << Module.new(&block) if block_given?
|
835
|
+
@extensions += extensions
|
738
836
|
extensions.each do |extension|
|
739
837
|
extend extension
|
740
838
|
extension.registered(self) if extension.respond_to?(:registered)
|
741
839
|
end
|
742
840
|
end
|
743
841
|
|
744
|
-
def development
|
745
|
-
def
|
746
|
-
def
|
842
|
+
def development?; environment == :development end
|
843
|
+
def production?; environment == :production end
|
844
|
+
def test?; environment == :test end
|
747
845
|
|
846
|
+
# Set configuration options for Sinatra and/or the app.
|
847
|
+
# Allows scoping of settings for certain environments.
|
748
848
|
def configure(*envs, &block)
|
749
|
-
|
750
|
-
yield if envs.empty? || envs.include?(environment.to_sym)
|
849
|
+
yield self if envs.empty? || envs.include?(environment.to_sym)
|
751
850
|
end
|
752
851
|
|
852
|
+
# Use the specified Rack middleware
|
753
853
|
def use(middleware, *args, &block)
|
754
854
|
@prototype = nil
|
755
855
|
@middleware << [middleware, args, block]
|
756
856
|
end
|
757
857
|
|
858
|
+
# Run the Sinatra app as a self-hosted server using
|
859
|
+
# Thin, Mongrel or WEBrick (in that order)
|
758
860
|
def run!(options={})
|
759
861
|
set options
|
760
862
|
handler = detect_rack_handler
|
@@ -783,30 +885,17 @@ module Sinatra
|
|
783
885
|
def new(*args, &bk)
|
784
886
|
builder = Rack::Builder.new
|
785
887
|
builder.use Rack::Session::Cookie if sessions? && !test?
|
786
|
-
builder.use Rack::CommonLogger
|
787
|
-
builder.use Rack::MethodOverride
|
788
|
-
|
888
|
+
builder.use Rack::CommonLogger if logging?
|
889
|
+
builder.use Rack::MethodOverride if methodoverride?
|
890
|
+
builder.use ShowExceptions if show_exceptions?
|
891
|
+
|
892
|
+
@middleware.each { |c,a,b| builder.use(c, *a, &b) }
|
789
893
|
builder.run super
|
790
894
|
builder.to_app
|
791
895
|
end
|
792
896
|
|
793
897
|
def call(env)
|
794
|
-
synchronize
|
795
|
-
reload! if reload?
|
796
|
-
prototype.call(env)
|
797
|
-
end
|
798
|
-
end
|
799
|
-
|
800
|
-
def reloading?
|
801
|
-
@reloading
|
802
|
-
end
|
803
|
-
|
804
|
-
def reload!
|
805
|
-
@reloading = true
|
806
|
-
reset!
|
807
|
-
$LOADED_FEATURES.delete("sinatra.rb")
|
808
|
-
::Kernel.load app_file
|
809
|
-
@reloading = false
|
898
|
+
synchronize { prototype.call(env) }
|
810
899
|
end
|
811
900
|
|
812
901
|
def reset!(base=superclass)
|
@@ -817,6 +906,7 @@ module Sinatra
|
|
817
906
|
@errors = base.errors.dup
|
818
907
|
@middleware = base.middleware.dup
|
819
908
|
@prototype = nil
|
909
|
+
@extensions = []
|
820
910
|
end
|
821
911
|
|
822
912
|
protected
|
@@ -832,7 +922,7 @@ module Sinatra
|
|
832
922
|
servers = Array(self.server)
|
833
923
|
servers.each do |server_name|
|
834
924
|
begin
|
835
|
-
return Rack::Handler.get(server_name)
|
925
|
+
return Rack::Handler.get(server_name.capitalize)
|
836
926
|
rescue LoadError
|
837
927
|
rescue NameError
|
838
928
|
end
|
@@ -858,11 +948,36 @@ module Sinatra
|
|
858
948
|
(class << self; self; end).
|
859
949
|
send :define_method, message, &block
|
860
950
|
end
|
951
|
+
|
952
|
+
public
|
953
|
+
CALLERS_TO_IGNORE = [
|
954
|
+
/lib\/sinatra.*\.rb$/, # all sinatra code
|
955
|
+
/\(.*\)/, # generated code
|
956
|
+
/custom_require\.rb$/, # rubygems require hacks
|
957
|
+
/active_support/, # active_support require hacks
|
958
|
+
] unless self.const_defined?('CALLERS_TO_IGNORE')
|
959
|
+
|
960
|
+
# add rubinius (and hopefully other VM impls) ignore patterns ...
|
961
|
+
CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
|
962
|
+
|
963
|
+
# Like Kernel#caller but excluding certain magic entries and without
|
964
|
+
# line / method information; the resulting array contains filenames only.
|
965
|
+
def caller_files
|
966
|
+
caller_locations.
|
967
|
+
map { |file,line| file }
|
968
|
+
end
|
969
|
+
|
970
|
+
def caller_locations
|
971
|
+
caller(1).
|
972
|
+
map { |line| line.split(/:(?=\d|in )/)[0,2] }.
|
973
|
+
reject { |file,line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
974
|
+
end
|
861
975
|
end
|
862
976
|
|
863
977
|
set :raise_errors, true
|
864
978
|
set :dump_errors, false
|
865
979
|
set :clean_trace, true
|
980
|
+
set :show_exceptions, Proc.new { development? }
|
866
981
|
set :sessions, false
|
867
982
|
set :logging, false
|
868
983
|
set :methodoverride, false
|
@@ -878,8 +993,7 @@ module Sinatra
|
|
878
993
|
set :root, Proc.new { app_file && File.expand_path(File.dirname(app_file)) }
|
879
994
|
set :views, Proc.new { root && File.join(root, 'views') }
|
880
995
|
set :public, Proc.new { root && File.join(root, 'public') }
|
881
|
-
set :
|
882
|
-
set :lock, Proc.new { reload? }
|
996
|
+
set :lock, false
|
883
997
|
|
884
998
|
# static files route
|
885
999
|
get(/.*[^\/]$/) do
|
@@ -905,6 +1019,8 @@ module Sinatra
|
|
905
1019
|
end
|
906
1020
|
|
907
1021
|
error NotFound do
|
1022
|
+
content_type 'text/html'
|
1023
|
+
|
908
1024
|
(<<-HTML).gsub(/^ {8}/, '')
|
909
1025
|
<!DOCTYPE html>
|
910
1026
|
<html>
|
@@ -926,35 +1042,6 @@ module Sinatra
|
|
926
1042
|
</html>
|
927
1043
|
HTML
|
928
1044
|
end
|
929
|
-
|
930
|
-
error do
|
931
|
-
next unless err = request.env['sinatra.error']
|
932
|
-
heading = err.class.name + ' - ' + err.message.to_s
|
933
|
-
(<<-HTML).gsub(/^ {8}/, '')
|
934
|
-
<!DOCTYPE html>
|
935
|
-
<html>
|
936
|
-
<head>
|
937
|
-
<style type="text/css">
|
938
|
-
body {font-family:verdana;color:#333}
|
939
|
-
#c {margin-left:20px}
|
940
|
-
h1 {color:#1D6B8D;margin:0;margin-top:-30px}
|
941
|
-
h2 {color:#1D6B8D;font-size:18px}
|
942
|
-
pre {border-left:2px solid #ddd;padding-left:10px;color:#000}
|
943
|
-
img {margin-top:10px}
|
944
|
-
</style>
|
945
|
-
</head>
|
946
|
-
<body>
|
947
|
-
<div id="c">
|
948
|
-
<img src="/__sinatra__/500.png">
|
949
|
-
<h1>#{escape_html(heading)}</h1>
|
950
|
-
<pre>#{escape_html(clean_backtrace(err.backtrace) * "\n")}</pre>
|
951
|
-
<h2>Params</h2>
|
952
|
-
<pre>#{escape_html(params.inspect)}</pre>
|
953
|
-
</div>
|
954
|
-
</body>
|
955
|
-
</html>
|
956
|
-
HTML
|
957
|
-
end
|
958
1045
|
end
|
959
1046
|
end
|
960
1047
|
|
@@ -970,7 +1057,7 @@ module Sinatra
|
|
970
1057
|
|
971
1058
|
def self.register(*extensions, &block) #:nodoc:
|
972
1059
|
added_methods = extensions.map {|m| m.public_instance_methods }.flatten
|
973
|
-
Delegator.delegate
|
1060
|
+
Delegator.delegate(*added_methods)
|
974
1061
|
super(*extensions, &block)
|
975
1062
|
end
|
976
1063
|
end
|
@@ -980,14 +1067,17 @@ module Sinatra
|
|
980
1067
|
class Application < Default
|
981
1068
|
end
|
982
1069
|
|
1070
|
+
# Sinatra delegation mixin. Mixing this module into an object causes all
|
1071
|
+
# methods to be delegated to the Sinatra::Application class. Used primarily
|
1072
|
+
# at the top-level.
|
983
1073
|
module Delegator #:nodoc:
|
984
1074
|
def self.delegate(*methods)
|
985
1075
|
methods.each do |method_name|
|
986
1076
|
eval <<-RUBY, binding, '(__DELEGATE__)', 1
|
987
1077
|
def #{method_name}(*args, &b)
|
988
|
-
::Sinatra::Application
|
1078
|
+
::Sinatra::Application.send(#{method_name.inspect}, *args, &b)
|
989
1079
|
end
|
990
|
-
private
|
1080
|
+
private #{method_name.inspect}
|
991
1081
|
RUBY
|
992
1082
|
end
|
993
1083
|
end
|
@@ -998,6 +1088,8 @@ module Sinatra
|
|
998
1088
|
:production?, :use_in_file_templates!, :helpers
|
999
1089
|
end
|
1000
1090
|
|
1091
|
+
# Create a new Sinatra application. The block is evaluated in the new app's
|
1092
|
+
# class scope.
|
1001
1093
|
def self.new(base=Base, options={}, &block)
|
1002
1094
|
base = Class.new(base)
|
1003
1095
|
base.send :class_eval, &block if block_given?
|