sinatra 1.0 → 1.1.a
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 +108 -1
- data/LICENSE +1 -1
- data/README.de.rdoc +1024 -0
- data/README.es.rdoc +1047 -0
- data/README.fr.rdoc +1038 -0
- data/README.hu.rdoc +607 -0
- data/README.jp.rdoc +473 -15
- data/README.rdoc +429 -41
- data/Rakefile +17 -6
- data/lib/sinatra/base.rb +357 -158
- data/lib/sinatra/showexceptions.rb +9 -1
- data/sinatra.gemspec +52 -9
- data/test/builder_test.rb +25 -1
- data/test/coffee_test.rb +88 -0
- data/test/encoding_test.rb +18 -0
- data/test/filter_test.rb +61 -2
- data/test/hello.mab +1 -0
- data/test/helper.rb +1 -0
- data/test/helpers_test.rb +141 -37
- data/test/less_test.rb +26 -2
- data/test/liquid_test.rb +58 -0
- data/test/markaby_test.rb +58 -0
- data/test/markdown_test.rb +35 -0
- data/test/nokogiri_test.rb +69 -0
- data/test/radius_test.rb +59 -0
- data/test/rdoc_test.rb +34 -0
- data/test/request_test.rb +12 -0
- data/test/routing_test.rb +35 -1
- data/test/sass_test.rb +46 -16
- data/test/scss_test.rb +88 -0
- data/test/settings_test.rb +32 -0
- data/test/sinatra_test.rb +4 -0
- data/test/static_test.rb +64 -0
- data/test/templates_test.rb +55 -1
- data/test/textile_test.rb +34 -0
- data/test/views/ascii.haml +2 -0
- data/test/views/explicitly_nested.str +1 -0
- data/test/views/hello.coffee +1 -0
- data/test/views/hello.liquid +1 -0
- data/test/views/hello.mab +1 -0
- data/test/views/hello.md +1 -0
- data/test/views/hello.nokogiri +1 -0
- data/test/views/hello.radius +1 -0
- data/test/views/hello.rdoc +1 -0
- data/test/views/hello.sass +1 -1
- data/test/views/hello.scss +3 -0
- data/test/views/hello.str +1 -0
- data/test/views/hello.textile +1 -0
- data/test/views/layout2.liquid +2 -0
- data/test/views/layout2.mab +2 -0
- data/test/views/layout2.nokogiri +3 -0
- data/test/views/layout2.radius +2 -0
- data/test/views/layout2.str +2 -0
- data/test/views/nested.str +1 -0
- data/test/views/utf8.haml +2 -0
- metadata +240 -33
- data/lib/sinatra/tilt.rb +0 -746
@@ -1,12 +1,20 @@
|
|
1
1
|
require 'rack/showexceptions'
|
2
2
|
|
3
3
|
module Sinatra
|
4
|
+
# Sinatra::ShowExceptions catches all exceptions raised from the app it
|
5
|
+
# wraps. It shows a useful backtrace with the sourcefile and clickable
|
6
|
+
# context, the whole Rack environment and the request data.
|
7
|
+
#
|
8
|
+
# Be careful when you use this on public-facing sites as it could reveal
|
9
|
+
# information helpful to attackers.
|
4
10
|
class ShowExceptions < Rack::ShowExceptions
|
5
11
|
def initialize(app)
|
6
12
|
@app = app
|
7
13
|
@template = ERB.new(TEMPLATE)
|
8
14
|
end
|
9
15
|
|
16
|
+
private
|
17
|
+
|
10
18
|
def frame_class(frame)
|
11
19
|
if frame.filename =~ /lib\/sinatra.*\.rb/
|
12
20
|
"framework"
|
@@ -18,7 +26,7 @@ module Sinatra
|
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
21
|
-
TEMPLATE =
|
29
|
+
TEMPLATE = <<-HTML # :nodoc:
|
22
30
|
<!DOCTYPE html>
|
23
31
|
<html>
|
24
32
|
<head>
|
data/sinatra.gemspec
CHANGED
@@ -3,13 +3,13 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'sinatra'
|
6
|
-
s.version = '1.
|
7
|
-
s.date = '2010-
|
6
|
+
s.version = '1.1.a'
|
7
|
+
s.date = '2010-10-19'
|
8
8
|
|
9
9
|
s.description = "Classy web-development dressed in a DSL"
|
10
10
|
s.summary = "Classy web-development dressed in a DSL"
|
11
11
|
|
12
|
-
s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet"]
|
12
|
+
s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet", "Konstantin Haase"]
|
13
13
|
s.email = "sinatrarb@googlegroups.com"
|
14
14
|
|
15
15
|
# = MANIFEST =
|
@@ -17,6 +17,10 @@ Gem::Specification.new do |s|
|
|
17
17
|
AUTHORS
|
18
18
|
CHANGES
|
19
19
|
LICENSE
|
20
|
+
README.de.rdoc
|
21
|
+
README.es.rdoc
|
22
|
+
README.fr.rdoc
|
23
|
+
README.hu.rdoc
|
20
24
|
README.jp.rdoc
|
21
25
|
README.rdoc
|
22
26
|
Rakefile
|
@@ -26,64 +30,103 @@ Gem::Specification.new do |s|
|
|
26
30
|
lib/sinatra/images/500.png
|
27
31
|
lib/sinatra/main.rb
|
28
32
|
lib/sinatra/showexceptions.rb
|
29
|
-
lib/sinatra/tilt.rb
|
30
33
|
sinatra.gemspec
|
31
34
|
test/base_test.rb
|
32
35
|
test/builder_test.rb
|
36
|
+
test/coffee_test.rb
|
33
37
|
test/contest.rb
|
38
|
+
test/encoding_test.rb
|
34
39
|
test/erb_test.rb
|
35
40
|
test/erubis_test.rb
|
36
41
|
test/extensions_test.rb
|
37
42
|
test/filter_test.rb
|
38
43
|
test/haml_test.rb
|
44
|
+
test/hello.mab
|
39
45
|
test/helper.rb
|
40
46
|
test/helpers_test.rb
|
41
47
|
test/less_test.rb
|
48
|
+
test/liquid_test.rb
|
42
49
|
test/mapped_error_test.rb
|
50
|
+
test/markaby_test.rb
|
51
|
+
test/markdown_test.rb
|
43
52
|
test/middleware_test.rb
|
53
|
+
test/nokogiri_test.rb
|
44
54
|
test/public/favicon.ico
|
55
|
+
test/radius_test.rb
|
56
|
+
test/rdoc_test.rb
|
45
57
|
test/request_test.rb
|
46
58
|
test/response_test.rb
|
47
59
|
test/result_test.rb
|
48
60
|
test/route_added_hook_test.rb
|
49
61
|
test/routing_test.rb
|
50
62
|
test/sass_test.rb
|
63
|
+
test/scss_test.rb
|
51
64
|
test/server_test.rb
|
52
65
|
test/settings_test.rb
|
53
66
|
test/sinatra_test.rb
|
54
67
|
test/static_test.rb
|
55
68
|
test/templates_test.rb
|
69
|
+
test/textile_test.rb
|
70
|
+
test/views/ascii.haml
|
56
71
|
test/views/error.builder
|
57
72
|
test/views/error.erb
|
58
73
|
test/views/error.erubis
|
59
74
|
test/views/error.haml
|
60
75
|
test/views/error.sass
|
76
|
+
test/views/explicitly_nested.str
|
61
77
|
test/views/foo/hello.test
|
62
78
|
test/views/hello.builder
|
79
|
+
test/views/hello.coffee
|
63
80
|
test/views/hello.erb
|
64
81
|
test/views/hello.erubis
|
65
82
|
test/views/hello.haml
|
66
83
|
test/views/hello.less
|
84
|
+
test/views/hello.liquid
|
85
|
+
test/views/hello.mab
|
86
|
+
test/views/hello.md
|
87
|
+
test/views/hello.nokogiri
|
88
|
+
test/views/hello.radius
|
89
|
+
test/views/hello.rdoc
|
67
90
|
test/views/hello.sass
|
91
|
+
test/views/hello.scss
|
92
|
+
test/views/hello.str
|
68
93
|
test/views/hello.test
|
94
|
+
test/views/hello.textile
|
69
95
|
test/views/layout2.builder
|
70
96
|
test/views/layout2.erb
|
71
97
|
test/views/layout2.erubis
|
72
98
|
test/views/layout2.haml
|
99
|
+
test/views/layout2.liquid
|
100
|
+
test/views/layout2.mab
|
101
|
+
test/views/layout2.nokogiri
|
102
|
+
test/views/layout2.radius
|
103
|
+
test/views/layout2.str
|
73
104
|
test/views/layout2.test
|
105
|
+
test/views/nested.str
|
106
|
+
test/views/utf8.haml
|
74
107
|
]
|
75
108
|
# = MANIFEST =
|
76
109
|
|
77
110
|
s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
|
78
111
|
|
79
|
-
s.extra_rdoc_files = %w[README.rdoc LICENSE]
|
80
|
-
s.add_dependency 'rack',
|
81
|
-
s.
|
82
|
-
s.add_development_dependency '
|
83
|
-
s.add_development_dependency '
|
112
|
+
s.extra_rdoc_files = %w[README.rdoc README.de.rdoc README.jp.rdoc README.fr.rdoc README.es.rdoc README.hu.rdoc LICENSE]
|
113
|
+
s.add_dependency 'rack', '~> 1.1'
|
114
|
+
s.add_dependency 'tilt', '~> 1.1'
|
115
|
+
s.add_development_dependency 'rake'
|
116
|
+
s.add_development_dependency 'shotgun', '~> 0.6'
|
117
|
+
s.add_development_dependency 'rack-test', '>= 0.5.6'
|
118
|
+
s.add_development_dependency 'haml', '>= 3.0'
|
84
119
|
s.add_development_dependency 'builder'
|
85
120
|
s.add_development_dependency 'erubis'
|
86
121
|
s.add_development_dependency 'less'
|
122
|
+
s.add_development_dependency 'liquid'
|
123
|
+
s.add_development_dependency 'rdiscount'
|
124
|
+
s.add_development_dependency 'RedCloth'
|
125
|
+
s.add_development_dependency 'radius'
|
126
|
+
s.add_development_dependency 'markaby'
|
127
|
+
s.add_development_dependency 'coffee-script'
|
128
|
+
s.add_development_dependency 'rdoc'
|
129
|
+
s.add_development_dependency 'nokogiri'
|
87
130
|
|
88
131
|
s.has_rdoc = true
|
89
132
|
s.homepage = "http://sinatra.rubyforge.org"
|
data/test/builder_test.rb
CHANGED
@@ -2,9 +2,10 @@ require File.dirname(__FILE__) + '/helper'
|
|
2
2
|
require 'builder'
|
3
3
|
|
4
4
|
class BuilderTest < Test::Unit::TestCase
|
5
|
-
def builder_app(&block)
|
5
|
+
def builder_app(options = {}, &block)
|
6
6
|
mock_app {
|
7
7
|
set :views, File.dirname(__FILE__) + '/views'
|
8
|
+
set options
|
8
9
|
get '/', &block
|
9
10
|
}
|
10
11
|
get '/'
|
@@ -16,6 +17,29 @@ class BuilderTest < Test::Unit::TestCase
|
|
16
17
|
assert_equal %{<?xml version="1.0" encoding="UTF-8"?>\n}, body
|
17
18
|
end
|
18
19
|
|
20
|
+
it 'defaults content type to xml' do
|
21
|
+
builder_app { builder 'xml.instruct!' }
|
22
|
+
assert ok?
|
23
|
+
assert_equal "application/xml;charset=utf-8", response['Content-Type']
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'defaults allows setting content type per route' do
|
27
|
+
builder_app do
|
28
|
+
content_type :html
|
29
|
+
builder 'xml.instruct!'
|
30
|
+
end
|
31
|
+
assert ok?
|
32
|
+
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'defaults allows setting content type globally' do
|
36
|
+
builder_app(:builder => { :content_type => 'html' }) do
|
37
|
+
builder 'xml.instruct!'
|
38
|
+
end
|
39
|
+
assert ok?
|
40
|
+
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
41
|
+
end
|
42
|
+
|
19
43
|
it 'renders inline blocks' do
|
20
44
|
builder_app {
|
21
45
|
@name = "Frank & Mary"
|
data/test/coffee_test.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'coffee-script'
|
5
|
+
|
6
|
+
class CoffeeTest < Test::Unit::TestCase
|
7
|
+
def coffee_app(options = {}, &block)
|
8
|
+
mock_app {
|
9
|
+
set :views, File.dirname(__FILE__) + '/views'
|
10
|
+
set(options)
|
11
|
+
get '/', &block
|
12
|
+
}
|
13
|
+
get '/'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'renders inline Coffee strings' do
|
17
|
+
coffee_app { coffee "alert 'Aye!'\n" }
|
18
|
+
assert ok?
|
19
|
+
assert_equal "(function() {\n alert('Aye!');\n})();\n", body
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'defaults content type to javascript' do
|
23
|
+
coffee_app { coffee "alert 'Aye!'\n" }
|
24
|
+
assert ok?
|
25
|
+
assert_equal "application/javascript;charset=utf-8", response['Content-Type']
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'defaults allows setting content type per route' do
|
29
|
+
coffee_app do
|
30
|
+
content_type :html
|
31
|
+
coffee "alert 'Aye!'\n"
|
32
|
+
end
|
33
|
+
assert ok?
|
34
|
+
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'defaults allows setting content type globally' do
|
38
|
+
coffee_app(:coffee => { :content_type => 'html' }) do
|
39
|
+
coffee "alert 'Aye!'\n"
|
40
|
+
end
|
41
|
+
assert ok?
|
42
|
+
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'renders .coffee files in views path' do
|
46
|
+
coffee_app { coffee :hello }
|
47
|
+
assert ok?
|
48
|
+
assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'ignores the layout option' do
|
52
|
+
coffee_app { coffee :hello, :layout => :layout2 }
|
53
|
+
assert ok?
|
54
|
+
assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raises error if template not found" do
|
58
|
+
mock_app {
|
59
|
+
get('/') { coffee :no_such_template }
|
60
|
+
}
|
61
|
+
assert_raise(Errno::ENOENT) { get('/') }
|
62
|
+
end
|
63
|
+
|
64
|
+
it "passes coffee options to the coffee engine" do
|
65
|
+
coffee_app {
|
66
|
+
coffee "alert 'Aye!'\n",
|
67
|
+
:no_wrap => true
|
68
|
+
}
|
69
|
+
assert ok?
|
70
|
+
assert_equal "alert('Aye!');", body
|
71
|
+
end
|
72
|
+
|
73
|
+
it "passes default coffee options to the coffee engine" do
|
74
|
+
mock_app {
|
75
|
+
set :coffee, :no_wrap => true # default coffee style is :nested
|
76
|
+
get '/' do
|
77
|
+
coffee "alert 'Aye!'\n"
|
78
|
+
end
|
79
|
+
}
|
80
|
+
get '/'
|
81
|
+
assert ok?
|
82
|
+
assert_equal "alert('Aye!');", body
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
rescue
|
87
|
+
warn "#{$!.to_s}: skipping coffee tests"
|
88
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.dirname(__FILE__) + '/helper'
|
3
|
+
|
4
|
+
class BaseTest < Test::Unit::TestCase
|
5
|
+
setup do
|
6
|
+
@base = Sinatra.new(Sinatra::Base)
|
7
|
+
@base.set :views, File.dirname(__FILE__) + "/views"
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'allows unicode strings in ascii templates per default (1.9)' do
|
11
|
+
@base.new.haml(:ascii, {}, :value => "åkej")
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows ascii strings in unicode templates per default (1.9)' do
|
15
|
+
next unless defined? Encoding
|
16
|
+
@base.new.haml(:utf8, {}, :value => "Some Lyrics".encode("ASCII"))
|
17
|
+
end
|
18
|
+
end
|
data/test/filter_test.rb
CHANGED
@@ -55,7 +55,7 @@ class BeforeFilterTest < Test::Unit::TestCase
|
|
55
55
|
|
56
56
|
get '/foo'
|
57
57
|
assert redirect?
|
58
|
-
assert_equal '/bar', response['Location']
|
58
|
+
assert_equal 'http://example.org/bar', response['Location']
|
59
59
|
assert_equal '', body
|
60
60
|
end
|
61
61
|
|
@@ -121,6 +121,29 @@ class BeforeFilterTest < Test::Unit::TestCase
|
|
121
121
|
assert_equal File.read(__FILE__), body
|
122
122
|
assert !ran_filter
|
123
123
|
end
|
124
|
+
|
125
|
+
it 'takes an optional route pattern' do
|
126
|
+
ran_filter = false
|
127
|
+
mock_app do
|
128
|
+
before("/b*") { ran_filter = true }
|
129
|
+
get('/foo') { }
|
130
|
+
get('/bar') { }
|
131
|
+
end
|
132
|
+
get '/foo'
|
133
|
+
assert !ran_filter
|
134
|
+
get '/bar'
|
135
|
+
assert ran_filter
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'generates block arguments from route pattern' do
|
139
|
+
subpath = nil
|
140
|
+
mock_app do
|
141
|
+
before("/foo/:sub") { |s| subpath = s }
|
142
|
+
get('/foo/*') { }
|
143
|
+
end
|
144
|
+
get '/foo/bar'
|
145
|
+
assert_equal subpath, 'bar'
|
146
|
+
end
|
124
147
|
end
|
125
148
|
|
126
149
|
class AfterFilterTest < Test::Unit::TestCase
|
@@ -166,7 +189,7 @@ class AfterFilterTest < Test::Unit::TestCase
|
|
166
189
|
|
167
190
|
get '/foo'
|
168
191
|
assert redirect?
|
169
|
-
assert_equal '/bar', response['Location']
|
192
|
+
assert_equal 'http://example.org/bar', response['Location']
|
170
193
|
assert_equal '', body
|
171
194
|
end
|
172
195
|
|
@@ -218,4 +241,40 @@ class AfterFilterTest < Test::Unit::TestCase
|
|
218
241
|
assert_equal File.read(__FILE__), body
|
219
242
|
assert !ran_filter
|
220
243
|
end
|
244
|
+
|
245
|
+
it 'takes an optional route pattern' do
|
246
|
+
ran_filter = false
|
247
|
+
mock_app do
|
248
|
+
after("/b*") { ran_filter = true }
|
249
|
+
get('/foo') { }
|
250
|
+
get('/bar') { }
|
251
|
+
end
|
252
|
+
get '/foo'
|
253
|
+
assert !ran_filter
|
254
|
+
get '/bar'
|
255
|
+
assert ran_filter
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'generates block arguments from route pattern' do
|
259
|
+
subpath = nil
|
260
|
+
mock_app do
|
261
|
+
after("/foo/:sub") { |s| subpath = s }
|
262
|
+
get('/foo/*') { }
|
263
|
+
end
|
264
|
+
get '/foo/bar'
|
265
|
+
assert_equal subpath, 'bar'
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'is possible to access url params from the route param' do
|
269
|
+
ran = false
|
270
|
+
mock_app do
|
271
|
+
get('/foo/*') { }
|
272
|
+
before('/foo/:sub') do
|
273
|
+
assert_equal params[:sub], 'bar'
|
274
|
+
ran = true
|
275
|
+
end
|
276
|
+
end
|
277
|
+
get '/foo/bar'
|
278
|
+
assert ran
|
279
|
+
end
|
221
280
|
end
|
data/test/hello.mab
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
h1 "Hello From Markaby"
|
data/test/helper.rb
CHANGED
data/test/helpers_test.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
|
+
require 'date'
|
2
3
|
|
3
4
|
class HelpersTest < Test::Unit::TestCase
|
4
5
|
def test_default
|
@@ -57,7 +58,7 @@ class HelpersTest < Test::Unit::TestCase
|
|
57
58
|
get '/'
|
58
59
|
assert_equal 302, status
|
59
60
|
assert_equal '', body
|
60
|
-
assert_equal '/foo', response['Location']
|
61
|
+
assert_equal 'http://example.org/foo', response['Location']
|
61
62
|
end
|
62
63
|
|
63
64
|
it 'uses the code given when specified' do
|
@@ -71,7 +72,7 @@ class HelpersTest < Test::Unit::TestCase
|
|
71
72
|
get '/'
|
72
73
|
assert_equal 301, status
|
73
74
|
assert_equal '', body
|
74
|
-
assert_equal '/foo', response['Location']
|
75
|
+
assert_equal 'http://example.org/foo', response['Location']
|
75
76
|
end
|
76
77
|
|
77
78
|
it 'redirects back to request.referer when passed back' do
|
@@ -84,7 +85,31 @@ class HelpersTest < Test::Unit::TestCase
|
|
84
85
|
request = Rack::MockRequest.new(@app)
|
85
86
|
response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
|
86
87
|
assert_equal 302, response.status
|
87
|
-
assert_equal '/foo', response['Location']
|
88
|
+
assert_equal 'http://example.org/foo', response['Location']
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'redirects using a non-standard HTTP port' do
|
92
|
+
mock_app {
|
93
|
+
get '/' do
|
94
|
+
redirect '/foo'
|
95
|
+
end
|
96
|
+
}
|
97
|
+
|
98
|
+
request = Rack::MockRequest.new(@app)
|
99
|
+
response = request.get('/', 'SERVER_PORT' => '81')
|
100
|
+
assert_equal 'http://example.org:81/foo', response['Location']
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'redirects using a non-standard HTTPS port' do
|
104
|
+
mock_app {
|
105
|
+
get '/' do
|
106
|
+
redirect '/foo'
|
107
|
+
end
|
108
|
+
}
|
109
|
+
|
110
|
+
request = Rack::MockRequest.new(@app)
|
111
|
+
response = request.get('/', 'SERVER_PORT' => '444')
|
112
|
+
assert_equal 'http://example.org:444/foo', response['Location']
|
88
113
|
end
|
89
114
|
end
|
90
115
|
|
@@ -266,21 +291,21 @@ class HelpersTest < Test::Unit::TestCase
|
|
266
291
|
}
|
267
292
|
|
268
293
|
get '/'
|
269
|
-
assert_equal 'text/plain', response['Content-Type']
|
294
|
+
assert_equal 'text/plain;charset=utf-8', response['Content-Type']
|
270
295
|
assert_equal 'Hello World', body
|
271
296
|
end
|
272
297
|
|
273
298
|
it 'takes media type parameters (like charset=)' do
|
274
299
|
mock_app {
|
275
300
|
get '/' do
|
276
|
-
content_type 'text/html', :charset => '
|
301
|
+
content_type 'text/html', :charset => 'latin1'
|
277
302
|
"<h1>Hello, World</h1>"
|
278
303
|
end
|
279
304
|
}
|
280
305
|
|
281
306
|
get '/'
|
282
307
|
assert ok?
|
283
|
-
assert_equal 'text/html;charset=
|
308
|
+
assert_equal 'text/html;charset=latin1', response['Content-Type']
|
284
309
|
assert_equal "<h1>Hello, World</h1>", body
|
285
310
|
end
|
286
311
|
|
@@ -295,7 +320,7 @@ class HelpersTest < Test::Unit::TestCase
|
|
295
320
|
|
296
321
|
get '/foo.xml'
|
297
322
|
assert ok?
|
298
|
-
assert_equal 'application/foo', response['Content-Type']
|
323
|
+
assert_equal 'application/foo;charset=utf-8', response['Content-Type']
|
299
324
|
assert_equal 'I AM FOO', body
|
300
325
|
end
|
301
326
|
|
@@ -341,7 +366,19 @@ class HelpersTest < Test::Unit::TestCase
|
|
341
366
|
it 'sets the Content-Type response header if a mime-type can be located' do
|
342
367
|
send_file_app
|
343
368
|
get '/file.txt'
|
344
|
-
assert_equal 'text/plain', response['Content-Type']
|
369
|
+
assert_equal 'text/plain;charset=utf-8', response['Content-Type']
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'sets the Content-Type response header if type option is set to a file extesion' do
|
373
|
+
send_file_app :type => 'html'
|
374
|
+
get '/file.txt'
|
375
|
+
assert_equal 'text/html;charset=utf-8', response['Content-Type']
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'sets the Content-Type response header if type option is set to a mime type' do
|
379
|
+
send_file_app :type => 'application/octet-stream'
|
380
|
+
get '/file.txt'
|
381
|
+
assert_equal 'application/octet-stream;charset=utf-8', response['Content-Type']
|
345
382
|
end
|
346
383
|
|
347
384
|
it 'sets the Content-Length response header' do
|
@@ -423,42 +460,109 @@ class HelpersTest < Test::Unit::TestCase
|
|
423
460
|
end
|
424
461
|
|
425
462
|
describe 'last_modified' do
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
body { 'Hello World' }
|
431
|
-
last_modified now
|
432
|
-
'Boo!'
|
433
|
-
end
|
434
|
-
}
|
435
|
-
@now = now
|
436
|
-
end
|
463
|
+
it 'ignores nil' do
|
464
|
+
mock_app do
|
465
|
+
get '/' do last_modified nil; 200; end
|
466
|
+
end
|
437
467
|
|
438
|
-
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
439
468
|
get '/'
|
440
|
-
|
469
|
+
assert ! response['Last-Modified']
|
441
470
|
end
|
442
471
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
472
|
+
[Time, DateTime].each do |klass|
|
473
|
+
describe "with #{klass.name}" do
|
474
|
+
setup do
|
475
|
+
last_modified_time = klass.now
|
476
|
+
mock_app do
|
477
|
+
get '/' do
|
478
|
+
last_modified last_modified_time
|
479
|
+
'Boo!'
|
480
|
+
end
|
481
|
+
end
|
482
|
+
@last_modified_time = Time.parse last_modified_time.to_s
|
483
|
+
end
|
448
484
|
|
449
|
-
|
450
|
-
|
451
|
-
assert_equal 304, status
|
452
|
-
assert_equal '', body
|
453
|
-
end
|
485
|
+
# fixes strange missing test error when running complete test suite.
|
486
|
+
it("does not complain about missing tests") { }
|
454
487
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
488
|
+
context "when there's no If-Modified-Since header" do
|
489
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
490
|
+
get '/'
|
491
|
+
assert_equal @last_modified_time.httpdate, response['Last-Modified']
|
492
|
+
end
|
459
493
|
|
460
|
-
|
461
|
-
|
494
|
+
it 'conditional GET misses and returns a body' do
|
495
|
+
get '/'
|
496
|
+
assert_equal 200, status
|
497
|
+
assert_equal 'Boo!', body
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
context "when there's an invalid If-Modified-Since header" do
|
502
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
503
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
|
504
|
+
assert_equal @last_modified_time.httpdate, response['Last-Modified']
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'conditional GET misses and returns a body' do
|
508
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' }
|
509
|
+
assert_equal 200, status
|
510
|
+
assert_equal 'Boo!', body
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
context "when the resource has been modified since the If-Modified-Since header date" do
|
515
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
516
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
|
517
|
+
assert_equal @last_modified_time.httpdate, response['Last-Modified']
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'conditional GET misses and returns a body' do
|
521
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate }
|
522
|
+
assert_equal 200, status
|
523
|
+
assert_equal 'Boo!', body
|
524
|
+
end
|
525
|
+
|
526
|
+
it 'does not rely on string comparison' do
|
527
|
+
mock_app do
|
528
|
+
get '/compare' do
|
529
|
+
last_modified "Mon, 18 Oct 2010 20:57:11 GMT"
|
530
|
+
"foo"
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
get '/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2010 23:43:52 GMT' }
|
535
|
+
assert_equal 200, status
|
536
|
+
assert_equal 'foo', body
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
context "when the resource has been modified on the exact If-Modified-Since header date" do
|
541
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
542
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
|
543
|
+
assert_equal @last_modified_time.httpdate, response['Last-Modified']
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'conditional GET matches and halts' do
|
547
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate }
|
548
|
+
assert_equal 304, status
|
549
|
+
assert_equal '', body
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
context "when the resource hasn't been modified since the If-Modified-Since header date" do
|
554
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
555
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
|
556
|
+
assert_equal @last_modified_time.httpdate, response['Last-Modified']
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'conditional GET matches and halts' do
|
560
|
+
get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate }
|
561
|
+
assert_equal 304, status
|
562
|
+
assert_equal '', body
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
462
566
|
end
|
463
567
|
end
|
464
568
|
|