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.
Files changed (97) hide show
  1. data/.gitignore +13 -0
  2. data/.travis.yml +16 -0
  3. data/.yardopts +4 -0
  4. data/AUTHORS +4 -0
  5. data/Gemfile +77 -0
  6. data/KNOWN_ISSUES +5 -0
  7. data/LICENSE +22 -0
  8. data/README.rdoc +1900 -0
  9. data/Rakefile +175 -0
  10. data/aldebaran.gemspec +19 -0
  11. data/lib/aldebaran.rb +7 -0
  12. data/lib/aldebaran/base.rb +1600 -0
  13. data/lib/aldebaran/images/404.png +0 -0
  14. data/lib/aldebaran/images/500.png +0 -0
  15. data/lib/aldebaran/main.rb +28 -0
  16. data/lib/aldebaran/showexceptions.rb +340 -0
  17. data/lib/aldebaran/version.rb +3 -0
  18. data/test/aldebaran_test.rb +17 -0
  19. data/test/base_test.rb +160 -0
  20. data/test/builder_test.rb +95 -0
  21. data/test/coffee_test.rb +92 -0
  22. data/test/contest.rb +98 -0
  23. data/test/creole_test.rb +65 -0
  24. data/test/delegator_test.rb +162 -0
  25. data/test/encoding_test.rb +20 -0
  26. data/test/erb_test.rb +104 -0
  27. data/test/extensions_test.rb +100 -0
  28. data/test/filter_test.rb +397 -0
  29. data/test/haml_test.rb +101 -0
  30. data/test/helper.rb +115 -0
  31. data/test/helpers_test.rb +1192 -0
  32. data/test/less_test.rb +67 -0
  33. data/test/liquid_test.rb +59 -0
  34. data/test/mapped_error_test.rb +259 -0
  35. data/test/markaby_test.rb +80 -0
  36. data/test/markdown_test.rb +81 -0
  37. data/test/middleware_test.rb +68 -0
  38. data/test/nokogiri_test.rb +69 -0
  39. data/test/public/favicon.ico +0 -0
  40. data/test/radius_test.rb +59 -0
  41. data/test/rdoc_test.rb +65 -0
  42. data/test/readme_test.rb +136 -0
  43. data/test/request_test.rb +45 -0
  44. data/test/response_test.rb +61 -0
  45. data/test/result_test.rb +98 -0
  46. data/test/route_added_hook_test.rb +59 -0
  47. data/test/routing_test.rb +1096 -0
  48. data/test/sass_test.rb +115 -0
  49. data/test/scss_test.rb +88 -0
  50. data/test/server_test.rb +48 -0
  51. data/test/settings_test.rb +493 -0
  52. data/test/slim_test.rb +98 -0
  53. data/test/static_test.rb +178 -0
  54. data/test/streaming_test.rb +100 -0
  55. data/test/templates_test.rb +298 -0
  56. data/test/textile_test.rb +65 -0
  57. data/test/views/a/in_a.str +1 -0
  58. data/test/views/ascii.erb +2 -0
  59. data/test/views/b/in_b.str +1 -0
  60. data/test/views/calc.html.erb +1 -0
  61. data/test/views/error.builder +3 -0
  62. data/test/views/error.erb +3 -0
  63. data/test/views/error.haml +3 -0
  64. data/test/views/error.sass +2 -0
  65. data/test/views/explicitly_nested.str +1 -0
  66. data/test/views/foo/hello.test +1 -0
  67. data/test/views/hello.builder +1 -0
  68. data/test/views/hello.coffee +1 -0
  69. data/test/views/hello.creole +1 -0
  70. data/test/views/hello.erb +1 -0
  71. data/test/views/hello.haml +1 -0
  72. data/test/views/hello.less +5 -0
  73. data/test/views/hello.liquid +1 -0
  74. data/test/views/hello.mab +1 -0
  75. data/test/views/hello.md +1 -0
  76. data/test/views/hello.nokogiri +1 -0
  77. data/test/views/hello.radius +1 -0
  78. data/test/views/hello.rdoc +1 -0
  79. data/test/views/hello.sass +2 -0
  80. data/test/views/hello.scss +3 -0
  81. data/test/views/hello.slim +1 -0
  82. data/test/views/hello.str +1 -0
  83. data/test/views/hello.test +1 -0
  84. data/test/views/hello.textile +1 -0
  85. data/test/views/layout2.builder +3 -0
  86. data/test/views/layout2.erb +2 -0
  87. data/test/views/layout2.haml +2 -0
  88. data/test/views/layout2.liquid +2 -0
  89. data/test/views/layout2.mab +2 -0
  90. data/test/views/layout2.nokogiri +3 -0
  91. data/test/views/layout2.radius +2 -0
  92. data/test/views/layout2.slim +3 -0
  93. data/test/views/layout2.str +2 -0
  94. data/test/views/layout2.test +1 -0
  95. data/test/views/nested.str +1 -0
  96. data/test/views/utf8.erb +2 -0
  97. metadata +231 -0
@@ -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
@@ -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