rocketio 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -5
- data/.pryrc +2 -0
- data/.travis.yml +3 -0
- data/README.md +22 -5
- data/Rakefile +7 -1
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/rocketio.rb +131 -3
- data/lib/rocketio/application.rb +31 -0
- data/lib/rocketio/controller.rb +288 -0
- data/lib/rocketio/controller/authentication.rb +141 -0
- data/lib/rocketio/controller/authorization.rb +53 -0
- data/lib/rocketio/controller/cookies.rb +59 -0
- data/lib/rocketio/controller/error_handlers.rb +89 -0
- data/lib/rocketio/controller/filters.rb +119 -0
- data/lib/rocketio/controller/flash.rb +21 -0
- data/lib/rocketio/controller/helpers.rb +438 -0
- data/lib/rocketio/controller/middleware.rb +32 -0
- data/lib/rocketio/controller/render.rb +148 -0
- data/lib/rocketio/controller/render/engine.rb +76 -0
- data/lib/rocketio/controller/render/layout.rb +27 -0
- data/lib/rocketio/controller/render/layouts.rb +85 -0
- data/lib/rocketio/controller/render/templates.rb +83 -0
- data/lib/rocketio/controller/request.rb +115 -0
- data/lib/rocketio/controller/response.rb +84 -0
- data/lib/rocketio/controller/sessions.rb +64 -0
- data/lib/rocketio/controller/token_auth.rb +118 -0
- data/lib/rocketio/controller/websocket.rb +21 -0
- data/lib/rocketio/error_templates/404.html +3 -0
- data/lib/rocketio/error_templates/409.html +7 -0
- data/lib/rocketio/error_templates/500.html +3 -0
- data/lib/rocketio/error_templates/501.html +6 -0
- data/lib/rocketio/error_templates/layout.html +1 -0
- data/lib/rocketio/exceptions.rb +4 -0
- data/lib/rocketio/router.rb +65 -0
- data/lib/rocketio/util.rb +122 -0
- data/lib/rocketio/version.rb +2 -2
- data/rocketio.gemspec +21 -17
- data/test/aliases_test.rb +54 -0
- data/test/authentication_test.rb +307 -0
- data/test/authorization_test.rb +91 -0
- data/test/cache_control_test.rb +268 -0
- data/test/content_type_test.rb +124 -0
- data/test/cookies_test.rb +49 -0
- data/test/error_handlers_test.rb +125 -0
- data/test/etag_test.rb +445 -0
- data/test/filters_test.rb +177 -0
- data/test/halt_test.rb +73 -0
- data/test/helpers_test.rb +171 -0
- data/test/middleware_test.rb +57 -0
- data/test/redirect_test.rb +135 -0
- data/test/render/engine_test.rb +71 -0
- data/test/render/get.erb +1 -0
- data/test/render/items.erb +1 -0
- data/test/render/layout.erb +1 -0
- data/test/render/layout_test.rb +104 -0
- data/test/render/layouts/master.erb +1 -0
- data/test/render/layouts_test.rb +145 -0
- data/test/render/master.erb +1 -0
- data/test/render/post.erb +1 -0
- data/test/render/put.erb +1 -0
- data/test/render/render_test.rb +101 -0
- data/test/render/setup.rb +14 -0
- data/test/render/templates/a/get.erb +1 -0
- data/test/render/templates/master.erb +1 -0
- data/test/render/templates_test.rb +146 -0
- data/test/request_test.rb +105 -0
- data/test/response_test.rb +119 -0
- data/test/routes_test.rb +70 -0
- data/test/sendfile_test.rb +209 -0
- data/test/sessions_test.rb +176 -0
- data/test/setup.rb +59 -0
- metadata +144 -9
- data/LICENSE.txt +0 -22
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'setup'
|
2
|
+
|
3
|
+
spec :Filters do
|
4
|
+
|
5
|
+
context :composition do
|
6
|
+
it 'inherits filters from superclass' do
|
7
|
+
before, around, after = [], [], []
|
8
|
+
a = mock_controller {
|
9
|
+
before(:get) {before << :a}
|
10
|
+
around(:get) {|a| around << :a}
|
11
|
+
after(:get) {after << :a}
|
12
|
+
def get; end
|
13
|
+
}
|
14
|
+
b = mock_controller(a)
|
15
|
+
app(b)
|
16
|
+
get
|
17
|
+
assert([before, around, after]).all? {|a| a.include?(:a)}
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'inherits filters explicitly' do
|
21
|
+
before, around, after = [], [], []
|
22
|
+
a = mock_controller {
|
23
|
+
before(:get) {before << :x}
|
24
|
+
around(:get) {|a| around << :x}
|
25
|
+
after(:get) {after << :x}
|
26
|
+
def get; end
|
27
|
+
}
|
28
|
+
b = mock_controller {
|
29
|
+
inherit :before, from: a
|
30
|
+
inherit :around, from: a
|
31
|
+
inherit :after, from: a
|
32
|
+
}
|
33
|
+
app(b)
|
34
|
+
get
|
35
|
+
assert([before, around, after]).all? {|a| a.include?(:x)}
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'explicitly inherited filters overrides filters inherited from superclass' do
|
39
|
+
before, around, after = [], [], []
|
40
|
+
a = mock_controller {
|
41
|
+
before(:get) {before << :a}
|
42
|
+
around(:get) {|a| around << :a}
|
43
|
+
after(:get) {after << :a}
|
44
|
+
def get; end
|
45
|
+
}
|
46
|
+
b = mock_controller {
|
47
|
+
before(:get) {before << :b}
|
48
|
+
around(:get) {|a| around << :b}
|
49
|
+
after(:get) {after << :b}
|
50
|
+
}
|
51
|
+
c = mock_controller(a) {
|
52
|
+
inherit :before, from: b
|
53
|
+
inherit :around, from: b
|
54
|
+
inherit :after, from: b
|
55
|
+
}
|
56
|
+
app(c)
|
57
|
+
get
|
58
|
+
assert([before, around, after]).none? {|a| a.include?(:a)}
|
59
|
+
assert([before, around, after]).all? {|a| a.include?(:b)}
|
60
|
+
end
|
61
|
+
|
62
|
+
test 'explicitly inherited filters complements filters inherited from superclass' do
|
63
|
+
before_get, around_get, after_get = [], [], []
|
64
|
+
before_post, around_post, after_post = [], [], []
|
65
|
+
a = mock_controller {
|
66
|
+
before(:get) {before_get << :a}
|
67
|
+
around(:get) {|a| around_get << :a}
|
68
|
+
after(:get) {after_get << :a}
|
69
|
+
}
|
70
|
+
b = mock_controller {
|
71
|
+
before(:post) {before_post << :b}
|
72
|
+
around(:post) {|a| around_post << :b}
|
73
|
+
after(:post) {after_post << :b}
|
74
|
+
}
|
75
|
+
c = mock_controller(a) {
|
76
|
+
inherit :before, from: b
|
77
|
+
inherit :around, from: b
|
78
|
+
inherit :after, from: b
|
79
|
+
}
|
80
|
+
app(c)
|
81
|
+
get
|
82
|
+
assert([before_get, around_get, after_get]).all? {|a| a.include?(:a)}
|
83
|
+
post
|
84
|
+
assert([before_post, around_post, after_post]).all? {|a| a.include?(:b)}
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'defined filters overrides filters inherited from superclass' do
|
88
|
+
before, around, after = [], [], []
|
89
|
+
a = mock_controller {
|
90
|
+
before(:get) {before << :a}
|
91
|
+
around(:get) {|a| around << :a}
|
92
|
+
after(:get) {after << :a}
|
93
|
+
}
|
94
|
+
b = mock_controller(a) {
|
95
|
+
before(:get) {before << :b}
|
96
|
+
after(:get) {after << :b}
|
97
|
+
}
|
98
|
+
app(b)
|
99
|
+
get
|
100
|
+
assert([before, after]).all? {|a| a == [:b]}
|
101
|
+
assert(around) == [:a]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'defines filters for all requested methods if called without arguments' do
|
106
|
+
before, around, after = [], [], []
|
107
|
+
app mock_controller {
|
108
|
+
before() {before << requested_method}
|
109
|
+
around() {|a| around << requested_method}
|
110
|
+
after() {after << requested_method}
|
111
|
+
}
|
112
|
+
filters = [before, around, after]
|
113
|
+
|
114
|
+
get
|
115
|
+
assert(filters).all? {|a| a.include?(:get)}
|
116
|
+
|
117
|
+
post
|
118
|
+
assert(filters).all? {|a| a.include?(:post)}
|
119
|
+
|
120
|
+
put
|
121
|
+
assert(filters).all? {|a| a.include?(:put)}
|
122
|
+
|
123
|
+
head
|
124
|
+
assert(filters).all? {|a| a.include?(:head)}
|
125
|
+
|
126
|
+
delete
|
127
|
+
assert(filters).all? {|a| a.include?(:delete)}
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'defines filters only for given requested method(s)' do
|
131
|
+
before, around, after = [], [], []
|
132
|
+
app mock_controller {
|
133
|
+
before(:get) {before << requested_method}
|
134
|
+
around(:put, :post) {|a| around << requested_method}
|
135
|
+
after(:delete) {after << requested_method}
|
136
|
+
def delete; end
|
137
|
+
}
|
138
|
+
get
|
139
|
+
assert(before).include?(:get)
|
140
|
+
assert([around, after]).none? {|a| a.include?(:get)}
|
141
|
+
|
142
|
+
post
|
143
|
+
assert(around).include?(:post)
|
144
|
+
assert([before, after]).none? {|a| a.include?(:post)}
|
145
|
+
|
146
|
+
put
|
147
|
+
assert(around).include?(:put)
|
148
|
+
assert([before, after]).none? {|a| a.include?(:put)}
|
149
|
+
|
150
|
+
delete
|
151
|
+
assert(after).include?(:delete)
|
152
|
+
assert([before, around]).none? {|a| a.include?(:delete)}
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'creates a void filter if called without a block' do
|
156
|
+
ctrl = mock_controller {
|
157
|
+
before(:get) {raise 'this should be overridden'}
|
158
|
+
before(:get)
|
159
|
+
def get; end
|
160
|
+
}.initialize_controller
|
161
|
+
app(ctrl)
|
162
|
+
expect(ctrl).to_receive(:__before_get__)
|
163
|
+
get
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'it calls wildcard filters before specialized ones' do
|
167
|
+
buffer = []
|
168
|
+
app mock_controller {
|
169
|
+
# specialized filter, called only on GET requests
|
170
|
+
before(:get) {buffer << requested_method}
|
171
|
+
# wildcard filter, called on any requests
|
172
|
+
before {buffer << :*}
|
173
|
+
}
|
174
|
+
get
|
175
|
+
assert(buffer) == [:*, :get]
|
176
|
+
end
|
177
|
+
end
|
data/test/halt_test.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'setup'
|
2
|
+
|
3
|
+
spec :HaltTest do
|
4
|
+
def halt_app *args, &block
|
5
|
+
app mock_controller {
|
6
|
+
define_method(:get) {
|
7
|
+
instance_exec(&block) if block
|
8
|
+
halt(*args)
|
9
|
+
}
|
10
|
+
}
|
11
|
+
get
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is halting using current response if no args given' do
|
15
|
+
halt_app {response.status = 222}
|
16
|
+
assert(last_response.status) == 222
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'is setting status if a Integer arg given' do
|
20
|
+
halt_app 222
|
21
|
+
assert(last_response.status) == 222
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is updating headers if a Hash arg given' do
|
25
|
+
halt_app 'X' => 'Y'
|
26
|
+
assert(last_response['X']) == 'Y'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is sets body if a no Array no Rack::Response no Hash no Integer arg given' do
|
30
|
+
halt_app 'body'
|
31
|
+
assert(last_response.body) == 'body'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'accepts status and headers' do
|
35
|
+
halt_app 222, 'X' => 'Y'
|
36
|
+
assert(last_response.status) == 222
|
37
|
+
assert(last_response['X']) == 'Y'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'accepts status, headers and body as separate arguments' do
|
41
|
+
halt_app 222, 'body', 'X' => 'Y'
|
42
|
+
assert(last_response.status) == 222
|
43
|
+
assert(last_response['X']) == 'Y'
|
44
|
+
assert(last_response.body) == 'body'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'updates current response if an array given' do
|
48
|
+
halt_app [222, {'X' => 'Y'}, 'body']
|
49
|
+
assert(last_response.status) == 222
|
50
|
+
assert(last_response['X']) == 'Y'
|
51
|
+
assert(last_response.body) == 'body'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'ignores other arguments if an array given' do
|
55
|
+
halt_app [222, {'X' => 'Y'}, 'body'], 400, {'X' => 'Z'}, 'altbody'
|
56
|
+
assert(last_response.status) == 222
|
57
|
+
assert(last_response['X']) == 'Y'
|
58
|
+
assert(last_response.body) == 'body'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns a fatal error unless given array\'s second element is a Hash' do
|
62
|
+
halt_app [200, 'wrong headers', 'boby']
|
63
|
+
assert(last_response.status) == 500
|
64
|
+
assert(last_response.body) =~ /no implicit conversion of String into Hash/
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'halts right away ignoring other arguments if a Rack::Response passed as first argument' do
|
68
|
+
halt_app Rack::Response.new('body', 222, {'X' => 'Y'}), 400, {'X' => 'Z'}, 'altbody'
|
69
|
+
assert(last_response.status) == 222
|
70
|
+
assert(last_response['X']) == 'Y'
|
71
|
+
assert(last_response.body) == 'body'
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'setup'
|
2
|
+
|
3
|
+
spec :HelpersTest do
|
4
|
+
|
5
|
+
def status_app(code, &block)
|
6
|
+
code += 2 if [204, 205, 304].include? code
|
7
|
+
block ||= proc { }
|
8
|
+
app mock_controller {
|
9
|
+
define_method :get do
|
10
|
+
response.status = code
|
11
|
+
instance_eval(&block).inspect
|
12
|
+
end
|
13
|
+
}
|
14
|
+
get
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'status' do
|
18
|
+
it 'sets the response status code' do
|
19
|
+
status_app 207
|
20
|
+
assert(last_response.status) == 207
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'not_found?' do
|
25
|
+
it 'is true for status == 404' do
|
26
|
+
status_app(404) { not_found? }
|
27
|
+
assert(last_response.body) == 'true'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is false for status gt 404' do
|
31
|
+
status_app(405) { not_found? }
|
32
|
+
assert(last_response.body) == 'false'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'is false for status lt 404' do
|
36
|
+
status_app(403) { not_found? }
|
37
|
+
assert(last_response.body) == 'false'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'informational?' do
|
42
|
+
it 'is true for 1xx status' do
|
43
|
+
status_app(100 + rand(100)) { informational? }
|
44
|
+
assert(last_response.body) == 'true'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'is false for status > 199' do
|
48
|
+
status_app(200 + rand(400)) { informational? }
|
49
|
+
assert(last_response.body) == 'false'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'success?' do
|
54
|
+
it 'is true for 2xx status' do
|
55
|
+
status_app(200 + rand(100)) { success? }
|
56
|
+
assert(last_response.body) == 'true'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'is false for status < 200' do
|
60
|
+
status_app(100 + rand(100)) { success? }
|
61
|
+
assert(last_response.body) == 'false'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'is false for status > 299' do
|
65
|
+
status_app(300 + rand(300)) { success? }
|
66
|
+
assert(last_response.body) == 'false'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'redirect?' do
|
71
|
+
it 'is true for 3xx status' do
|
72
|
+
status_app(300 + rand(100)) { redirect? }
|
73
|
+
assert(last_response.body) == 'true'
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'is false for status < 300' do
|
77
|
+
status_app(200 + rand(100)) { redirect? }
|
78
|
+
assert(last_response.body) == 'false'
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'is false for status > 399' do
|
82
|
+
status_app(400 + rand(200)) { redirect? }
|
83
|
+
assert(last_response.body) == 'false'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'client_error?' do
|
88
|
+
it 'is true for 4xx status' do
|
89
|
+
status_app(400 + rand(100)) { client_error? }
|
90
|
+
assert(last_response.body) == 'true'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'is false for status < 400' do
|
94
|
+
status_app(200 + rand(200)) { client_error? }
|
95
|
+
assert(last_response.body) == 'false'
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'is false for status > 499' do
|
99
|
+
status_app(500 + rand(100)) { client_error? }
|
100
|
+
assert(last_response.body) == 'false'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'server_error?' do
|
105
|
+
it 'is true for 5xx status' do
|
106
|
+
status_app(500 + rand(100)) { server_error? }
|
107
|
+
assert(last_response.body) == 'true'
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'is false for status < 500' do
|
111
|
+
status_app(200 + rand(300)) { server_error? }
|
112
|
+
assert(last_response.body) == 'false'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'body' do
|
117
|
+
it 'takes a block for deferred body generation' do
|
118
|
+
app mock_controller {
|
119
|
+
define_method(:get) { response.body = -> { 'Hello World' } }
|
120
|
+
}
|
121
|
+
|
122
|
+
get
|
123
|
+
assert(last_response.body) == 'Hello World'
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'takes a String, Array, or other object responding to #each' do
|
127
|
+
app mock_controller {
|
128
|
+
define_method(:get) { response.body = 'Hello World' }
|
129
|
+
}
|
130
|
+
|
131
|
+
get
|
132
|
+
assert(last_response.body) == 'Hello World'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'headers' do
|
137
|
+
it 'sets headers on the response object when given a Hash' do
|
138
|
+
app mock_controller {
|
139
|
+
define_method(:get) {headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'}
|
140
|
+
}
|
141
|
+
|
142
|
+
get
|
143
|
+
assert(last_response).ok?
|
144
|
+
assert(last_response['X-Foo']) == 'bar'
|
145
|
+
assert(last_response['X-Baz']) == 'bling'
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns the response headers hash when no hash provided' do
|
149
|
+
app mock_controller {
|
150
|
+
define_method(:get) {headers['X-Foo'] = 'bar'}
|
151
|
+
}
|
152
|
+
|
153
|
+
get
|
154
|
+
assert(last_response).ok?
|
155
|
+
assert(last_response['X-Foo']) == 'bar'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'back' do
|
160
|
+
it "makes redirecting back pretty" do
|
161
|
+
app mock_controller('/foo') {
|
162
|
+
def get; redirect back end
|
163
|
+
}
|
164
|
+
|
165
|
+
env['HTTP_REFERER'] = 'http://github.com'
|
166
|
+
get '/foo'
|
167
|
+
assert(last_response).redirect?
|
168
|
+
assert(last_response.location) == "http://github.com"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'setup'
|
2
|
+
|
3
|
+
spec :Middleware do
|
4
|
+
|
5
|
+
buff = []
|
6
|
+
ware = Class.new {
|
7
|
+
def initialize(*); yield end
|
8
|
+
def call(*); [200, {}, []] end
|
9
|
+
}
|
10
|
+
before { buff.clear }
|
11
|
+
|
12
|
+
it 'inherits middleware from superclass' do
|
13
|
+
a = mock_controller {
|
14
|
+
use(ware) {buff << :x}
|
15
|
+
use(ware) {buff << :y}
|
16
|
+
}
|
17
|
+
b = mock_controller(a) {
|
18
|
+
def get; end
|
19
|
+
}
|
20
|
+
app mock_app(b)
|
21
|
+
get
|
22
|
+
assert(buff) == [:y, :x]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'complements middleware inherited from superclass' do
|
26
|
+
a = mock_controller {
|
27
|
+
use(ware) {buff << 1}
|
28
|
+
use(ware) {buff << 2}
|
29
|
+
}
|
30
|
+
b = mock_controller {
|
31
|
+
use(ware) { buff << 3 }
|
32
|
+
inherit :middleware, from: a
|
33
|
+
def get; end
|
34
|
+
}
|
35
|
+
app mock_app(b)
|
36
|
+
get
|
37
|
+
assert(buff) == [3, 2, 1]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'uses `inherit` to complement middleware inherited from superclass' do
|
41
|
+
a = mock_controller {
|
42
|
+
use(ware) {buff << :x}
|
43
|
+
use(ware) {buff << :y}
|
44
|
+
}
|
45
|
+
b = mock_controller(a) {
|
46
|
+
use(ware) {buff << :z}
|
47
|
+
def get; end
|
48
|
+
}
|
49
|
+
c = mock_controller(a) {
|
50
|
+
inherit :middleware, from: b
|
51
|
+
def get; end
|
52
|
+
}
|
53
|
+
app mock_app(c)
|
54
|
+
get
|
55
|
+
assert(buff) == [:y, :x, :z]
|
56
|
+
end
|
57
|
+
end
|