sinatra-base 1.0

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 (58) hide show
  1. data/AUTHORS +43 -0
  2. data/CHANGES +511 -0
  3. data/LICENSE +22 -0
  4. data/README.jp.rdoc +552 -0
  5. data/README.rdoc +636 -0
  6. data/Rakefile +116 -0
  7. data/lib/sinatra.rb +7 -0
  8. data/lib/sinatra/base.rb +1167 -0
  9. data/lib/sinatra/images/404.png +0 -0
  10. data/lib/sinatra/images/500.png +0 -0
  11. data/lib/sinatra/main.rb +28 -0
  12. data/lib/sinatra/showexceptions.rb +307 -0
  13. data/lib/sinatra/tilt.rb +746 -0
  14. data/sinatra-base.gemspec +94 -0
  15. data/test/base_test.rb +160 -0
  16. data/test/builder_test.rb +65 -0
  17. data/test/contest.rb +64 -0
  18. data/test/erb_test.rb +81 -0
  19. data/test/erubis_test.rb +82 -0
  20. data/test/extensions_test.rb +100 -0
  21. data/test/filter_test.rb +221 -0
  22. data/test/haml_test.rb +95 -0
  23. data/test/helper.rb +76 -0
  24. data/test/helpers_test.rb +582 -0
  25. data/test/less_test.rb +37 -0
  26. data/test/mapped_error_test.rb +197 -0
  27. data/test/middleware_test.rb +68 -0
  28. data/test/public/favicon.ico +0 -0
  29. data/test/request_test.rb +33 -0
  30. data/test/response_test.rb +42 -0
  31. data/test/result_test.rb +98 -0
  32. data/test/route_added_hook_test.rb +59 -0
  33. data/test/routing_test.rb +860 -0
  34. data/test/sass_test.rb +85 -0
  35. data/test/server_test.rb +47 -0
  36. data/test/settings_test.rb +368 -0
  37. data/test/sinatra_test.rb +13 -0
  38. data/test/static_test.rb +93 -0
  39. data/test/templates_test.rb +159 -0
  40. data/test/views/error.builder +3 -0
  41. data/test/views/error.erb +3 -0
  42. data/test/views/error.erubis +3 -0
  43. data/test/views/error.haml +3 -0
  44. data/test/views/error.sass +2 -0
  45. data/test/views/foo/hello.test +1 -0
  46. data/test/views/hello.builder +1 -0
  47. data/test/views/hello.erb +1 -0
  48. data/test/views/hello.erubis +1 -0
  49. data/test/views/hello.haml +1 -0
  50. data/test/views/hello.less +5 -0
  51. data/test/views/hello.sass +2 -0
  52. data/test/views/hello.test +1 -0
  53. data/test/views/layout2.builder +3 -0
  54. data/test/views/layout2.erb +2 -0
  55. data/test/views/layout2.erubis +2 -0
  56. data/test/views/layout2.haml +2 -0
  57. data/test/views/layout2.test +1 -0
  58. metadata +257 -0
@@ -0,0 +1,94 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+
5
+ s.name = 'sinatra-base'
6
+ s.version = '1.0'
7
+ s.date = '2010-03-23'
8
+
9
+ s.description = "Classy web-development dressed in a DSL"
10
+ s.summary = "Classy web-development dressed in a DSL"
11
+
12
+ s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet"]
13
+ s.email = "sinatrarb@googlegroups.com"
14
+
15
+ # = MANIFEST =
16
+ s.files = %w[
17
+ AUTHORS
18
+ CHANGES
19
+ LICENSE
20
+ README.jp.rdoc
21
+ README.rdoc
22
+ Rakefile
23
+ lib/sinatra.rb
24
+ lib/sinatra/base.rb
25
+ lib/sinatra/images/404.png
26
+ lib/sinatra/images/500.png
27
+ lib/sinatra/main.rb
28
+ lib/sinatra/showexceptions.rb
29
+ lib/sinatra/tilt.rb
30
+ sinatra-base.gemspec
31
+ test/base_test.rb
32
+ test/builder_test.rb
33
+ test/contest.rb
34
+ test/erb_test.rb
35
+ test/erubis_test.rb
36
+ test/extensions_test.rb
37
+ test/filter_test.rb
38
+ test/haml_test.rb
39
+ test/helper.rb
40
+ test/helpers_test.rb
41
+ test/less_test.rb
42
+ test/mapped_error_test.rb
43
+ test/middleware_test.rb
44
+ test/public/favicon.ico
45
+ test/request_test.rb
46
+ test/response_test.rb
47
+ test/result_test.rb
48
+ test/route_added_hook_test.rb
49
+ test/routing_test.rb
50
+ test/sass_test.rb
51
+ test/server_test.rb
52
+ test/settings_test.rb
53
+ test/sinatra_test.rb
54
+ test/static_test.rb
55
+ test/templates_test.rb
56
+ test/views/error.builder
57
+ test/views/error.erb
58
+ test/views/error.erubis
59
+ test/views/error.haml
60
+ test/views/error.sass
61
+ test/views/foo/hello.test
62
+ test/views/hello.builder
63
+ test/views/hello.erb
64
+ test/views/hello.erubis
65
+ test/views/hello.haml
66
+ test/views/hello.less
67
+ test/views/hello.sass
68
+ test/views/hello.test
69
+ test/views/layout2.builder
70
+ test/views/layout2.erb
71
+ test/views/layout2.erubis
72
+ test/views/layout2.haml
73
+ test/views/layout2.test
74
+ ]
75
+ # = MANIFEST =
76
+
77
+ s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
78
+
79
+ s.extra_rdoc_files = %w[README.rdoc LICENSE]
80
+ s.add_dependency 'rack', '>= 1.0'
81
+ s.add_development_dependency 'shotgun', '>= 0.6', '< 1.0'
82
+ s.add_development_dependency 'rack-test', '>= 0.3.0'
83
+ s.add_development_dependency 'haml'
84
+ s.add_development_dependency 'builder'
85
+ s.add_development_dependency 'erubis'
86
+ s.add_development_dependency 'less'
87
+
88
+ s.has_rdoc = true
89
+ s.homepage = "http://sinatra.rubyforge.org"
90
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sinatra", "--main", "README.rdoc"]
91
+ s.require_paths = %w[lib]
92
+ s.rubyforge_project = 'sinatra'
93
+ s.rubygems_version = '1.1.1'
94
+ end
@@ -0,0 +1,160 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+ def test_default
5
+ assert true
6
+ end
7
+
8
+ describe 'Sinatra::Base subclasses' do
9
+ class TestApp < Sinatra::Base
10
+ get '/' do
11
+ 'Hello World'
12
+ end
13
+ end
14
+
15
+ it 'include Rack::Utils' do
16
+ assert TestApp.included_modules.include?(Rack::Utils)
17
+ end
18
+
19
+ it 'processes requests with #call' do
20
+ assert TestApp.respond_to?(:call)
21
+
22
+ request = Rack::MockRequest.new(TestApp)
23
+ response = request.get('/')
24
+ assert response.ok?
25
+ assert_equal 'Hello World', response.body
26
+ end
27
+
28
+ class TestApp < Sinatra::Base
29
+ get '/state' do
30
+ @foo ||= "new"
31
+ body = "Foo: #{@foo}"
32
+ @foo = 'discard'
33
+ body
34
+ end
35
+ end
36
+
37
+ it 'does not maintain state between requests' do
38
+ request = Rack::MockRequest.new(TestApp)
39
+ 2.times do
40
+ response = request.get('/state')
41
+ assert response.ok?
42
+ assert_equal 'Foo: new', response.body
43
+ end
44
+ end
45
+
46
+ it "passes the subclass to configure blocks" do
47
+ ref = nil
48
+ TestApp.configure { |app| ref = app }
49
+ assert_equal TestApp, ref
50
+ end
51
+
52
+ it "allows the configure block arg to be omitted and does not change context" do
53
+ context = nil
54
+ TestApp.configure { context = self }
55
+ assert_equal self, context
56
+ end
57
+ end
58
+
59
+ describe "Sinatra::Base as Rack middleware" do
60
+ app = lambda { |env|
61
+ headers = {'X-Downstream' => 'true'}
62
+ headers['X-Route-Missing'] = env['sinatra.route-missing'] || ''
63
+ [210, headers, ['Hello from downstream']] }
64
+
65
+ class TestMiddleware < Sinatra::Base
66
+ end
67
+
68
+ it 'creates a middleware that responds to #call with .new' do
69
+ middleware = TestMiddleware.new(app)
70
+ assert middleware.respond_to?(:call)
71
+ end
72
+
73
+ it 'exposes the downstream app' do
74
+ middleware = TestMiddleware.new(app)
75
+ assert_same app, middleware.app
76
+ end
77
+
78
+ class TestMiddleware < Sinatra::Base
79
+ def route_missing
80
+ env['sinatra.route-missing'] = '1'
81
+ super
82
+ end
83
+
84
+ get '/' do
85
+ 'Hello from middleware'
86
+ end
87
+ end
88
+
89
+ middleware = TestMiddleware.new(app)
90
+ request = Rack::MockRequest.new(middleware)
91
+
92
+ it 'intercepts requests' do
93
+ response = request.get('/')
94
+ assert response.ok?
95
+ assert_equal 'Hello from middleware', response.body
96
+ end
97
+
98
+ it 'automatically forwards requests downstream when no matching route found' do
99
+ response = request.get('/missing')
100
+ assert_equal 210, response.status
101
+ assert_equal 'Hello from downstream', response.body
102
+ end
103
+
104
+ it 'calls #route_missing before forwarding downstream' do
105
+ response = request.get('/missing')
106
+ assert_equal '1', response['X-Route-Missing']
107
+ end
108
+
109
+ class TestMiddleware < Sinatra::Base
110
+ get '/low-level-forward' do
111
+ app.call(env)
112
+ end
113
+ end
114
+
115
+ it 'can call the downstream app directly and return result' do
116
+ response = request.get('/low-level-forward')
117
+ assert_equal 210, response.status
118
+ assert_equal 'true', response['X-Downstream']
119
+ assert_equal 'Hello from downstream', response.body
120
+ end
121
+
122
+ class TestMiddleware < Sinatra::Base
123
+ get '/explicit-forward' do
124
+ response['X-Middleware'] = 'true'
125
+ res = forward
126
+ assert_nil res
127
+ assert_equal 210, response.status
128
+ assert_equal 'true', response['X-Downstream']
129
+ assert_equal ['Hello from downstream'], response.body
130
+ 'Hello after explicit forward'
131
+ end
132
+ end
133
+
134
+ it 'forwards the request downstream and integrates the response into the current context' do
135
+ response = request.get('/explicit-forward')
136
+ assert_equal 210, response.status
137
+ assert_equal 'true', response['X-Downstream']
138
+ assert_equal 'Hello after explicit forward', response.body
139
+ assert_equal '28', response['Content-Length']
140
+ end
141
+
142
+ app_content_length = lambda {|env|
143
+ [200, {'Content-Length' => '16'}, 'From downstream!']}
144
+
145
+ class TestMiddlewareContentLength < Sinatra::Base
146
+ get '/forward' do
147
+ res = forward
148
+ 'From after explicit forward!'
149
+ end
150
+ end
151
+
152
+ middleware_content_length = TestMiddlewareContentLength.new(app_content_length)
153
+ request_content_length = Rack::MockRequest.new(middleware_content_length)
154
+
155
+ it "sets content length for last response" do
156
+ response = request_content_length.get('/forward')
157
+ assert_equal '28', response['Content-Length']
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'builder'
3
+
4
+ class BuilderTest < Test::Unit::TestCase
5
+ def builder_app(&block)
6
+ mock_app {
7
+ set :views, File.dirname(__FILE__) + '/views'
8
+ get '/', &block
9
+ }
10
+ get '/'
11
+ end
12
+
13
+ it 'renders inline Builder strings' do
14
+ builder_app { builder 'xml.instruct!' }
15
+ assert ok?
16
+ assert_equal %{<?xml version="1.0" encoding="UTF-8"?>\n}, body
17
+ end
18
+
19
+ it 'renders inline blocks' do
20
+ builder_app {
21
+ @name = "Frank & Mary"
22
+ builder do |xml|
23
+ xml.couple @name
24
+ end
25
+ }
26
+ assert ok?
27
+ assert_equal "<couple>Frank &amp; Mary</couple>\n", body
28
+ end
29
+
30
+ it 'renders .builder files in views path' do
31
+ builder_app {
32
+ @name = "Blue"
33
+ builder :hello
34
+ }
35
+ assert ok?
36
+ assert_equal %(<exclaim>You're my boy, Blue!</exclaim>\n), body
37
+ end
38
+
39
+ it "renders with inline layouts" do
40
+ mock_app {
41
+ layout do
42
+ %(xml.layout { xml << yield })
43
+ end
44
+ get('/') { builder %(xml.em 'Hello World') }
45
+ }
46
+ get '/'
47
+ assert ok?
48
+ assert_equal "<layout>\n<em>Hello World</em>\n</layout>\n", body
49
+ end
50
+
51
+ it "renders with file layouts" do
52
+ builder_app {
53
+ builder %(xml.em 'Hello World'), :layout => :layout2
54
+ }
55
+ assert ok?
56
+ assert_equal "<layout>\n<em>Hello World</em>\n</layout>\n", body
57
+ end
58
+
59
+ it "raises error if template not found" do
60
+ mock_app {
61
+ get('/') { builder :no_such_template }
62
+ }
63
+ assert_raise(Errno::ENOENT) { get('/') }
64
+ end
65
+ end
@@ -0,0 +1,64 @@
1
+ require "test/unit"
2
+
3
+ # Test::Unit loads a default test if the suite is empty, and the only
4
+ # purpose of that test is to fail. As having empty contexts is a common
5
+ # practice, we decided to overwrite TestSuite#empty? in order to
6
+ # allow them. Having a failure when no tests have been defined seems
7
+ # counter-intuitive.
8
+ class Test::Unit::TestSuite
9
+ unless method_defined?(:empty?)
10
+ def empty?
11
+ false
12
+ end
13
+ end
14
+ end
15
+
16
+ # We added setup, test and context as class methods, and the instance
17
+ # method setup now iterates on the setup blocks. Note that all setup
18
+ # blocks must be defined with the block syntax. Adding a setup instance
19
+ # method defeats the purpose of this library.
20
+ class Test::Unit::TestCase
21
+ def self.setup(&block)
22
+ setup_blocks << block
23
+ end
24
+
25
+ def setup
26
+ self.class.setup_blocks.each do |block|
27
+ instance_eval(&block)
28
+ end
29
+ end
30
+
31
+ def self.context(name, &block)
32
+ subclass = Class.new(self.superclass)
33
+ subclass.setup_blocks.unshift(*setup_blocks)
34
+ subclass.class_eval(&block)
35
+ const_set(context_name(name), subclass)
36
+ end
37
+
38
+ def self.test(name, &block)
39
+ define_method(test_name(name), &block)
40
+ end
41
+
42
+ class << self
43
+ alias_method :should, :test
44
+ alias_method :describe, :context
45
+ end
46
+
47
+ private
48
+
49
+ def self.setup_blocks
50
+ @setup_blocks ||= []
51
+ end
52
+
53
+ def self.context_name(name)
54
+ "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
55
+ end
56
+
57
+ def self.test_name(name)
58
+ "test_#{sanitize_name(name).gsub(/\s+/,'_')}".to_sym
59
+ end
60
+
61
+ def self.sanitize_name(name)
62
+ name.gsub(/\W+/, ' ').strip
63
+ end
64
+ end
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ERBTest < Test::Unit::TestCase
4
+ def erb_app(&block)
5
+ mock_app {
6
+ set :views, File.dirname(__FILE__) + '/views'
7
+ get '/', &block
8
+ }
9
+ get '/'
10
+ end
11
+
12
+ it 'renders inline ERB strings' do
13
+ erb_app { erb '<%= 1 + 1 %>' }
14
+ assert ok?
15
+ assert_equal '2', body
16
+ end
17
+
18
+ it 'renders .erb files in views path' do
19
+ erb_app { erb :hello }
20
+ assert ok?
21
+ assert_equal "Hello World\n", body
22
+ end
23
+
24
+ it 'takes a :locals option' do
25
+ erb_app {
26
+ locals = {:foo => 'Bar'}
27
+ erb '<%= foo %>', :locals => locals
28
+ }
29
+ assert ok?
30
+ assert_equal 'Bar', body
31
+ end
32
+
33
+ it "renders with inline layouts" do
34
+ mock_app {
35
+ layout { 'THIS. IS. <%= yield.upcase %>!' }
36
+ get('/') { erb 'Sparta' }
37
+ }
38
+ get '/'
39
+ assert ok?
40
+ assert_equal 'THIS. IS. SPARTA!', body
41
+ end
42
+
43
+ it "renders with file layouts" do
44
+ erb_app {
45
+ erb 'Hello World', :layout => :layout2
46
+ }
47
+ assert ok?
48
+ assert_equal "ERB Layout!\nHello World\n", body
49
+ end
50
+
51
+ it "renders erb with blocks" do
52
+ mock_app {
53
+ def container
54
+ @_out_buf << "THIS."
55
+ yield
56
+ @_out_buf << "SPARTA!"
57
+ end
58
+ def is; "IS." end
59
+ get '/' do
60
+ erb '<% container do %> <%= is %> <% end %>'
61
+ end
62
+ }
63
+ get '/'
64
+ assert ok?
65
+ assert_equal 'THIS. IS. SPARTA!', body
66
+ end
67
+
68
+ it "can be used in a nested fashion for partials and whatnot" do
69
+ mock_app {
70
+ template(:inner) { "<inner><%= 'hi' %></inner>" }
71
+ template(:outer) { "<outer><%= erb :inner %></outer>" }
72
+ get '/' do
73
+ erb :outer
74
+ end
75
+ }
76
+
77
+ get '/'
78
+ assert ok?
79
+ assert_equal '<outer><inner>hi</inner></outer>', body
80
+ end
81
+ end