aldebaran 1.0.1
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/.gitignore +13 -0
- data/.travis.yml +16 -0
- data/.yardopts +4 -0
- data/AUTHORS +4 -0
- data/Gemfile +77 -0
- data/KNOWN_ISSUES +5 -0
- data/LICENSE +22 -0
- data/README.rdoc +1900 -0
- data/Rakefile +175 -0
- data/aldebaran.gemspec +19 -0
- data/lib/aldebaran.rb +7 -0
- data/lib/aldebaran/base.rb +1600 -0
- data/lib/aldebaran/images/404.png +0 -0
- data/lib/aldebaran/images/500.png +0 -0
- data/lib/aldebaran/main.rb +28 -0
- data/lib/aldebaran/showexceptions.rb +340 -0
- data/lib/aldebaran/version.rb +3 -0
- data/test/aldebaran_test.rb +17 -0
- data/test/base_test.rb +160 -0
- data/test/builder_test.rb +95 -0
- data/test/coffee_test.rb +92 -0
- data/test/contest.rb +98 -0
- data/test/creole_test.rb +65 -0
- data/test/delegator_test.rb +162 -0
- data/test/encoding_test.rb +20 -0
- data/test/erb_test.rb +104 -0
- data/test/extensions_test.rb +100 -0
- data/test/filter_test.rb +397 -0
- data/test/haml_test.rb +101 -0
- data/test/helper.rb +115 -0
- data/test/helpers_test.rb +1192 -0
- data/test/less_test.rb +67 -0
- data/test/liquid_test.rb +59 -0
- data/test/mapped_error_test.rb +259 -0
- data/test/markaby_test.rb +80 -0
- data/test/markdown_test.rb +81 -0
- data/test/middleware_test.rb +68 -0
- data/test/nokogiri_test.rb +69 -0
- data/test/public/favicon.ico +0 -0
- data/test/radius_test.rb +59 -0
- data/test/rdoc_test.rb +65 -0
- data/test/readme_test.rb +136 -0
- data/test/request_test.rb +45 -0
- data/test/response_test.rb +61 -0
- data/test/result_test.rb +98 -0
- data/test/route_added_hook_test.rb +59 -0
- data/test/routing_test.rb +1096 -0
- data/test/sass_test.rb +115 -0
- data/test/scss_test.rb +88 -0
- data/test/server_test.rb +48 -0
- data/test/settings_test.rb +493 -0
- data/test/slim_test.rb +98 -0
- data/test/static_test.rb +178 -0
- data/test/streaming_test.rb +100 -0
- data/test/templates_test.rb +298 -0
- data/test/textile_test.rb +65 -0
- data/test/views/a/in_a.str +1 -0
- data/test/views/ascii.erb +2 -0
- data/test/views/b/in_b.str +1 -0
- data/test/views/calc.html.erb +1 -0
- 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
- data/test/views/explicitly_nested.str +1 -0
- data/test/views/foo/hello.test +1 -0
- data/test/views/hello.builder +1 -0
- data/test/views/hello.coffee +1 -0
- data/test/views/hello.creole +1 -0
- data/test/views/hello.erb +1 -0
- data/test/views/hello.haml +1 -0
- data/test/views/hello.less +5 -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 +2 -0
- data/test/views/hello.scss +3 -0
- data/test/views/hello.slim +1 -0
- data/test/views/hello.str +1 -0
- data/test/views/hello.test +1 -0
- data/test/views/hello.textile +1 -0
- data/test/views/layout2.builder +3 -0
- data/test/views/layout2.erb +2 -0
- data/test/views/layout2.haml +2 -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.slim +3 -0
- data/test/views/layout2.str +2 -0
- data/test/views/layout2.test +1 -0
- data/test/views/nested.str +1 -0
- data/test/views/utf8.erb +2 -0
- metadata +231 -0
data/test/slim_test.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'slim'
|
5
|
+
|
6
|
+
class SlimTest < Test::Unit::TestCase
|
7
|
+
def slim_app(&block)
|
8
|
+
mock_app {
|
9
|
+
set :views, File.dirname(__FILE__) + '/views'
|
10
|
+
get '/', &block
|
11
|
+
}
|
12
|
+
get '/'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'renders inline slim strings' do
|
16
|
+
slim_app { slim "h1 Hiya\n" }
|
17
|
+
assert ok?
|
18
|
+
assert_equal "<h1>Hiya</h1>", body
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'renders .slim files in views path' do
|
22
|
+
slim_app { slim :hello }
|
23
|
+
assert ok?
|
24
|
+
assert_equal "<h1>Hello From Slim</h1>", body
|
25
|
+
end
|
26
|
+
|
27
|
+
it "renders with inline layouts" do
|
28
|
+
mock_app {
|
29
|
+
layout { %(h1\n | THIS. IS. \n == yield.upcase ) }
|
30
|
+
get('/') { slim 'em Sparta' }
|
31
|
+
}
|
32
|
+
get '/'
|
33
|
+
assert ok?
|
34
|
+
assert_equal "<h1>THIS. IS. <EM>SPARTA</EM></h1>", body
|
35
|
+
end
|
36
|
+
|
37
|
+
it "renders with file layouts" do
|
38
|
+
slim_app {
|
39
|
+
slim '| Hello World', :layout => :layout2
|
40
|
+
}
|
41
|
+
assert ok?
|
42
|
+
assert_equal "<h1>Slim Layout!</h1><p>Hello World</p>", body
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises error if template not found" do
|
46
|
+
mock_app {
|
47
|
+
get('/') { slim :no_such_template }
|
48
|
+
}
|
49
|
+
assert_raise(Errno::ENOENT) { get('/') }
|
50
|
+
end
|
51
|
+
|
52
|
+
HTML4_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"
|
53
|
+
|
54
|
+
it "passes slim options to the slim engine" do
|
55
|
+
mock_app {
|
56
|
+
get '/' do
|
57
|
+
slim "doctype html\nh1 Hello World", :format => :html4
|
58
|
+
end
|
59
|
+
}
|
60
|
+
get '/'
|
61
|
+
assert ok?
|
62
|
+
assert_equal "#{HTML4_DOCTYPE}<h1>Hello World</h1>", body
|
63
|
+
end
|
64
|
+
|
65
|
+
it "passes default slim options to the slim engine" do
|
66
|
+
mock_app {
|
67
|
+
set :slim, {:format => :html4}
|
68
|
+
get '/' do
|
69
|
+
slim "doctype html\nh1 Hello World"
|
70
|
+
end
|
71
|
+
}
|
72
|
+
get '/'
|
73
|
+
assert ok?
|
74
|
+
assert_equal "#{HTML4_DOCTYPE}<h1>Hello World</h1>", body
|
75
|
+
end
|
76
|
+
|
77
|
+
it "merges the default slim options with the overrides and passes them to the slim engine" do
|
78
|
+
mock_app {
|
79
|
+
set :slim, {:format => :html4}
|
80
|
+
get '/' do
|
81
|
+
slim "doctype html\nh1.header Hello World"
|
82
|
+
end
|
83
|
+
get '/html5' do
|
84
|
+
slim "doctype html\nh1.header Hello World", :format => :html5
|
85
|
+
end
|
86
|
+
}
|
87
|
+
get '/'
|
88
|
+
assert ok?
|
89
|
+
assert_match(/^#{HTML4_DOCTYPE}/, body)
|
90
|
+
get '/html5'
|
91
|
+
assert ok?
|
92
|
+
assert_equal "<!DOCTYPE html><h1 class=\"header\">Hello World</h1>", body
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
rescue LoadError
|
97
|
+
warn "#{$!.to_s}: skipping slim tests"
|
98
|
+
end
|
data/test/static_test.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class StaticTest < Test::Unit::TestCase
|
4
|
+
setup do
|
5
|
+
mock_app {
|
6
|
+
set :static, true
|
7
|
+
set :public_folder, File.dirname(__FILE__)
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'serves GET requests for files in the public directory' do
|
12
|
+
get "/#{File.basename(__FILE__)}"
|
13
|
+
assert ok?
|
14
|
+
assert_equal File.read(__FILE__), body
|
15
|
+
assert_equal File.size(__FILE__).to_s, response['Content-Length']
|
16
|
+
assert response.headers.include?('Last-Modified')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'produces a body that can be iterated over multiple times' do
|
20
|
+
env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
|
21
|
+
status, headers, body = @app.call(env)
|
22
|
+
buf1, buf2 = [], []
|
23
|
+
body.each { |part| buf1 << part }
|
24
|
+
body.each { |part| buf2 << part }
|
25
|
+
assert_equal buf1.join, buf2.join
|
26
|
+
assert_equal File.read(__FILE__), buf1.join
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'sets the aldebaran.static_file env variable if served' do
|
30
|
+
env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
|
31
|
+
status, headers, body = @app.call(env)
|
32
|
+
assert_equal File.expand_path(__FILE__), env['aldebaran.static_file']
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'serves HEAD requests for files in the public directory' do
|
36
|
+
head "/#{File.basename(__FILE__)}"
|
37
|
+
assert ok?
|
38
|
+
assert_equal '', body
|
39
|
+
assert_equal File.size(__FILE__).to_s, response['Content-Length']
|
40
|
+
assert response.headers.include?('Last-Modified')
|
41
|
+
end
|
42
|
+
|
43
|
+
%w[POST PUT DELETE].each do |verb|
|
44
|
+
it "does not serve #{verb} requests" do
|
45
|
+
send verb.downcase, "/#{File.basename(__FILE__)}"
|
46
|
+
assert_equal 404, status
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'serves files in preference to custom routes' do
|
51
|
+
@app.get("/#{File.basename(__FILE__)}") { 'Hello World' }
|
52
|
+
get "/#{File.basename(__FILE__)}"
|
53
|
+
assert ok?
|
54
|
+
assert body != 'Hello World'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'does not serve directories' do
|
58
|
+
get "/"
|
59
|
+
assert not_found?
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'passes to the next handler when the static option is disabled' do
|
63
|
+
@app.set :static, false
|
64
|
+
get "/#{File.basename(__FILE__)}"
|
65
|
+
assert not_found?
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'passes to the next handler when the public option is nil' do
|
69
|
+
@app.set :public_folder, nil
|
70
|
+
get "/#{File.basename(__FILE__)}"
|
71
|
+
assert not_found?
|
72
|
+
end
|
73
|
+
|
74
|
+
it '404s when a file is not found' do
|
75
|
+
get "/foobarbaz.txt"
|
76
|
+
assert not_found?
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'serves files when .. path traverses within public directory' do
|
80
|
+
get "/data/../#{File.basename(__FILE__)}"
|
81
|
+
assert ok?
|
82
|
+
assert_equal File.read(__FILE__), body
|
83
|
+
end
|
84
|
+
|
85
|
+
it '404s when .. path traverses outside of public directory' do
|
86
|
+
mock_app {
|
87
|
+
set :static, true
|
88
|
+
set :public_folder, File.dirname(__FILE__) + '/data'
|
89
|
+
}
|
90
|
+
get "/../#{File.basename(__FILE__)}"
|
91
|
+
assert not_found?
|
92
|
+
end
|
93
|
+
|
94
|
+
def assert_valid_range(http_range, range, path, file)
|
95
|
+
request = Rack::MockRequest.new(@app)
|
96
|
+
response = request.get("/#{File.basename(path)}", 'HTTP_RANGE' => http_range)
|
97
|
+
|
98
|
+
should_be = file[range]
|
99
|
+
expected_range = "bytes #{range.begin}-#{range.end}/#{file.length}"
|
100
|
+
|
101
|
+
assert_equal 206,response.status, "Should be HTTP/1.1 206 Partial content"
|
102
|
+
assert_equal should_be.length, response.body.length, "Unexpected response length for #{http_range}"
|
103
|
+
assert_equal should_be, response.body, "Unexpected response data for #{http_range}"
|
104
|
+
assert_equal should_be.length.to_s, response['Content-Length'], "Incorrect Content-Length for #{http_range}"
|
105
|
+
assert_equal expected_range, response['Content-Range'], "Incorrect Content-Range for #{http_range}"
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'handles valid byte ranges correctly' do
|
109
|
+
# Use the biggest file in this dir so we can test ranges > 8k bytes. (StaticFile sends in 8k chunks.)
|
110
|
+
path = File.dirname(__FILE__) + '/helpers_test.rb' # currently 16k bytes
|
111
|
+
file = File.read(path)
|
112
|
+
length = file.length
|
113
|
+
assert length > 9000, "The test file #{path} is too short (#{length} bytes) to run these tests"
|
114
|
+
|
115
|
+
[0..0, 42..88, 1234..1234, 100..9000, 0..(length-1), (length-1)..(length-1)].each do |range|
|
116
|
+
assert_valid_range("bytes=#{range.begin}-#{range.end}", range, path, file)
|
117
|
+
end
|
118
|
+
|
119
|
+
[0, 100, length-100, length-1].each do |start|
|
120
|
+
assert_valid_range("bytes=#{start}-", (start..length-1), path, file)
|
121
|
+
end
|
122
|
+
|
123
|
+
[1, 100, length-100, length-1, length].each do |range_length|
|
124
|
+
assert_valid_range("bytes=-#{range_length}", (length-range_length..length-1), path, file)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Some valid ranges that exceed the length of the file:
|
128
|
+
assert_valid_range("bytes=100-999999", (100..length-1), path, file)
|
129
|
+
assert_valid_range("bytes=100-#{length}", (100..length-1), path, file)
|
130
|
+
assert_valid_range("bytes=-#{length}", (0..length-1), path, file)
|
131
|
+
assert_valid_range("bytes=-#{length+1}", (0..length-1), path, file)
|
132
|
+
assert_valid_range("bytes=-999999", (0..length-1), path, file)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'correctly ignores syntactically invalid range requests' do
|
136
|
+
# ...and also ignores multi-range requests, which aren't supported yet
|
137
|
+
["bytes=45-40", "bytes=IV-LXVI", "octets=10-20", "bytes=-", "bytes=1-2,3-4"].each do |http_range|
|
138
|
+
request = Rack::MockRequest.new(@app)
|
139
|
+
response = request.get("/#{File.basename(__FILE__)}", 'HTTP_RANGE' => http_range)
|
140
|
+
|
141
|
+
assert_equal 200,response.status, "Invalid range '#{http_range}' should be ignored"
|
142
|
+
assert_equal nil,response['Content-Range'], "Invalid range '#{http_range}' should be ignored"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'returns error 416 for unsatisfiable range requests' do
|
147
|
+
# An unsatisfiable request is one that specifies a start that's at or past the end of the file.
|
148
|
+
length = File.read(__FILE__).length
|
149
|
+
["bytes=888888-", "bytes=888888-999999", "bytes=#{length}-#{length}"].each do |http_range|
|
150
|
+
request = Rack::MockRequest.new(@app)
|
151
|
+
response = request.get("/#{File.basename(__FILE__)}", 'HTTP_RANGE' => http_range)
|
152
|
+
|
153
|
+
assert_equal 416,response.status, "Unsatisfiable range '#{http_range}' should return 416"
|
154
|
+
assert_equal "bytes */#{length}",response['Content-Range'], "416 response should include actual length"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'does not include static cache control headers by default' do
|
159
|
+
env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
|
160
|
+
status, headers, body = @app.call(env)
|
161
|
+
assert !headers.has_key?('Cache-Control')
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'sets cache control headers on static files if set' do
|
165
|
+
@app.set :static_cache_control, :public
|
166
|
+
env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
|
167
|
+
status, headers, body = @app.call(env)
|
168
|
+
assert headers.has_key?('Cache-Control')
|
169
|
+
assert_equal headers['Cache-Control'], 'public'
|
170
|
+
|
171
|
+
@app.set :static_cache_control, [:public, :must_revalidate, {:max_age => 300}]
|
172
|
+
env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
|
173
|
+
status, headers, body = @app.call(env)
|
174
|
+
assert headers.has_key?('Cache-Control')
|
175
|
+
assert_equal headers['Cache-Control'], 'public, must-revalidate, max-age=300'
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class StreamingTest < Test::Unit::TestCase
|
4
|
+
Stream = aldebaran::Helpers::Stream
|
5
|
+
|
6
|
+
it 'returns the concatinated body' do
|
7
|
+
mock_app do
|
8
|
+
get '/' do
|
9
|
+
stream do |out|
|
10
|
+
out << "Hello" << " "
|
11
|
+
out << "World!"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
get('/')
|
17
|
+
assert_body "Hello World!"
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'always yields strings' do
|
21
|
+
stream = Stream.new { |out| out << :foo }
|
22
|
+
stream.each { |str| assert_equal 'foo', str }
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'postpones body generation' do
|
26
|
+
step = 0
|
27
|
+
|
28
|
+
stream = Stream.new do |out|
|
29
|
+
10.times do
|
30
|
+
out << step
|
31
|
+
step += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
stream.each do |s|
|
36
|
+
assert_equal s, step.to_s
|
37
|
+
step += 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'calls the callback after it is done' do
|
42
|
+
step = 0
|
43
|
+
final = 0
|
44
|
+
stream = Stream.new { |o| 10.times { step += 1 }}
|
45
|
+
stream.callback { final = step }
|
46
|
+
stream.each { |str| }
|
47
|
+
assert_equal 10, final
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not trigger the callback if close is set to false' do
|
51
|
+
step = 0
|
52
|
+
final = 0
|
53
|
+
stream = Stream.new(Stream, false) { |o| 10.times { step += 1 } }
|
54
|
+
stream.callback { final = step }
|
55
|
+
stream.each { |str| }
|
56
|
+
assert_equal 0, final
|
57
|
+
end
|
58
|
+
|
59
|
+
class MockScheduler
|
60
|
+
def initialize(*) @schedule, @defer = [], [] end
|
61
|
+
def schedule(&block) @schedule << block end
|
62
|
+
def defer(&block) @defer << block end
|
63
|
+
def schedule!(*) @schedule.pop.call until @schedule.empty? end
|
64
|
+
def defer!(*) @defer.pop.call until @defer.empty? end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'allows dropping in another scheduler' do
|
68
|
+
scheduler = MockScheduler.new
|
69
|
+
processing = sending = done = false
|
70
|
+
|
71
|
+
stream = Stream.new(scheduler) do |out|
|
72
|
+
processing = true
|
73
|
+
out << :foo
|
74
|
+
end
|
75
|
+
|
76
|
+
stream.each { sending = true}
|
77
|
+
stream.callback { done = true }
|
78
|
+
|
79
|
+
scheduler.schedule!
|
80
|
+
assert !processing
|
81
|
+
assert !sending
|
82
|
+
assert !done
|
83
|
+
|
84
|
+
scheduler.defer!
|
85
|
+
assert processing
|
86
|
+
assert !sending
|
87
|
+
assert !done
|
88
|
+
|
89
|
+
scheduler.schedule!
|
90
|
+
assert sending
|
91
|
+
assert done
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'schedules exceptions to be raised on the main thread/event loop/...' do
|
95
|
+
scheduler = MockScheduler.new
|
96
|
+
Stream.new(scheduler) { fail 'should be caught' }.each { }
|
97
|
+
scheduler.defer!
|
98
|
+
assert_raise(RuntimeError) { scheduler.schedule! }
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path('../helper', __FILE__)
|
3
|
+
File.delete(File.dirname(__FILE__) + '/views/layout.test') rescue nil
|
4
|
+
|
5
|
+
class TestTemplate < Tilt::Template
|
6
|
+
def prepare
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(scope, locals={}, &block)
|
10
|
+
inner = block ? block.call : ''
|
11
|
+
data + inner
|
12
|
+
end
|
13
|
+
|
14
|
+
Tilt.register 'test', self
|
15
|
+
end
|
16
|
+
|
17
|
+
class TemplatesTest < Test::Unit::TestCase
|
18
|
+
def render_app(base=aldebaran::Base, options = {}, &block)
|
19
|
+
base, options = aldebaran::Base, base if base.is_a? Hash
|
20
|
+
mock_app(base) {
|
21
|
+
set :views, File.dirname(__FILE__) + '/views'
|
22
|
+
set options
|
23
|
+
get '/', &block
|
24
|
+
template(:layout3) { "Layout 3!\n" }
|
25
|
+
}
|
26
|
+
get '/'
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_default_layout
|
30
|
+
layout = File.dirname(__FILE__) + '/views/layout.test'
|
31
|
+
File.open(layout, 'wb') { |io| io.write "Layout!\n" }
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
File.unlink(layout) rescue nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'renders String templates directly' do
|
38
|
+
render_app { render :test, 'Hello World' }
|
39
|
+
assert ok?
|
40
|
+
assert_equal 'Hello World', body
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'renders Proc templates using the call result' do
|
44
|
+
render_app { render :test, Proc.new {'Hello World'} }
|
45
|
+
assert ok?
|
46
|
+
assert_equal 'Hello World', body
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'looks up Symbol templates in views directory' do
|
50
|
+
render_app { render :test, :hello }
|
51
|
+
assert ok?
|
52
|
+
assert_equal "Hello World!\n", body
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'uses the default layout template if not explicitly overridden' do
|
56
|
+
with_default_layout do
|
57
|
+
render_app { render :test, :hello }
|
58
|
+
assert ok?
|
59
|
+
assert_equal "Layout!\nHello World!\n", body
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'uses the default layout template if not really overriden' do
|
64
|
+
with_default_layout do
|
65
|
+
render_app { render :test, :hello, :layout => true }
|
66
|
+
assert ok?
|
67
|
+
assert_equal "Layout!\nHello World!\n", body
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'uses the layout template specified' do
|
72
|
+
render_app { render :test, :hello, :layout => :layout2 }
|
73
|
+
assert ok?
|
74
|
+
assert_equal "Layout 2!\nHello World!\n", body
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'uses layout templates defined with the #template method' do
|
78
|
+
render_app { render :test, :hello, :layout => :layout3 }
|
79
|
+
assert ok?
|
80
|
+
assert_equal "Layout 3!\nHello World!\n", body
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'avoids wrapping layouts around nested templates' do
|
84
|
+
render_app { render :str, :nested, :layout => :layout2 }
|
85
|
+
assert ok?
|
86
|
+
assert_equal "<h1>String Layout!</h1>\n<content><h1>Hello From String</h1></content>", body
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'allows explicitly wrapping layouts around nested templates' do
|
90
|
+
render_app { render :str, :explicitly_nested, :layout => :layout2 }
|
91
|
+
assert ok?
|
92
|
+
assert_equal "<h1>String Layout!</h1>\n<content><h1>String Layout!</h1>\n<h1>Hello From String</h1></content>", body
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'two independent render calls do not disable layouts' do
|
96
|
+
render_app do
|
97
|
+
render :str, :explicitly_nested, :layout => :layout2
|
98
|
+
render :str, :nested, :layout => :layout2
|
99
|
+
end
|
100
|
+
assert ok?
|
101
|
+
assert_equal "<h1>String Layout!</h1>\n<content><h1>Hello From String</h1></content>", body
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'is possible to use partials in layouts' do
|
105
|
+
render_app do
|
106
|
+
settings.layout { "<%= erb 'foo' %><%= yield %>" }
|
107
|
+
erb 'bar'
|
108
|
+
end
|
109
|
+
assert ok?
|
110
|
+
assert_equal "foobar", body
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'loads templates from source file' do
|
114
|
+
mock_app { enable :inline_templates }
|
115
|
+
assert_equal "this is foo\n\n", @app.templates[:foo][0]
|
116
|
+
assert_equal "X\n= yield\nX\n", @app.templates[:layout][0]
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'ignores spaces after names of inline templates' do
|
120
|
+
mock_app { enable :inline_templates }
|
121
|
+
assert_equal "There's a space after 'bar'!\n\n", @app.templates[:bar][0]
|
122
|
+
assert_equal "this is not foo\n\n", @app.templates[:"foo bar"][0]
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'loads templates from given source file' do
|
126
|
+
mock_app { set :inline_templates, __FILE__ }
|
127
|
+
assert_equal "this is foo\n\n", @app.templates[:foo][0]
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'inline_templates ignores IO errors' do
|
131
|
+
assert_nothing_raised {
|
132
|
+
mock_app {
|
133
|
+
set :inline_templates, '/foo/bar'
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
assert @app.templates.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'allows unicode in inline templates' do
|
141
|
+
mock_app { set :inline_templates, __FILE__ }
|
142
|
+
assert_equal "Den som tror at hemma det är där man bor har aldrig vart hos mig.\n\n",
|
143
|
+
@app.templates[:umlaut][0]
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'loads templates from specified views directory' do
|
147
|
+
render_app { render :test, :hello, :views => settings.views + '/foo' }
|
148
|
+
|
149
|
+
assert_equal "from another views directory\n", body
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'passes locals to the layout' do
|
153
|
+
mock_app {
|
154
|
+
template :my_layout do
|
155
|
+
'Hello <%= name %>!<%= yield %>'
|
156
|
+
end
|
157
|
+
|
158
|
+
get '/' do
|
159
|
+
erb '<p>content</p>', { :layout => :my_layout }, { :name => 'Mike'}
|
160
|
+
end
|
161
|
+
}
|
162
|
+
|
163
|
+
get '/'
|
164
|
+
assert ok?
|
165
|
+
assert_equal 'Hello Mike!<p>content</p>', body
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'loads templates defined in subclasses' do
|
169
|
+
base = Class.new(aldebaran::Base)
|
170
|
+
base.template(:foo) { 'bar' }
|
171
|
+
render_app(base) { render :test, :foo }
|
172
|
+
assert ok?
|
173
|
+
assert_equal 'bar', body
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'allows setting default content type per template engine' do
|
177
|
+
render_app(:str => { :content_type => :txt }) { render :str, 'foo' }
|
178
|
+
assert_equal 'text/plain;charset=utf-8', response['Content-Type']
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'setting default content type does not affect other template engines' do
|
182
|
+
render_app(:str => { :content_type => :txt }) { render :test, 'foo' }
|
183
|
+
assert_equal 'text/html;charset=utf-8', response['Content-Type']
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'setting default content type per template engine does not override content_type' do
|
187
|
+
render_app :str => { :content_type => :txt } do
|
188
|
+
content_type :html
|
189
|
+
render :str, 'foo'
|
190
|
+
end
|
191
|
+
assert_equal 'text/html;charset=utf-8', response['Content-Type']
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'uses templates in superclasses before subclasses' do
|
195
|
+
base = Class.new(aldebaran::Base)
|
196
|
+
base.template(:foo) { 'template in superclass' }
|
197
|
+
assert_equal 'template in superclass', base.templates[:foo].first.call
|
198
|
+
|
199
|
+
mock_app(base) {
|
200
|
+
set :views, File.dirname(__FILE__) + '/views'
|
201
|
+
template(:foo) { 'template in subclass' }
|
202
|
+
get('/') { render :test, :foo }
|
203
|
+
}
|
204
|
+
assert_equal 'template in subclass', @app.templates[:foo].first.call
|
205
|
+
|
206
|
+
get '/'
|
207
|
+
assert ok?
|
208
|
+
assert_equal 'template in subclass', body
|
209
|
+
end
|
210
|
+
|
211
|
+
it "is possible to use a different engine for the layout than for the template itself explicitely" do
|
212
|
+
render_app do
|
213
|
+
settings.template(:layout) { 'Hello <%= yield %>!' }
|
214
|
+
render :str, "<%= 'World' %>", :layout_engine => :erb
|
215
|
+
end
|
216
|
+
assert_equal "Hello <%= 'World' %>!", body
|
217
|
+
end
|
218
|
+
|
219
|
+
it "is possible to use a different engine for the layout than for the template itself globally" do
|
220
|
+
render_app :str => { :layout_engine => :erb } do
|
221
|
+
settings.template(:layout) { 'Hello <%= yield %>!' }
|
222
|
+
render :str, "<%= 'World' %>"
|
223
|
+
end
|
224
|
+
assert_equal "Hello <%= 'World' %>!", body
|
225
|
+
end
|
226
|
+
|
227
|
+
it "does not leak the content type to the template" do
|
228
|
+
render_app :str => { :layout_engine => :erb } do
|
229
|
+
settings.template(:layout) { 'Hello <%= yield %>!' }
|
230
|
+
render :str, "<%= 'World' %>", :content_type => :txt
|
231
|
+
end
|
232
|
+
assert_equal "text/html;charset=utf-8", headers['Content-Type']
|
233
|
+
end
|
234
|
+
|
235
|
+
it "is possible to register another template" do
|
236
|
+
Tilt.register "html.erb", Tilt[:erb]
|
237
|
+
render_app { render :erb, :calc }
|
238
|
+
assert_equal '2', body
|
239
|
+
end
|
240
|
+
|
241
|
+
it "passes scope to the template" do
|
242
|
+
mock_app do
|
243
|
+
template :scoped do
|
244
|
+
'Hello <%= foo %>'
|
245
|
+
end
|
246
|
+
|
247
|
+
get '/' do
|
248
|
+
some_scope = Object.new
|
249
|
+
def some_scope.foo() 'World!' end
|
250
|
+
erb :scoped, :scope => some_scope
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
get '/'
|
255
|
+
assert ok?
|
256
|
+
assert_equal 'Hello World!', body
|
257
|
+
end
|
258
|
+
|
259
|
+
it "is possible to use custom logic for finding template files" do
|
260
|
+
mock_app do
|
261
|
+
set :views, ["a", "b"].map { |d| File.dirname(__FILE__) + '/views/' + d }
|
262
|
+
def find_template(views, name, engine, &block)
|
263
|
+
Array(views).each { |v| super(v, name, engine, &block) }
|
264
|
+
end
|
265
|
+
|
266
|
+
get('/:name') do
|
267
|
+
render :str, params[:name].to_sym
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
get '/in_a'
|
272
|
+
assert_body 'Gimme an A!'
|
273
|
+
|
274
|
+
get '/in_b'
|
275
|
+
assert_body 'Gimme a B!'
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# __END__ : this is not the real end of the script.
|
280
|
+
|
281
|
+
__END__
|
282
|
+
|
283
|
+
@@ foo
|
284
|
+
this is foo
|
285
|
+
|
286
|
+
@@ bar
|
287
|
+
There's a space after 'bar'!
|
288
|
+
|
289
|
+
@@ foo bar
|
290
|
+
this is not foo
|
291
|
+
|
292
|
+
@@ umlaut
|
293
|
+
Den som tror at hemma det är där man bor har aldrig vart hos mig.
|
294
|
+
|
295
|
+
@@ layout
|
296
|
+
X
|
297
|
+
= yield
|
298
|
+
X
|