sinatra 1.1.0 → 1.1.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 +36 -0
- data/README.de.rdoc +7 -7
- data/README.es.rdoc +3 -3
- data/README.fr.rdoc +3 -3
- data/README.jp.rdoc +2 -2
- data/README.pt-br.rdoc +647 -0
- data/README.rdoc +3 -3
- data/README.ru.rdoc +1015 -0
- data/README.zh.rdoc +3 -3
- data/Rakefile +23 -17
- data/lib/sinatra/base.rb +62 -33
- data/sinatra.gemspec +6 -4
- data/test/coffee_test.rb +3 -3
- data/test/filter_test.rb +10 -0
- data/test/haml_test.rb +5 -0
- data/test/helper.rb +4 -0
- data/test/helpers_test.rb +61 -3
- data/test/nokogiri_test.rb +5 -5
- data/test/rdoc_test.rb +2 -2
- data/test/routing_test.rb +9 -0
- data/test/templates_test.rb +19 -1
- metadata +11 -8
data/README.zh.rdoc
CHANGED
@@ -859,7 +859,7 @@ Sinatra::Base子类可用的方法实际上就是
|
|
859
859
|
require 'sinatra/base'
|
860
860
|
|
861
861
|
class LoginScreen < Sinatra::Base
|
862
|
-
enable :
|
862
|
+
enable :sessions
|
863
863
|
|
864
864
|
get('/login') { haml :login }
|
865
865
|
|
@@ -901,7 +901,7 @@ Sinatra::Application,或者这个类就是你显式创建的子类。
|
|
901
901
|
|
902
902
|
通过 `set` 创建的选项是类层面的方法:
|
903
903
|
|
904
|
-
class MyApp
|
904
|
+
class MyApp < Sinatra::Base
|
905
905
|
# 嘿,我在应用变量域!
|
906
906
|
set :foo, 42
|
907
907
|
foo # => 42
|
@@ -931,7 +931,7 @@ Sinatra::Application,或者这个类就是你显式创建的子类。
|
|
931
931
|
`erb` 或者 `haml`。你可以在请求变量域当中通过`settings`辅助方法
|
932
932
|
访问应用变量域:
|
933
933
|
|
934
|
-
class MyApp
|
934
|
+
class MyApp < Sinatra::Base
|
935
935
|
# 嘿,我在应用变量域!
|
936
936
|
get '/define_route/:name' do
|
937
937
|
# 针对 '/define_route/:name' 的请求变量域
|
data/Rakefile
CHANGED
@@ -12,6 +12,10 @@ def source_version
|
|
12
12
|
end
|
13
13
|
|
14
14
|
# SPECS ===============================================================
|
15
|
+
task :test do
|
16
|
+
ENV['LANG'] = 'C'
|
17
|
+
ENV.delete 'LC_CTYPE'
|
18
|
+
end
|
15
19
|
|
16
20
|
if !ENV['NO_TEST_FIX'] and RUBY_VERSION == '1.9.2' and RUBY_PATCHLEVEL == 0
|
17
21
|
# Avoids seg fault
|
@@ -44,26 +48,28 @@ end
|
|
44
48
|
|
45
49
|
desc 'Generate RDoc under doc/api'
|
46
50
|
task 'doc' => ['doc:api']
|
51
|
+
task('doc:api') { sh "yardoc -o doc/api" }
|
52
|
+
CLEAN.include 'doc/api'
|
47
53
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
54
|
+
# README ===============================================================
|
55
|
+
task :add_template, [:name] do |t, args|
|
56
|
+
Dir.glob('README.*') do |file|
|
57
|
+
code = File.read(file)
|
58
|
+
if code =~ /^===.*#{args.name.capitalize}/
|
59
|
+
puts "Already covered in #{file}"
|
60
|
+
else
|
61
|
+
template = code[/===[^\n]*Liquid.*index\.liquid<\/tt>[^\n]*/m]
|
62
|
+
if !template
|
63
|
+
puts "Liquid not found in #{file}"
|
64
|
+
else
|
65
|
+
puts "Adding section to #{file}"
|
66
|
+
template = template.gsub(/Liquid/, args.name.capitalize).gsub(/liquid/, args.name.downcase)
|
67
|
+
code.gsub! /^(\s*===.*CoffeeScript)/, template << "\n\\1"
|
68
|
+
File.open(file, "w") { |f| f << code }
|
69
|
+
end
|
70
|
+
end
|
64
71
|
end
|
65
72
|
end
|
66
|
-
CLEAN.include 'doc/api'
|
67
73
|
|
68
74
|
# PACKAGING ============================================================
|
69
75
|
|
data/lib/sinatra/base.rb
CHANGED
@@ -7,7 +7,7 @@ require 'sinatra/showexceptions'
|
|
7
7
|
require 'tilt'
|
8
8
|
|
9
9
|
module Sinatra
|
10
|
-
VERSION = '1.1.
|
10
|
+
VERSION = '1.1.2'
|
11
11
|
|
12
12
|
# The request object. See Rack::Request for more info:
|
13
13
|
# http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
@@ -28,6 +28,18 @@ module Sinatra
|
|
28
28
|
else
|
29
29
|
alias secure? ssl?
|
30
30
|
end
|
31
|
+
|
32
|
+
def route
|
33
|
+
@route ||= begin
|
34
|
+
path = Rack::Utils.unescape(path_info)
|
35
|
+
path.empty? ? "/" : path
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def path_info=(value)
|
40
|
+
@route = nil
|
41
|
+
super
|
42
|
+
end
|
31
43
|
end
|
32
44
|
|
33
45
|
# The response object. See Rack::Response and Rack::ResponseHelpers for
|
@@ -128,10 +140,15 @@ module Sinatra
|
|
128
140
|
# Set the Content-Type of the response body given a media type or file
|
129
141
|
# extension.
|
130
142
|
def content_type(type, params={})
|
131
|
-
|
143
|
+
default = params.delete :default
|
144
|
+
mime_type = mime_type(type) || default
|
132
145
|
fail "Unknown media type: %p" % type if mime_type.nil?
|
133
|
-
|
134
|
-
|
146
|
+
mime_type = mime_type.dup
|
147
|
+
unless params.include? :charset or settings.add_charset.all? { |p| not p === mime_type }
|
148
|
+
params[:charset] = params.delete('charset') || settings.default_encoding
|
149
|
+
end
|
150
|
+
mime_type << ";#{params.map { |kv| kv.join('=') }.join(', ')}" unless params.empty?
|
151
|
+
response['Content-Type'] = mime_type
|
135
152
|
end
|
136
153
|
|
137
154
|
# Set the Content-Disposition to "attachment" with the specified filename,
|
@@ -149,10 +166,9 @@ module Sinatra
|
|
149
166
|
stat = File.stat(path)
|
150
167
|
last_modified stat.mtime
|
151
168
|
|
152
|
-
|
153
|
-
File.extname(path)
|
154
|
-
|
155
|
-
'application/octet-stream'
|
169
|
+
if opts[:type] or not response['Content-Type']
|
170
|
+
content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
|
171
|
+
end
|
156
172
|
|
157
173
|
if opts[:disposition] == 'attachment' || opts[:filename]
|
158
174
|
attachment opts[:filename] || path
|
@@ -264,7 +280,11 @@ module Sinatra
|
|
264
280
|
end
|
265
281
|
|
266
282
|
values = values.map { |value| value.to_s.tr('_','-') }
|
267
|
-
hash.each
|
283
|
+
hash.each do |key, value|
|
284
|
+
key = key.to_s.tr('_', '-')
|
285
|
+
value = value.to_i if key == "max-age"
|
286
|
+
values << [key, value].join('=')
|
287
|
+
end
|
268
288
|
|
269
289
|
response['Cache-Control'] = values.join(', ') if values.any?
|
270
290
|
end
|
@@ -435,30 +455,29 @@ module Sinatra
|
|
435
455
|
def render(engine, data, options={}, locals={}, &block)
|
436
456
|
# merge app-level options
|
437
457
|
options = settings.send(engine).merge(options) if settings.respond_to?(engine)
|
438
|
-
options[:outvar]
|
458
|
+
options[:outvar] ||= '@_out_buf'
|
459
|
+
options[:default_encoding] ||= settings.default_encoding
|
439
460
|
|
440
461
|
# extract generic options
|
441
462
|
locals = options.delete(:locals) || locals || {}
|
442
463
|
views = options.delete(:views) || settings.views || "./views"
|
443
464
|
@default_layout = :layout if @default_layout.nil?
|
444
465
|
layout = options.delete(:layout)
|
466
|
+
eat_errors = layout.nil?
|
445
467
|
layout = @default_layout if layout.nil? or layout == true
|
446
468
|
content_type = options.delete(:content_type) || options.delete(:default_content_type)
|
447
469
|
|
448
470
|
# compile and render template
|
449
471
|
layout_was = @default_layout
|
450
|
-
@default_layout = false
|
472
|
+
@default_layout = false
|
451
473
|
template = compile_template(engine, data, options, views)
|
452
474
|
output = template.render(self, locals, &block)
|
453
475
|
@default_layout = layout_was
|
454
476
|
|
455
477
|
# render layout
|
456
478
|
if layout
|
457
|
-
|
458
|
-
|
459
|
-
output = render(engine, layout, options, locals) { output }
|
460
|
-
rescue Errno::ENOENT
|
461
|
-
end
|
479
|
+
options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors)
|
480
|
+
catch(:layout_missing) { output = render(engine, layout, options, locals) { output }}
|
462
481
|
end
|
463
482
|
|
464
483
|
output.extend(ContentTyped).content_type = content_type if content_type
|
@@ -466,6 +485,7 @@ module Sinatra
|
|
466
485
|
end
|
467
486
|
|
468
487
|
def compile_template(engine, data, options, views)
|
488
|
+
eat_errors = options.delete :eat_errors
|
469
489
|
template_cache.fetch engine, data, options do
|
470
490
|
template = Tilt[engine]
|
471
491
|
raise "Template engine not found: #{engine}" if template.nil?
|
@@ -477,12 +497,14 @@ module Sinatra
|
|
477
497
|
body = body.call if body.respond_to?(:call)
|
478
498
|
template.new(path, line.to_i, options) { body }
|
479
499
|
else
|
500
|
+
found = false
|
480
501
|
path = ::File.join(views, "#{data}.#{engine}")
|
481
502
|
Tilt.mappings.each do |ext, klass|
|
482
|
-
break if File.exists?(path)
|
503
|
+
break if found = File.exists?(path)
|
483
504
|
next unless klass == template
|
484
505
|
path = ::File.join(views, "#{data}.#{ext}")
|
485
506
|
end
|
507
|
+
throw :layout_missing if eat_errors and !found
|
486
508
|
template.new(path, 1, options)
|
487
509
|
end
|
488
510
|
when data.is_a?(Proc) || data.is_a?(String)
|
@@ -524,6 +546,7 @@ module Sinatra
|
|
524
546
|
@response = Response.new
|
525
547
|
@params = indifferent_params(@request.params)
|
526
548
|
template_cache.clear if settings.reload_templates
|
549
|
+
force_encoding(@request.route)
|
527
550
|
force_encoding(@params)
|
528
551
|
|
529
552
|
@response['Content-Type'] = nil
|
@@ -627,11 +650,7 @@ module Sinatra
|
|
627
650
|
# Returns pass block.
|
628
651
|
def process_route(pattern, keys, conditions)
|
629
652
|
@original_params ||= @params
|
630
|
-
|
631
|
-
path = unescape(@request.path_info)
|
632
|
-
path.empty? ? "/" : path
|
633
|
-
end
|
634
|
-
if match = pattern.match(@path)
|
653
|
+
if match = pattern.match(@request.route)
|
635
654
|
values = match.captures.to_a
|
636
655
|
params =
|
637
656
|
if keys.any?
|
@@ -893,19 +912,25 @@ module Sinatra
|
|
893
912
|
file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file
|
894
913
|
|
895
914
|
begin
|
896
|
-
|
897
|
-
|
915
|
+
io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
|
916
|
+
app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
|
898
917
|
rescue Errno::ENOENT
|
899
918
|
app, data = nil
|
900
919
|
end
|
901
920
|
|
902
921
|
if data
|
922
|
+
if app and app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
|
923
|
+
encoding = $2
|
924
|
+
else
|
925
|
+
encoding = settings.default_encoding
|
926
|
+
end
|
903
927
|
lines = app.count("\n") + 1
|
904
928
|
template = nil
|
929
|
+
force_encoding data, encoding
|
905
930
|
data.each_line do |line|
|
906
931
|
lines += 1
|
907
932
|
if line =~ /^@@\s*(.*\S)\s*$/
|
908
|
-
template = ''
|
933
|
+
template = force_encoding('', encoding)
|
909
934
|
templates[$1.to_sym] = [template, file, lines]
|
910
935
|
elsif template
|
911
936
|
template << line
|
@@ -1181,7 +1206,8 @@ module Sinatra
|
|
1181
1206
|
/\(.*\)/, # generated code
|
1182
1207
|
/rubygems\/custom_require\.rb$/, # rubygems require hacks
|
1183
1208
|
/active_support/, # active_support require hacks
|
1184
|
-
|
1209
|
+
/bundler(\/runtime)?\.rb/, # bundler require hacks
|
1210
|
+
/<internal:/ # internal in ruby >= 1.9.2
|
1185
1211
|
]
|
1186
1212
|
|
1187
1213
|
# add rubinius (and hopefully other VM impls) ignore patterns ...
|
@@ -1209,20 +1235,22 @@ module Sinatra
|
|
1209
1235
|
#
|
1210
1236
|
# The latter might not be necessary if Rack handles it one day.
|
1211
1237
|
# Keep an eye on Rack's LH #100.
|
1238
|
+
def force_encoding(*args) settings.force_encoding(*args) end
|
1212
1239
|
if defined? Encoding
|
1213
|
-
def force_encoding(data)
|
1214
|
-
return if data ==
|
1240
|
+
def self.force_encoding(data, encoding = default_encoding)
|
1241
|
+
return if data == settings || data.is_a?(Tempfile)
|
1215
1242
|
if data.respond_to? :force_encoding
|
1216
|
-
data.force_encoding
|
1243
|
+
data.force_encoding encoding
|
1217
1244
|
elsif data.respond_to? :each_value
|
1218
|
-
data.each_value { |v| force_encoding(v) }
|
1245
|
+
data.each_value { |v| force_encoding(v, encoding) }
|
1219
1246
|
elsif data.respond_to? :each
|
1220
|
-
data.each { |v| force_encoding(v) }
|
1247
|
+
data.each { |v| force_encoding(v, encoding) }
|
1221
1248
|
end
|
1249
|
+
data
|
1222
1250
|
end
|
1223
1251
|
else
|
1224
|
-
def force_encoding(*) end
|
1225
|
-
|
1252
|
+
def self.force_encoding(data, *) data end
|
1253
|
+
end
|
1226
1254
|
|
1227
1255
|
reset!
|
1228
1256
|
|
@@ -1234,6 +1262,7 @@ module Sinatra
|
|
1234
1262
|
set :logging, false
|
1235
1263
|
set :method_override, false
|
1236
1264
|
set :default_encoding, "utf-8"
|
1265
|
+
set :add_charset, [/^text\//, 'application/javascript', 'application/xml', 'application/xhtml+xml']
|
1237
1266
|
|
1238
1267
|
class << self
|
1239
1268
|
alias_method :methodoverride?, :method_override?
|
data/sinatra.gemspec
CHANGED
@@ -3,8 +3,8 @@ 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.1.
|
7
|
-
s.date = '2010-
|
6
|
+
s.version = '1.1.2'
|
7
|
+
s.date = '2010-12-25'
|
8
8
|
|
9
9
|
s.description = "Classy web-development dressed in a DSL"
|
10
10
|
s.summary = "Classy web-development dressed in a DSL"
|
@@ -22,7 +22,9 @@ Gem::Specification.new do |s|
|
|
22
22
|
README.fr.rdoc
|
23
23
|
README.hu.rdoc
|
24
24
|
README.jp.rdoc
|
25
|
+
README.pt-br.rdoc
|
25
26
|
README.rdoc
|
27
|
+
README.ru.rdoc
|
26
28
|
README.zh.rdoc
|
27
29
|
Rakefile
|
28
30
|
lib/sinatra.rb
|
@@ -112,7 +114,7 @@ Gem::Specification.new do |s|
|
|
112
114
|
|
113
115
|
s.extra_rdoc_files = %w[README.rdoc README.de.rdoc README.jp.rdoc README.fr.rdoc README.es.rdoc README.hu.rdoc README.zh.rdoc LICENSE]
|
114
116
|
s.add_dependency 'rack', '~> 1.1'
|
115
|
-
s.add_dependency 'tilt', '~> 1.
|
117
|
+
s.add_dependency 'tilt', '~> 1.2'
|
116
118
|
s.add_development_dependency 'rake'
|
117
119
|
s.add_development_dependency 'shotgun', '~> 0.6'
|
118
120
|
s.add_development_dependency 'rack-test', '>= 0.5.6'
|
@@ -125,7 +127,7 @@ Gem::Specification.new do |s|
|
|
125
127
|
s.add_development_dependency 'RedCloth'
|
126
128
|
s.add_development_dependency 'radius'
|
127
129
|
s.add_development_dependency 'markaby'
|
128
|
-
s.add_development_dependency 'coffee-script'
|
130
|
+
s.add_development_dependency 'coffee-script', '>= 2.0'
|
129
131
|
s.add_development_dependency 'rdoc'
|
130
132
|
s.add_development_dependency 'nokogiri'
|
131
133
|
|
data/test/coffee_test.rb
CHANGED
@@ -16,7 +16,7 @@ class CoffeeTest < Test::Unit::TestCase
|
|
16
16
|
it 'renders inline Coffee strings' do
|
17
17
|
coffee_app { coffee "alert 'Aye!'\n" }
|
18
18
|
assert ok?
|
19
|
-
assert_equal "(function() {\n alert('Aye!');\n})();\n", body
|
19
|
+
assert_equal "(function() {\n alert('Aye!');\n}).call(this);\n", body
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'defaults content type to javascript' do
|
@@ -45,13 +45,13 @@ class CoffeeTest < Test::Unit::TestCase
|
|
45
45
|
it 'renders .coffee files in views path' do
|
46
46
|
coffee_app { coffee :hello }
|
47
47
|
assert ok?
|
48
|
-
assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
|
48
|
+
assert_equal "(function() {\n alert(\"Aye!\");\n}).call(this);\n", body
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'ignores the layout option' do
|
52
52
|
coffee_app { coffee :hello, :layout => :layout2 }
|
53
53
|
assert ok?
|
54
|
-
assert_equal "(function() {\n alert(\"Aye!\");\n})();\n", body
|
54
|
+
assert_equal "(function() {\n alert(\"Aye!\");\n}).call(this);\n", body
|
55
55
|
end
|
56
56
|
|
57
57
|
it "raises error if template not found" do
|
data/test/filter_test.rb
CHANGED
@@ -255,6 +255,16 @@ class AfterFilterTest < Test::Unit::TestCase
|
|
255
255
|
assert ran_filter
|
256
256
|
end
|
257
257
|
|
258
|
+
it 'changes to path_info from a pattern matching before filter are respoected when routing' do
|
259
|
+
mock_app do
|
260
|
+
before('/foo') { request.path_info = '/bar' }
|
261
|
+
get('/bar') { 'blah' }
|
262
|
+
end
|
263
|
+
get '/foo'
|
264
|
+
assert ok?
|
265
|
+
assert_equal 'blah', body
|
266
|
+
end
|
267
|
+
|
258
268
|
it 'generates block arguments from route pattern' do
|
259
269
|
subpath = nil
|
260
270
|
mock_app do
|
data/test/haml_test.rb
CHANGED
@@ -89,6 +89,11 @@ class HAMLTest < Test::Unit::TestCase
|
|
89
89
|
assert ok?
|
90
90
|
assert_match(/^<!DOCTYPE html PUBLIC (.*) HTML 4.01/, body)
|
91
91
|
end
|
92
|
+
|
93
|
+
it "is possible to pass locals" do
|
94
|
+
haml_app { haml "= foo", :locals => { :foo => 'bar' }}
|
95
|
+
assert_equal "bar\n", body
|
96
|
+
end
|
92
97
|
end
|
93
98
|
rescue
|
94
99
|
warn "#{$!.to_s}: skipping haml tests"
|
data/test/helper.rb
CHANGED
@@ -53,6 +53,10 @@ class Test::Unit::TestCase
|
|
53
53
|
response.body.to_s
|
54
54
|
end
|
55
55
|
|
56
|
+
def assert_body(value)
|
57
|
+
assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "")
|
58
|
+
end
|
59
|
+
|
56
60
|
# Delegate other missing methods to response.
|
57
61
|
def method_missing(name, *args, &block)
|
58
62
|
if response && response.respond_to?(name)
|
data/test/helpers_test.rb
CHANGED
@@ -320,7 +320,7 @@ class HelpersTest < Test::Unit::TestCase
|
|
320
320
|
|
321
321
|
get '/foo.xml'
|
322
322
|
assert ok?
|
323
|
-
assert_equal 'application/foo
|
323
|
+
assert_equal 'application/foo', response['Content-Type']
|
324
324
|
assert_equal 'I AM FOO', body
|
325
325
|
end
|
326
326
|
|
@@ -334,6 +334,32 @@ class HelpersTest < Test::Unit::TestCase
|
|
334
334
|
|
335
335
|
assert_raise(RuntimeError) { get '/foo.xml' }
|
336
336
|
end
|
337
|
+
|
338
|
+
it 'only sets default charset for specific mime types' do
|
339
|
+
tests_ran = false
|
340
|
+
mock_app do
|
341
|
+
mime_type :foo, 'text/foo'
|
342
|
+
mime_type :bar, 'application/bar'
|
343
|
+
mime_type :baz, 'application/baz'
|
344
|
+
add_charset << mime_type(:baz)
|
345
|
+
get '/' do
|
346
|
+
assert_equal content_type(:txt), 'text/plain;charset=utf-8'
|
347
|
+
assert_equal content_type(:css), 'text/css;charset=utf-8'
|
348
|
+
assert_equal content_type(:html), 'text/html;charset=utf-8'
|
349
|
+
assert_equal content_type(:foo), 'text/foo;charset=utf-8'
|
350
|
+
assert_equal content_type(:xml), 'application/xml;charset=utf-8'
|
351
|
+
assert_equal content_type(:xhtml), 'application/xhtml+xml;charset=utf-8'
|
352
|
+
assert_equal content_type(:js), 'application/javascript;charset=utf-8'
|
353
|
+
assert_equal content_type(:bar), 'application/bar'
|
354
|
+
assert_equal content_type(:png), 'image/png'
|
355
|
+
assert_equal content_type(:baz), 'application/baz;charset=utf-8'
|
356
|
+
tests_ran = true
|
357
|
+
"done"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
get '/'
|
361
|
+
assert tests_ran
|
362
|
+
end
|
337
363
|
end
|
338
364
|
|
339
365
|
describe 'send_file' do
|
@@ -378,7 +404,7 @@ class HelpersTest < Test::Unit::TestCase
|
|
378
404
|
it 'sets the Content-Type response header if type option is set to a mime type' do
|
379
405
|
send_file_app :type => 'application/octet-stream'
|
380
406
|
get '/file.txt'
|
381
|
-
assert_equal 'application/octet-stream
|
407
|
+
assert_equal 'application/octet-stream', response['Content-Type']
|
382
408
|
end
|
383
409
|
|
384
410
|
it 'sets the Content-Length response header' do
|
@@ -420,13 +446,45 @@ class HelpersTest < Test::Unit::TestCase
|
|
420
446
|
get '/file.txt'
|
421
447
|
assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
|
422
448
|
end
|
449
|
+
|
450
|
+
it "is able to send files with unkown mime type" do
|
451
|
+
@file = File.dirname(__FILE__) + '/file.foobar'
|
452
|
+
File.open(@file, 'wb') { |io| io.write('Hello World') }
|
453
|
+
send_file_app
|
454
|
+
get '/file.txt'
|
455
|
+
assert_equal 'application/octet-stream', response['Content-Type']
|
456
|
+
end
|
457
|
+
|
458
|
+
it "does not override Content-Type if already set and no explicit type is given" do
|
459
|
+
path = @file
|
460
|
+
mock_app do
|
461
|
+
get '/' do
|
462
|
+
content_type :png
|
463
|
+
send_file path
|
464
|
+
end
|
465
|
+
end
|
466
|
+
get '/'
|
467
|
+
assert_equal 'image/png', response['Content-Type']
|
468
|
+
end
|
469
|
+
|
470
|
+
it "does override Content-Type even if already set, if explicit type is given" do
|
471
|
+
path = @file
|
472
|
+
mock_app do
|
473
|
+
get '/' do
|
474
|
+
content_type :png
|
475
|
+
send_file path, :type => :gif
|
476
|
+
end
|
477
|
+
end
|
478
|
+
get '/'
|
479
|
+
assert_equal 'image/gif', response['Content-Type']
|
480
|
+
end
|
423
481
|
end
|
424
482
|
|
425
483
|
describe 'cache_control' do
|
426
484
|
setup do
|
427
485
|
mock_app {
|
428
486
|
get '/' do
|
429
|
-
cache_control :public, :no_cache, :max_age => 60
|
487
|
+
cache_control :public, :no_cache, :max_age => 60.0
|
430
488
|
'Hello World'
|
431
489
|
end
|
432
490
|
}
|