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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 809986637c600091f82231a4d8b5abc98d8901f6
4
- data.tar.gz: 4d85c02a50c030f4405fcb7c957e44fd7c27e3d4
3
+ metadata.gz: 5dd4947d9238c95169d7a38db1ff5964db35efad
4
+ data.tar.gz: 65d2a79bfca8c5879721516d31029fd756ebc1c5
5
5
  SHA512:
6
- metadata.gz: a61261e0ff70da449f4f3b15c55ec9261947d8b49b7b6747a4d660f76862268e25d50254977ef5e428215dbfb732ae03885f9c0c4ee07a14f9ac69b405e0a1b0
7
- data.tar.gz: 5558f936798f39acb2a2f56ae98a3ad90fc66fd3a47be8992753f1cf6f5fec24cee5a79833e7a4cad26e2022258aed89084bf54b420c7430479ff37eb876b134
6
+ metadata.gz: 1da99edfa1e946edd6f62764a95ab09e999cc6eccef9d915d0741e6ed8912ed8629d28b58605c7960972c0795c5ab912b2824bb018322c82bd90b1c7fee08be9
7
+ data.tar.gz: 194fda3f3e9bf9f7a7b0ce2156bf8e34d2134ba7013e1366a7a8363e1cbba72c826daed7b8f1c934894e9431c8bcc87ab1d9c2b905a0741151d212d9a6c238b2
data/CHANGELOG.md CHANGED
@@ -1,9 +1,13 @@
1
1
  changelog
2
2
  =========
3
3
 
4
+ ### 0.1.11 13 jun 2014
5
+
6
+ * add halt method and handling
7
+
4
8
  ### 0.1.10 12 jun 2014
5
9
 
6
- * add RequestError
10
+ * add RequestError and handling
7
11
 
8
12
  ### 0.1.9 5 jun 2014
9
13
 
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
- In Sinatra, one can `halt` and optionally pass status codes and a body. While that functionality
163
- is not (yet?) present in Angelo, the ability to `raise` a `RequestError` is. Raising an instance
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
- \* If you want to return a different status code, you can pass it as a second argument to
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[:socket][path] = WebsocketResponder.new &block
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
@@ -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
- @body = case @body
126
- when String
127
- JSON.parse @body if respond_with? :json # for the raises
128
- @body
129
- when Hash
130
- raise 'html response requires String' if respond_with? :html
131
- @body.to_json if respond_with? :json
132
- when NilClass
133
- EMPTY_STRING
134
- end
135
-
136
- status = @redirect.nil? ? :ok : :moved_permanently
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? ? :socket : request.method.downcase.to_sym
22
+ meth = request.websocket? ? :websocket : request.method.downcase.to_sym
23
23
  dispatch! meth, connection, request
24
24
  end
25
25
  # RubyProf.pause
@@ -1,3 +1,3 @@
1
1
  module Angelo
2
- VERSION = '0.1.10'
2
+ VERSION = '0.1.11'
3
3
  end
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, :socket]
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 = ->{
@@ -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.10
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-12 00:00:00.000000000 Z
11
+ date: 2014-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: reel