syro 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +84 -6
  3. data/lib/syro.rb +60 -3
  4. data/syro.gemspec +1 -1
  5. data/test/all.rb +46 -0
  6. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88701e942289c077ba534c8779ee97c650d23973
4
- data.tar.gz: 65731a7bc5389784eeaadfb8fa55d938e30d41ca
3
+ metadata.gz: 585d2fe3559bfaa4cc09f2a6b25efac445ca739b
4
+ data.tar.gz: 99a97c194e80a465474f2439a7f80e938f6e69c8
5
5
  SHA512:
6
- metadata.gz: f83855e744ad2f3efe4508d6b0a9221262664a2e2ec5d62d75735157a5323e387529dd0e60b52605002f2d2690f6af46a9dce875c13730f3ad60373cf2ebedf3
7
- data.tar.gz: 31b066cd541d148bfe8ae8c2919f1ba27428de6cba381ab9b0157b768c688dbe9341b60d9f19569e759f1ab7199210ac6b3e45a52fd7d227af767886832bbaec
6
+ metadata.gz: 23adfa66e18f592c65688248b8f9c4f625c988c8a6392e84ea578cc2263396ef5170b1cde6a27132aa43b3139679f1e523ddfd38d07cf4ddb7fa09fd0f3a7804
7
+ data.tar.gz: e1ae691f6c4d9fee2aaaec0c814519bc0bb4cd6a765dea46b63e978564426bd9763b946e8e203e2ad8b0f64f55a766c2ad4be667a171180d85bacb08db9e6c3d
data/README.md CHANGED
@@ -48,10 +48,10 @@ end
48
48
 
49
49
  The block is evaluated in a sandbox where the following methods are
50
50
  available: `env`, `req`, `res`, `path`, `inbox`, `call`, `run`,
51
- `halt`, `consume`, `capture`, `root?` `match`, `default`, `on`,
52
- `root`,`get`, `put`, `head`, `post`, `patch`, `delete` and `options`.
53
- Three other methods are available for customizations: `default_headers`,
54
- `request_class` and `response_class`.
51
+ `halt`, `handle`, `finish!`, `consume`, `capture`, `root?` `match`,
52
+ `default`, `on`, `root`,`get`, `put`, `head`, `post`, `patch`,
53
+ `delete` and `options`. Three other methods are available for
54
+ customizations: `default_headers`, `request_class` and `response_class`.
55
55
 
56
56
  As a recommendation, user created variables should be instance
57
57
  variables. That way they won't mix with the API methods defined in
@@ -83,6 +83,12 @@ argument.
83
83
  `halt`: Terminates the request. It receives an array with the
84
84
  response as per Rack's specification.
85
85
 
86
+ `handle`: Installs a handler for a given status code. It receives
87
+ a status code and a block that will be executed from `finish!`.
88
+
89
+ `finish!`: Terminates the request by executing any installed handlers
90
+ and then halting with the current value of `res.finish`.
91
+
86
92
  `consume`: Match and consume a path segment.
87
93
 
88
94
  `capture`: Match and capture a path segment. The value is stored in
@@ -254,6 +260,78 @@ post do
254
260
  end
255
261
  ```
256
262
 
263
+ Handlers
264
+ --------
265
+
266
+ Status code handlers can be installed with the `handle` command,
267
+ which receives a status code and a block to be executed just before
268
+ finishing the request.
269
+
270
+ By default, if there are no matches in a Syro application the
271
+ response is a `404` with an empty body. If we decide to handle the
272
+ `404` requests and return a string, we can do as follows:
273
+
274
+ ```ruby
275
+ App = Syro.new do
276
+ handle 404 do
277
+ res.text "Not found!"
278
+ end
279
+
280
+ get do
281
+ res.text "Found!
282
+ end
283
+ end
284
+ ```
285
+
286
+ In this example, a `GET` request to `"/"` will return a status `200`
287
+ with the body `"Found!"`. Any other request will return a `404`
288
+ with the body `"Not found!"`.
289
+
290
+ If a new handler is installed for the same status code, the previous
291
+ handler is overwritten. A handler is valid in the current scope and
292
+ in all its nested branches. Blocks that end before the handler is
293
+ installed are not affected.
294
+
295
+ This is a contrived example that shows some edge cases when using handlers:
296
+
297
+ ```ruby
298
+ App = Syro.new do
299
+ on "foo" do
300
+ # 404, empty body
301
+ end
302
+
303
+ handle 404 do
304
+ res.text "Not found!"
305
+ end
306
+
307
+ on "bar" do
308
+ # 404, body is "Not found!"
309
+ end
310
+
311
+ on "baz" do
312
+ # 404, body is "Couldn't find baz"
313
+
314
+ handle 404 do
315
+ res.text "Couldn't find baz"
316
+ end
317
+ end
318
+ end
319
+ ```
320
+
321
+ A request to `"/foo"` will return a `404`, because the request
322
+ method was not matched. But as the `on "foo"` block ends before the
323
+ handler is installed, the result will be a blank screen. On the
324
+ other hand, a request to `"/bar"` will return a `404` with the plain
325
+ text `"Not found!"`.
326
+
327
+ Finally, a request to `"/baz"` will return a `404` with the plain text
328
+ `"Couldn't find baz"`, because by the time the `on "baz"` block ends
329
+ a new handler is installed, and thus the previous one is overwritten.
330
+
331
+ Any status code can be handled this way, even status `200`. In that
332
+ case the handler will behave as a filter to be run after each
333
+ successful request.
334
+
257
335
  Content type
258
336
  ------------
259
337
 
@@ -317,11 +395,11 @@ just use `Rack::Builder`:
317
395
  App = Rack::Builder.new do
318
396
  use Rack::Session::Cookie, secret: "..."
319
397
 
320
- run Syro.new do
398
+ run Syro.new {
321
399
  get do
322
400
  res.write("Hello, world")
323
401
  end
324
- end
402
+ }
325
403
  end
326
404
  ```
327
405
 
@@ -269,8 +269,7 @@ class Syro
269
269
 
270
270
  catch(:halt) do
271
271
  instance_eval(&@syro_code)
272
-
273
- @syro_res.finish
272
+ finish!
274
273
  end
275
274
  end
276
275
 
@@ -297,6 +296,64 @@ class Syro
297
296
  throw(:halt, response)
298
297
  end
299
298
 
299
+ # Install a handler for a given status code. Once a handler is
300
+ # installed, it will be called by Syro before halting the
301
+ # request.
302
+ #
303
+ # handle 404 do
304
+ # res.text "Not found!"
305
+ # end
306
+ #
307
+ # If a new handler is installed for the same status code, the
308
+ # previous handler is overwritten. A handler is valid in the
309
+ # current scope and in all its nested branches. Blocks that end
310
+ # before the handler is installed are not affected.
311
+ #
312
+ # For example:
313
+ #
314
+ # on "foo" do
315
+ # # Not found
316
+ # end
317
+ #
318
+ # handle 404 do
319
+ # res.text "Not found!"
320
+ # end
321
+ #
322
+ # on "bar" do
323
+ # # Not found
324
+ # end
325
+ #
326
+ # on "baz" do
327
+ # # Not found
328
+ #
329
+ # handle 404 do
330
+ # res.text "Couldn't find baz"
331
+ # end
332
+ # end
333
+ #
334
+ # A request to "/foo" will return a 404, because the request
335
+ # method was not matched. But as the `on "foo"` block ends
336
+ # before the handler is installed, the result will be a blank
337
+ # screen. On the other hand, a request to "/bar" will return a
338
+ # 404 with the plain text "Not found!".
339
+ #
340
+ # Finally, a request to "/baz" will return a 404 with the plain text
341
+ # "Couldn't find baz", because by the time the `on "baz"` block ends
342
+ # a new handler is installed, and thus the previous one is overwritten.
343
+ #
344
+ # Any status code can be handled this way, even status `200`.
345
+ # In that case the handler will behave as a filter to be run
346
+ # after each successful request.
347
+ #
348
+ def handle(status, &block)
349
+ inbox[status] = block
350
+ end
351
+
352
+ def finish!
353
+ inbox[res.status]&.call
354
+ halt(res.finish)
355
+ end
356
+
300
357
  def consume(arg)
301
358
  @syro_path.consume(arg)
302
359
  end
@@ -319,7 +376,7 @@ class Syro
319
376
  end
320
377
 
321
378
  def default
322
- yield; halt(res.finish)
379
+ yield; finish!
323
380
  end
324
381
 
325
382
  def on(arg)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "syro"
3
- s.version = "3.0.1"
3
+ s.version = "3.1.0"
4
4
  s.summary = "Simple router"
5
5
  s.description = "Simple router for web applications"
6
6
  s.authors = ["Michel Martens"]
@@ -79,6 +79,26 @@ comments = Syro.new do
79
79
  end
80
80
  end
81
81
 
82
+ handlers = Syro.new do
83
+ on "without_handler" do
84
+ # Not found
85
+ end
86
+
87
+ handle(404) do
88
+ res.text "Not found!"
89
+ end
90
+
91
+ on "with_handler" do
92
+ # Not found
93
+ end
94
+
95
+ on "with_local_handler" do
96
+ handle(404) do
97
+ res.text "Also not found!"
98
+ end
99
+ end
100
+ end
101
+
82
102
  app = Syro.new do
83
103
  get do
84
104
  res.write "GET /"
@@ -194,6 +214,10 @@ app = Syro.new do
194
214
  run(json)
195
215
  end
196
216
 
217
+ on "handlers" do
218
+ run(handlers)
219
+ end
220
+
197
221
  on "private" do
198
222
  res.status = 401
199
223
  res.write("Unauthorized")
@@ -369,3 +393,25 @@ test "content type" do |f|
369
393
  f.get("/json")
370
394
  assert_equal "application/json", f.last_response.headers["Content-Type"]
371
395
  end
396
+
397
+ test "status code handling" do |f|
398
+ f.get("/handlers")
399
+ assert_equal 404, f.last_response.status
400
+ assert_equal "text/plain", f.last_response.headers["Content-Type"]
401
+ assert_equal "Not found!", f.last_response.body
402
+
403
+ f.get("/handlers/without_handler")
404
+ assert_equal 404, f.last_response.status
405
+ assert_equal nil, f.last_response.headers["Content-Type"]
406
+ assert_equal "", f.last_response.body
407
+
408
+ f.get("/handlers/with_handler")
409
+ assert_equal 404, f.last_response.status
410
+ assert_equal "text/plain", f.last_response.headers["Content-Type"]
411
+ assert_equal "Not found!", f.last_response.body
412
+
413
+ f.get("/handlers/with_local_handler")
414
+ assert_equal 404, f.last_response.status
415
+ assert_equal "text/plain", f.last_response.headers["Content-Type"]
416
+ assert_equal "Also not found!", f.last_response.body
417
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syro
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-27 00:00:00.000000000 Z
11
+ date: 2018-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: seg
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  version: '0'
104
104
  requirements: []
105
105
  rubyforge_project:
106
- rubygems_version: 2.4.5.1
106
+ rubygems_version: 2.6.11
107
107
  signing_key:
108
108
  specification_version: 4
109
109
  summary: Simple router