angelo 0.1.10 → 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/README.md +41 -8
- data/lib/angelo/base.rb +5 -1
- data/lib/angelo/responder.rb +24 -13
- data/lib/angelo/server.rb +1 -1
- data/lib/angelo/version.rb +1 -1
- data/lib/angelo.rb +3 -1
- data/test/angelo/error_spec.rb +95 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5dd4947d9238c95169d7a38db1ff5964db35efad
|
4
|
+
data.tar.gz: 65d2a79bfca8c5879721516d31029fd756ebc1c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1da99edfa1e946edd6f62764a95ab09e999cc6eccef9d915d0741e6ed8912ed8629d28b58605c7960972c0795c5ab912b2824bb018322c82bd90b1c7fee08be9
|
7
|
+
data.tar.gz: 194fda3f3e9bf9f7a7b0ce2156bf8e34d2134ba7013e1366a7a8363e1cbba72c826daed7b8f1c934894e9431c8bcc87ab1d9c2b905a0741151d212d9a6c238b2
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -29,6 +29,9 @@ route handlers denoted by HTTP verb and path. Unlike Sinatra, the only acceptabl
|
|
29
29
|
route block is the body of the response in full. Chunked response support was recently added to Reel,
|
30
30
|
and look for that support in Angelo soon.
|
31
31
|
|
32
|
+
Angelo also features `before` and `after` blocks, just like Sinatra. The one difference lies in how
|
33
|
+
after blocks are handled. See the Errors section below for more info.
|
34
|
+
|
32
35
|
There is also [Mustermann](#mustermann) support for full-on, Sinatra-like path
|
33
36
|
matching and params.
|
34
37
|
|
@@ -157,18 +160,35 @@ get '/' do
|
|
157
160
|
end
|
158
161
|
```
|
159
162
|
|
160
|
-
### Errors
|
163
|
+
### Errors and Halting
|
164
|
+
|
165
|
+
Angelo gives you two ordained methods of stopping route processing:
|
166
|
+
|
167
|
+
* raise an instance of `RequestError`
|
168
|
+
* `halt` with a status code and message
|
169
|
+
|
170
|
+
The main difference is that `halt` will still run an `after` block, and raising `RequestError`
|
171
|
+
will bypass the `after` block.
|
161
172
|
|
162
|
-
|
163
|
-
|
164
|
-
of this always\* causes a 400 status code response, and the message in the instance is the body
|
165
|
-
of the the response. If the route or class was set to respond with JSON, the body is converted
|
166
|
-
to a JSON object with one key, `error`, that has a value of the message. If the message is a
|
167
|
-
`Hash`, the hash is converted to a JSON object, or to a string for other content types.
|
173
|
+
Any other exceptions or errors raised by your route handler will be handled with a 500 status
|
174
|
+
code and the message will be the body of the response.
|
168
175
|
|
169
|
-
|
176
|
+
#### RequestError
|
177
|
+
|
178
|
+
Raising an instance of `Angelo::RequestError` causes a 400 status code response, and the message
|
179
|
+
in the instance is the body of the the response. If the route or class was set to respond with
|
180
|
+
JSON, the body is converted to a JSON object with one key, `error`, that has a value of the message.
|
181
|
+
If the message is a `Hash`, the hash is converted to a JSON object, or to a string for other content
|
182
|
+
types.
|
183
|
+
|
184
|
+
If you want to return a different status code, you can pass it as a second argument to
|
170
185
|
`RequestError.new`. See example below.
|
171
186
|
|
187
|
+
#### Halting
|
188
|
+
|
189
|
+
You can `halt` from within any route handler, optionally passing status code and a body. The
|
190
|
+
body is handled the same way as raising `RequestError`.
|
191
|
+
|
172
192
|
##### Example
|
173
193
|
|
174
194
|
```ruby
|
@@ -186,6 +206,11 @@ end
|
|
186
206
|
get '/not_found' do
|
187
207
|
raise RequestError.new 'not found', 404
|
188
208
|
end
|
209
|
+
|
210
|
+
get '/halt' do
|
211
|
+
halt 200, "everything's fine"
|
212
|
+
raise RequestError.new "won't get here"
|
213
|
+
end
|
189
214
|
```
|
190
215
|
|
191
216
|
```
|
@@ -220,6 +245,14 @@ Connection: Keep-Alive
|
|
220
245
|
Content-Length: 9
|
221
246
|
|
222
247
|
not found
|
248
|
+
|
249
|
+
$ curl -i http://127.0.0.1:4567/halt
|
250
|
+
HTTP/1.1 200 OK
|
251
|
+
Content-Type: text/html
|
252
|
+
Connection: Keep-Alive
|
253
|
+
Content-Length: 18
|
254
|
+
|
255
|
+
everything's fine
|
223
256
|
```
|
224
257
|
|
225
258
|
### WORK LEFT TO DO
|
data/lib/angelo/base.rb
CHANGED
@@ -86,7 +86,7 @@ module Angelo
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def websocket path, &block
|
89
|
-
routes[:
|
89
|
+
routes[:websocket][path] = WebsocketResponder.new &block
|
90
90
|
end
|
91
91
|
|
92
92
|
def on_pong &block
|
@@ -166,6 +166,10 @@ module Angelo
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
+
def halt status = 400, body = ''
|
170
|
+
throw :halt, HALT_STRUCT.new(status, body)
|
171
|
+
end
|
172
|
+
|
169
173
|
end
|
170
174
|
|
171
175
|
end
|
data/lib/angelo/responder.rb
CHANGED
@@ -47,6 +47,7 @@ module Angelo
|
|
47
47
|
def request= request
|
48
48
|
@params = nil
|
49
49
|
@redirect = nil
|
50
|
+
@body = nil
|
50
51
|
@request = request
|
51
52
|
handle_request
|
52
53
|
end
|
@@ -54,7 +55,7 @@ module Angelo
|
|
54
55
|
def handle_request
|
55
56
|
if @response_handler
|
56
57
|
@base.before if @base.respond_to? :before
|
57
|
-
@body = @response_handler.bind(@base).call || ''
|
58
|
+
@body = catch(:halt) { @response_handler.bind(@base).call || '' }
|
58
59
|
@base.after if @base.respond_to? :after
|
59
60
|
respond
|
60
61
|
else
|
@@ -122,18 +123,28 @@ module Angelo
|
|
122
123
|
end
|
123
124
|
|
124
125
|
def respond
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
126
|
+
status = nil
|
127
|
+
case @body
|
128
|
+
when HALT_STRUCT
|
129
|
+
status = @body.status
|
130
|
+
@body = @body.body
|
131
|
+
if Hash === @body
|
132
|
+
@body = {error: @body} if status != :ok or status < 200 && status >= 300
|
133
|
+
@body = @body.to_json if respond_with? :json
|
134
|
+
end
|
135
|
+
|
136
|
+
when String
|
137
|
+
JSON.parse @body if respond_with? :json # for the raises
|
138
|
+
|
139
|
+
when Hash
|
140
|
+
raise 'html response requires String' if respond_with? :html
|
141
|
+
@body = @body.to_json if respond_with? :json
|
142
|
+
|
143
|
+
when NilClass
|
144
|
+
@body = EMPTY_STRING
|
145
|
+
end
|
146
|
+
|
147
|
+
status ||= @redirect.nil? ? :ok : :moved_permanently
|
137
148
|
headers LOCATION_HEADER_KEY => @redirect if @redirect
|
138
149
|
|
139
150
|
Angelo.log @connection, @request, nil, status, @body.size
|
data/lib/angelo/server.rb
CHANGED
@@ -19,7 +19,7 @@ module Angelo
|
|
19
19
|
def on_connection connection
|
20
20
|
# RubyProf.resume
|
21
21
|
connection.each_request do |request|
|
22
|
-
meth = request.websocket? ? :
|
22
|
+
meth = request.websocket? ? :websocket : request.method.downcase.to_sym
|
23
23
|
dispatch! meth, connection, request
|
24
24
|
end
|
25
25
|
# RubyProf.pause
|
data/lib/angelo/version.rb
CHANGED
data/lib/angelo.rb
CHANGED
@@ -14,7 +14,7 @@ module Angelo
|
|
14
14
|
DELETE = 'DELETE'
|
15
15
|
OPTIONS = 'OPTIONS'
|
16
16
|
|
17
|
-
ROUTABLE = [:get, :post, :put, :delete, :
|
17
|
+
ROUTABLE = [:get, :post, :put, :delete, :websocket]
|
18
18
|
HTTPABLE = [:get, :post, :put, :delete]
|
19
19
|
STATICABLE = [:get, :head]
|
20
20
|
|
@@ -51,6 +51,8 @@ module Angelo
|
|
51
51
|
DASH = '-'
|
52
52
|
EMPTY_STRING = ''
|
53
53
|
|
54
|
+
HALT_STRUCT = Struct.new :status, :body
|
55
|
+
|
54
56
|
def self.log connection, request, socket, status, body_size = '-'
|
55
57
|
|
56
58
|
remote_ip = ->{
|
data/test/angelo/error_spec.rb
CHANGED
@@ -4,8 +4,17 @@ describe Angelo::Base do
|
|
4
4
|
|
5
5
|
describe :handle_error do
|
6
6
|
|
7
|
+
after_ran = false
|
8
|
+
before do
|
9
|
+
after_ran = false
|
10
|
+
end
|
11
|
+
|
7
12
|
define_app do
|
8
13
|
|
14
|
+
after do
|
15
|
+
after_ran = true
|
16
|
+
end
|
17
|
+
|
9
18
|
Angelo::HTTPABLE.each do |m|
|
10
19
|
__send__ m, '/' do
|
11
20
|
|
@@ -105,6 +114,92 @@ describe Angelo::Base do
|
|
105
114
|
|
106
115
|
end
|
107
116
|
|
117
|
+
it 'does not run after blocks when handling a raised error' do
|
118
|
+
Angelo::HTTPABLE.each do |m|
|
119
|
+
__send__ m, '/'
|
120
|
+
last_response.status.must_equal 400
|
121
|
+
last_response.headers['Content-Type'].split(';').must_include Angelo::HTML_TYPE
|
122
|
+
last_response.body.to_s.must_equal 'error message'
|
123
|
+
refute after_ran, 'after block should not have ran'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
describe :halt do
|
130
|
+
|
131
|
+
after_ran = false
|
132
|
+
before do
|
133
|
+
after_ran = false
|
134
|
+
end
|
135
|
+
|
136
|
+
define_app do
|
137
|
+
|
138
|
+
after do
|
139
|
+
after_ran = true
|
140
|
+
end
|
141
|
+
|
142
|
+
Angelo::HTTPABLE.each do |m|
|
143
|
+
__send__ m, '/halt' do
|
144
|
+
halt
|
145
|
+
raise RequestError.new "shouldn't get here"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Angelo::HTTPABLE.each do |m|
|
150
|
+
__send__ m, '/teapot' do
|
151
|
+
halt 418, "i'm a teapot"
|
152
|
+
raise RequestError.new "shouldn't get here"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
Angelo::HTTPABLE.each do |m|
|
157
|
+
__send__ m, '/calm_json' do
|
158
|
+
content_type :json
|
159
|
+
halt 420, {calm: 'enhance'}
|
160
|
+
raise RequestError.new "shouldn't get here"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'halts properly' do
|
167
|
+
Angelo::HTTPABLE.each do |m|
|
168
|
+
__send__ m, '/halt'
|
169
|
+
last_response.status.must_equal 400
|
170
|
+
last_response.headers['Content-Type'].split(';').must_include Angelo::HTML_TYPE
|
171
|
+
last_response.body.to_s.must_equal ''
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'halts with different status code properly' do
|
176
|
+
Angelo::HTTPABLE.each do |m|
|
177
|
+
__send__ m, '/teapot'
|
178
|
+
last_response.status.must_equal 418
|
179
|
+
last_response.headers['Content-Type'].split(';').must_include Angelo::HTML_TYPE
|
180
|
+
last_response.body.to_s.must_equal "i'm a teapot"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'halts with json content type correctly' do
|
185
|
+
Angelo::HTTPABLE.each do |m|
|
186
|
+
__send__ m, '/calm_json'
|
187
|
+
last_response.status.must_equal 420
|
188
|
+
last_response.headers['Content-Type'].split(';').must_include Angelo::JSON_TYPE
|
189
|
+
last_response.body.to_s.must_equal({error: {calm: 'enhance'}}.to_json)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'runs after blocks when halting' do
|
194
|
+
Angelo::HTTPABLE.each do |m|
|
195
|
+
__send__ m, '/halt'
|
196
|
+
last_response.status.must_equal 400
|
197
|
+
last_response.headers['Content-Type'].split(';').must_include Angelo::HTML_TYPE
|
198
|
+
last_response.body.to_s.must_equal ''
|
199
|
+
assert after_ran, 'after block should have ran'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
108
203
|
end
|
109
204
|
|
110
205
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angelo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenichi Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: reel
|