gin 0.0.0 → 1.0.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.
- data/.autotest +3 -3
- data/.gitignore +7 -0
- data/History.rdoc +3 -6
- data/Manifest.txt +36 -2
- data/README.rdoc +24 -14
- data/Rakefile +2 -9
- data/lib/gin.rb +122 -1
- data/lib/gin/app.rb +595 -0
- data/lib/gin/config.rb +50 -0
- data/lib/gin/controller.rb +602 -0
- data/lib/gin/core_ext/cgi.rb +15 -0
- data/lib/gin/core_ext/gin_class.rb +10 -0
- data/lib/gin/errorable.rb +113 -0
- data/lib/gin/filterable.rb +200 -0
- data/lib/gin/reloadable.rb +90 -0
- data/lib/gin/request.rb +76 -0
- data/lib/gin/response.rb +51 -0
- data/lib/gin/router.rb +222 -0
- data/lib/gin/stream.rb +56 -0
- data/public/400.html +14 -0
- data/public/404.html +13 -0
- data/public/500.html +14 -0
- data/public/error.html +38 -0
- data/public/favicon.ico +0 -0
- data/public/gin.css +61 -0
- data/public/gin_sm.png +0 -0
- data/test/app/app_foo.rb +15 -0
- data/test/app/controllers/app_controller.rb +16 -0
- data/test/app/controllers/foo_controller.rb +3 -0
- data/test/mock_config/backend.yml +7 -0
- data/test/mock_config/memcache.yml +10 -0
- data/test/mock_config/not_a_config.txt +0 -0
- data/test/test_app.rb +592 -0
- data/test/test_config.rb +33 -0
- data/test/test_controller.rb +808 -0
- data/test/test_errorable.rb +221 -0
- data/test/test_filterable.rb +126 -0
- data/test/test_gin.rb +59 -0
- data/test/test_helper.rb +5 -0
- data/test/test_request.rb +81 -0
- data/test/test_response.rb +68 -0
- data/test/test_router.rb +193 -0
- metadata +80 -15
- data/bin/gin +0 -3
- data/test/gin_test.rb +0 -8
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class ErrorableTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class Foo
|
6
|
+
include Gin::Errorable
|
7
|
+
|
8
|
+
def self.delete_all_handlers!
|
9
|
+
@err_handlers = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :env
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@status = 200
|
16
|
+
@env = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def status val=nil
|
20
|
+
@status = val if val
|
21
|
+
@status
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Bar < Foo; end
|
26
|
+
|
27
|
+
|
28
|
+
def setup
|
29
|
+
Foo.delete_all_handlers!
|
30
|
+
Bar.delete_all_handlers!
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def test_handler_lookup
|
35
|
+
block_404 = lambda{|err| "404" }
|
36
|
+
block_err = lambda{|err| "ERROR'D!" }
|
37
|
+
|
38
|
+
Foo.error(404, &block_404)
|
39
|
+
Foo.error(Exception, &block_err)
|
40
|
+
|
41
|
+
assert_equal block_404, Foo.error_handler_for(404)
|
42
|
+
assert_equal block_err, Foo.error_handler_for(Exception.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def test_handler_local_fallback
|
47
|
+
block_def = lambda{|err| "default" }
|
48
|
+
Foo.error(&block_def)
|
49
|
+
assert_equal block_def, Foo.error_handler_for(404)
|
50
|
+
assert_equal block_def, Foo.error_handler_for(ArgumentError.new)
|
51
|
+
|
52
|
+
block_err = lambda{|err| "ERROR'D!" }
|
53
|
+
Foo.error(StandardError, &block_err)
|
54
|
+
assert_equal block_err, Foo.error_handler_for(ArgumentError.new)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def test_handler_inheritance
|
59
|
+
block_404 = lambda{|err| "404" }
|
60
|
+
block_err = lambda{|err| "ERROR'D!" }
|
61
|
+
Foo.error(StandardError, &block_err)
|
62
|
+
Foo.error(404, &block_404)
|
63
|
+
|
64
|
+
assert_equal block_404, Bar.error_handler_for(404)
|
65
|
+
assert_equal block_err, Bar.error_handler_for(ArgumentError.new)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def test_handler_inheritance_fallback
|
70
|
+
block_404 = lambda{|err| "404" }
|
71
|
+
block_def = lambda{|err| "default" }
|
72
|
+
Foo.error(&block_def)
|
73
|
+
Bar.error(404, &block_404)
|
74
|
+
|
75
|
+
assert_equal block_404, Bar.error_handler_for(404)
|
76
|
+
assert_equal block_def, Bar.error_handler_for(ArgumentError.new)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def test_handler_err_inheritance_order
|
81
|
+
block_err = lambda{|err| "ERROR'D!" }
|
82
|
+
block_def = lambda{|err| "default" }
|
83
|
+
Foo.error(ArgumentError, &block_err)
|
84
|
+
Bar.error(&block_def)
|
85
|
+
|
86
|
+
assert_equal block_def, Bar.error_handler_for(ArgumentError.new)
|
87
|
+
|
88
|
+
block_err2 = lambda{|err| "ERROR'D!" }
|
89
|
+
Bar.error(Exception, &block_err2)
|
90
|
+
|
91
|
+
assert_equal block_err2, Bar.error_handler_for(ArgumentError.new)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def test_handler_status_inheritance_order
|
96
|
+
block_404 = lambda{|err| "404" }
|
97
|
+
block_def = lambda{|err| "default" }
|
98
|
+
Foo.error(404, &block_404)
|
99
|
+
Bar.error(&block_def)
|
100
|
+
|
101
|
+
assert_equal block_def, Bar.error_handler_for(ArgumentError.new)
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def test_handle_status
|
106
|
+
handlers = []
|
107
|
+
Foo.error{ handlers << :default }
|
108
|
+
Foo.all_errors{ handlers << :all }
|
109
|
+
Foo.error(404){ handlers << :s404 }
|
110
|
+
|
111
|
+
Foo.new.handle_status(404)
|
112
|
+
assert_equal [:s404], handlers
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def test_handle_status_missing
|
117
|
+
assert_nil Foo.new.handle_status(404)
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def test_handle_error
|
122
|
+
handlers = []
|
123
|
+
Foo.error{ handlers << :default }
|
124
|
+
|
125
|
+
err = ArgumentError.new
|
126
|
+
foo = Foo.new
|
127
|
+
foo.handle_error(err)
|
128
|
+
|
129
|
+
assert_equal [err], foo.env['gin.errors']
|
130
|
+
assert_equal [:default], handlers
|
131
|
+
assert_equal 500, foo.status
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def test_all_errors_no_rescue_handler
|
136
|
+
handlers = []
|
137
|
+
Foo.all_errors{ handlers << :all }
|
138
|
+
|
139
|
+
err = ArgumentError.new
|
140
|
+
bar = Bar.new
|
141
|
+
|
142
|
+
assert_raises ArgumentError do
|
143
|
+
bar.handle_error err
|
144
|
+
end
|
145
|
+
|
146
|
+
assert_equal [err], bar.env['gin.errors']
|
147
|
+
assert_equal [:all], handlers
|
148
|
+
assert_equal 500, bar.status
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def test_handle_error_all_errors
|
153
|
+
handlers = []
|
154
|
+
err = ArgumentError.new
|
155
|
+
|
156
|
+
Foo.error{|e| raise "Unexpected Error" unless err == e; handlers << :default }
|
157
|
+
Foo.all_errors{|e| raise "Unexpected Error" unless err == e; handlers << :all }
|
158
|
+
|
159
|
+
foo = Foo.new
|
160
|
+
foo.handle_error(err)
|
161
|
+
|
162
|
+
assert_equal [err], foo.env['gin.errors']
|
163
|
+
assert_equal [:default, :all], handlers
|
164
|
+
assert_equal 500, foo.status
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def test_handle_error_with_status
|
169
|
+
Foo.error(Gin::NotFound){ "OOPS" }
|
170
|
+
foo = Foo.new
|
171
|
+
|
172
|
+
foo.status 200
|
173
|
+
foo.handle_error(Gin::NotFound.new)
|
174
|
+
assert_equal 404, foo.status
|
175
|
+
|
176
|
+
foo.status 302
|
177
|
+
foo.handle_error(Gin::NotFound.new)
|
178
|
+
assert_equal 404, foo.status
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def test_handle_error_preset_status
|
183
|
+
Foo.error{ "OOPS" }
|
184
|
+
foo = Foo.new
|
185
|
+
|
186
|
+
foo.status(400)
|
187
|
+
foo.handle_error(ArgumentError.new)
|
188
|
+
assert_equal 400, foo.status
|
189
|
+
|
190
|
+
foo.status(302)
|
191
|
+
foo.handle_error(ArgumentError.new)
|
192
|
+
assert_equal 500, foo.status
|
193
|
+
|
194
|
+
foo.status(200)
|
195
|
+
foo.handle_error(ArgumentError.new)
|
196
|
+
assert_equal 500, foo.status
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def test_handle_error_preset_status_with_status
|
201
|
+
Foo.error(Gin::NotFound){ "OOPS" }
|
202
|
+
foo = Foo.new
|
203
|
+
foo.status(400)
|
204
|
+
foo.handle_error(Gin::NotFound.new)
|
205
|
+
|
206
|
+
assert_equal 404, foo.status
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
def test_handle_error_missing
|
211
|
+
foo = Foo.new
|
212
|
+
err = ArgumentError.new
|
213
|
+
|
214
|
+
assert_raises ArgumentError do
|
215
|
+
foo.handle_error(err)
|
216
|
+
end
|
217
|
+
|
218
|
+
assert_equal [err], foo.env['gin.errors']
|
219
|
+
assert_equal 500, foo.status
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class FilterableTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
FILTER_CALLS = []
|
6
|
+
|
7
|
+
class AppCtrl
|
8
|
+
include Gin::Filterable
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :is_logged_in
|
12
|
+
end
|
13
|
+
|
14
|
+
self.is_logged_in = true
|
15
|
+
|
16
|
+
filter :logged_in do
|
17
|
+
FILTER_CALLS << :logged_in
|
18
|
+
self.class.is_logged_in
|
19
|
+
end
|
20
|
+
|
21
|
+
filter :find_device do
|
22
|
+
FILTER_CALLS << :find_device
|
23
|
+
"iPhone"
|
24
|
+
end
|
25
|
+
|
26
|
+
filter :log_action do
|
27
|
+
FILTER_CALLS << :log_action
|
28
|
+
"foo"
|
29
|
+
end
|
30
|
+
|
31
|
+
filter :set_login_cookie do
|
32
|
+
FILTER_CALLS << :set_login_cookie
|
33
|
+
"COOKIES"
|
34
|
+
end
|
35
|
+
|
36
|
+
filter :other_filter do
|
37
|
+
FILTER_CALLS << :other_filter
|
38
|
+
"other_filter"
|
39
|
+
end
|
40
|
+
|
41
|
+
before_filter :logged_in
|
42
|
+
before_filter :find_device
|
43
|
+
|
44
|
+
after_filter :log_action
|
45
|
+
after_filter :set_login_cookie, :other_filter, :except => :foo
|
46
|
+
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def __call_filters__ type, action #:nodoc:
|
51
|
+
filter(*__send__(:"#{type}_filters_for", action))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class SessionCtrl < AppCtrl
|
57
|
+
class << self
|
58
|
+
attr_accessor :is_custom_thing
|
59
|
+
end
|
60
|
+
|
61
|
+
self.is_logged_in = true
|
62
|
+
self.is_custom_thing = true
|
63
|
+
|
64
|
+
filter :custom_thing do
|
65
|
+
FILTER_CALLS << :custom_thing
|
66
|
+
self.class.is_custom_thing
|
67
|
+
end
|
68
|
+
|
69
|
+
before_filter :custom_thing
|
70
|
+
|
71
|
+
skip_before_filter :find_device
|
72
|
+
skip_before_filter :logged_in, :only => [:create, :new]
|
73
|
+
skip_after_filter :set_login_cookie, :except => [:logout]
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
def setup
|
79
|
+
FILTER_CALLS.clear
|
80
|
+
@app_ctrl = AppCtrl.new
|
81
|
+
@session_ctrl = SessionCtrl.new
|
82
|
+
SessionCtrl.is_logged_in = true
|
83
|
+
SessionCtrl.is_custom_thing = true
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def test_filter_chain_inheritance
|
88
|
+
assert_equal [:logged_in, :find_device],
|
89
|
+
AppCtrl.before_filters[nil]
|
90
|
+
|
91
|
+
assert_equal [:logged_in, :custom_thing],
|
92
|
+
SessionCtrl.before_filters[nil]
|
93
|
+
|
94
|
+
assert_equal [:log_action, :set_login_cookie, :other_filter],
|
95
|
+
AppCtrl.after_filters[nil]
|
96
|
+
|
97
|
+
assert_equal [:log_action, :other_filter],
|
98
|
+
SessionCtrl.after_filters[nil]
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def test_call_filters
|
103
|
+
@app_ctrl.send(:__call_filters__, :before, :action)
|
104
|
+
assert_equal [:logged_in, :find_device], FILTER_CALLS
|
105
|
+
|
106
|
+
FILTER_CALLS.clear
|
107
|
+
@session_ctrl.send(:__call_filters__, :before, :action)
|
108
|
+
assert_equal [:logged_in, :custom_thing], FILTER_CALLS
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def test_call_filters_with_restrictions
|
113
|
+
@app_ctrl.send(:__call_filters__, :before, :create)
|
114
|
+
assert_equal [:logged_in, :find_device], FILTER_CALLS
|
115
|
+
|
116
|
+
FILTER_CALLS.clear
|
117
|
+
@session_ctrl.send(:__call_filters__, :before, :create)
|
118
|
+
assert_equal [:custom_thing], FILTER_CALLS
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def test_filter_calls
|
123
|
+
@session_ctrl.filter :logged_in, :custom_thing, :other_filter
|
124
|
+
assert_equal [:logged_in, :custom_thing, :other_filter], FILTER_CALLS
|
125
|
+
end
|
126
|
+
end
|
data/test/test_gin.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class GinTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_underscore
|
6
|
+
assert_equal "foo_bar", Gin.underscore("FooBar")
|
7
|
+
assert_equal "foo_bar", Gin.underscore("fooBar")
|
8
|
+
assert_equal "foo_bar", Gin.underscore("foo_Bar")
|
9
|
+
assert_equal "foo_http", Gin.underscore("fooHTTP")
|
10
|
+
assert_equal "foo_http_thing", Gin.underscore("fooHTTPThing")
|
11
|
+
assert_equal "foo/bar", Gin.underscore("Foo::Bar")
|
12
|
+
assert_equal "foo/http", Gin.underscore("Foo::HTTP")
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def test_build_query
|
17
|
+
hash = {a: "bob", b: [1,2.2,-3,{ba:"test"}], c:true, d:false}
|
18
|
+
expected = "a=bob&b[]=1&b[]=2.2&b[]=-3&b[][ba]=test&c=true&d=false"
|
19
|
+
assert_equal expected, Gin.build_query(hash)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def test_build_query_non_hash
|
24
|
+
[[1,2,3], 1, 1.2, "str"].each do |obj|
|
25
|
+
assert_raises(ArgumentError, "#{obj.class} did not raise ArgumentError") do
|
26
|
+
Gin.build_query obj
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def test_find_loadpath
|
33
|
+
assert_equal __FILE__, Gin.find_loadpath("test/test_gin")
|
34
|
+
assert_equal __FILE__, Gin.find_loadpath("test/test_gin.rb")
|
35
|
+
assert_equal __FILE__, Gin.find_loadpath(__FILE__)
|
36
|
+
assert_nil Gin.find_loadpath("FUUUUU")
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def test_const_find
|
41
|
+
assert_equal Test::Unit, Gin.const_find("Test::Unit")
|
42
|
+
assert_equal Test::Unit, Gin.const_find("Unit", Test)
|
43
|
+
assert_raises(NameError){ Gin.const_find("Unit", Gin) }
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def test_app_trace
|
48
|
+
trace = [
|
49
|
+
Gin::LIB_DIR + "/thing",
|
50
|
+
"/path/to/app/thing",
|
51
|
+
Gin::LIB_DIR + "/gin/app.rb:123:in `dispatch'",
|
52
|
+
Gem.path[0] + "/foo",
|
53
|
+
"/stuff/to/ignore"
|
54
|
+
]
|
55
|
+
|
56
|
+
assert_equal [Gin::LIB_DIR + "/thing", "/path/to/app/thing"],
|
57
|
+
Gin.app_trace(trace)
|
58
|
+
end
|
59
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class RequestTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@env = {
|
7
|
+
'HTTP_HOST' => 'example.com',
|
8
|
+
'rack.input' => '',
|
9
|
+
'QUERY_STRING' => 'id=456&foo=bar&bar=5&bool=true',
|
10
|
+
'gin.path_query_hash' => {'id' => 123},
|
11
|
+
}
|
12
|
+
@req = Gin::Request.new @env
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def test_query_hash_as_param
|
17
|
+
assert_equal 123, @req.params['id']
|
18
|
+
assert_equal 'bar', @req.params['foo']
|
19
|
+
assert_equal 5, @req.params['bar']
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def test_params_symbol_accessible
|
24
|
+
[:id, :foo, :bar].each do |key|
|
25
|
+
assert @req.params[key]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def test_forwarded
|
31
|
+
assert !@req.forwarded?
|
32
|
+
@env["HTTP_X_FORWARDED_HOST"] = "example.com"
|
33
|
+
assert @req.forwarded?
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_ssl
|
38
|
+
assert !@req.ssl?
|
39
|
+
|
40
|
+
@env['HTTPS'] = 'on'
|
41
|
+
assert @req.ssl?
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def test_safe
|
46
|
+
@env['REQUEST_METHOD'] = 'POST'
|
47
|
+
assert !@req.safe?, "Verb POST should NOT be safe"
|
48
|
+
|
49
|
+
%w{GET HEAD OPTIONS TRACE}.each do |verb|
|
50
|
+
@env['REQUEST_METHOD'] = verb
|
51
|
+
assert @req.safe?, "Verb #{verb} should be safe"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def test_idempotent
|
57
|
+
@env['REQUEST_METHOD'] = 'POST'
|
58
|
+
assert !@req.idempotent?, "Verb POST should NOT be idempotent"
|
59
|
+
|
60
|
+
%w{GET HEAD OPTIONS TRACE PUT DELETE}.each do |verb|
|
61
|
+
@env['REQUEST_METHOD'] = verb
|
62
|
+
assert @req.idempotent?, "Verb #{verb} should be idempotent"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def test_process_params
|
68
|
+
assert_equal true, @req.send(:process_params, "true")
|
69
|
+
assert_equal false, @req.send(:process_params, "false")
|
70
|
+
assert_equal 1, @req.send(:process_params, "1")
|
71
|
+
assert_equal 1.1, @req.send(:process_params, "1.1")
|
72
|
+
assert_equal "not_true", @req.send(:process_params, "not_true")
|
73
|
+
|
74
|
+
ary = @req.send(:process_params, ["true", "1", "foo"])
|
75
|
+
assert_equal [true, 1, "foo"], ary
|
76
|
+
|
77
|
+
hash = @req.send(:process_params, {'key' => ["true", "1", "foo"]})
|
78
|
+
assert_equal [true, 1, "foo"], hash['key']
|
79
|
+
assert_equal hash['key'].object_id, hash[:key].object_id
|
80
|
+
end
|
81
|
+
end
|