syro 3.0.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gems +3 -3
- data/README.md +85 -7
- data/lib/syro.rb +79 -11
- data/syro.gemspec +2 -2
- data/test/all.rb +89 -0
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 91ee832b6435348393681438b2e8a167c1d5c56a3ebaaf494b4f3840b716adde
|
4
|
+
data.tar.gz: 3ba242a11056f3fd32da0b2198b9c10fa35e5c4f4db7217ec044fadf047f01b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4b4c73c4b4d731914a119a81b5bfc1154872f47343744532a0334525e0a2f978878015d1df11324376551c6617818193c0b6d462b9fbd54c3cd535b0a5ea78e
|
7
|
+
data.tar.gz: '0825e4cd946e7fba9d84907cce3442b53c158baaf2c0678864df1f0648b3834feb1976c1b62facdeb82e6fb172863958b432ba5ab7d067e26ce52bb3133ffea9'
|
data/.gems
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
cutest -v 1.2.3
|
2
|
-
|
3
|
-
|
4
|
-
rack-test -v
|
2
|
+
seg -v 1.2.0
|
3
|
+
rack -v 2.2.3
|
4
|
+
rack-test -v 1.1.0
|
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`,
|
52
|
-
`root`,`get`, `put`, `head`, `post`, `patch`,
|
53
|
-
Three other methods are available for
|
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
|
@@ -93,7 +99,7 @@ the inbox.
|
|
93
99
|
`match`: Receives a String, a Symbol or a boolean, and returns true
|
94
100
|
if it matches the request.
|
95
101
|
|
96
|
-
`default`: Receives a block that will be executed
|
102
|
+
`default`: Receives a block that will be executed unconditionally.
|
97
103
|
|
98
104
|
`on`: Receives a value to be matched, and a block that will be
|
99
105
|
executed only if the request is matched.
|
@@ -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
|
398
|
+
run Syro.new {
|
321
399
|
get do
|
322
400
|
res.write("Hello, world")
|
323
401
|
end
|
324
|
-
|
402
|
+
}
|
325
403
|
end
|
326
404
|
```
|
327
405
|
|
data/lib/syro.rb
CHANGED
@@ -209,11 +209,23 @@ class Syro
|
|
209
209
|
end
|
210
210
|
|
211
211
|
class Deck
|
212
|
-
|
213
|
-
|
214
|
-
|
212
|
+
|
213
|
+
# Attaches the supplied block to a subclass of Deck as #dispatch!
|
214
|
+
# Returns the subclassed Deck.
|
215
|
+
def self.implement(&code)
|
216
|
+
Class.new(self) do
|
217
|
+
define_method(:dispatch!, code)
|
218
|
+
private :dispatch!
|
219
|
+
|
220
|
+
# Instead of calling inspect on this anonymous class,
|
221
|
+
# defer to the superclass which is likely Syro::Deck.
|
222
|
+
define_method(:inspect) do
|
223
|
+
self.class.superclass.inspect
|
224
|
+
end
|
215
225
|
end
|
226
|
+
end
|
216
227
|
|
228
|
+
module API
|
217
229
|
def env
|
218
230
|
@syro_env
|
219
231
|
end
|
@@ -268,9 +280,8 @@ class Syro
|
|
268
280
|
@syro_inbox = inbox
|
269
281
|
|
270
282
|
catch(:halt) do
|
271
|
-
|
272
|
-
|
273
|
-
@syro_res.finish
|
283
|
+
dispatch!
|
284
|
+
finish!
|
274
285
|
end
|
275
286
|
end
|
276
287
|
|
@@ -278,7 +289,7 @@ class Syro
|
|
278
289
|
path, script = env[Rack::PATH_INFO], env[Rack::SCRIPT_NAME]
|
279
290
|
|
280
291
|
env[Rack::PATH_INFO] = @syro_path.curr
|
281
|
-
env[Rack::SCRIPT_NAME] = @syro_path.prev
|
292
|
+
env[Rack::SCRIPT_NAME] = script.to_s + @syro_path.prev
|
282
293
|
env[Syro::INBOX] = inbox
|
283
294
|
|
284
295
|
halt(app.call(env))
|
@@ -297,6 +308,64 @@ class Syro
|
|
297
308
|
throw(:halt, response)
|
298
309
|
end
|
299
310
|
|
311
|
+
# Install a handler for a given status code. Once a handler is
|
312
|
+
# installed, it will be called by Syro before halting the
|
313
|
+
# request.
|
314
|
+
#
|
315
|
+
# handle 404 do
|
316
|
+
# res.text "Not found!"
|
317
|
+
# end
|
318
|
+
#
|
319
|
+
# If a new handler is installed for the same status code, the
|
320
|
+
# previous handler is overwritten. A handler is valid in the
|
321
|
+
# current scope and in all its nested branches. Blocks that end
|
322
|
+
# before the handler is installed are not affected.
|
323
|
+
#
|
324
|
+
# For example:
|
325
|
+
#
|
326
|
+
# on "foo" do
|
327
|
+
# # Not found
|
328
|
+
# end
|
329
|
+
#
|
330
|
+
# handle 404 do
|
331
|
+
# res.text "Not found!"
|
332
|
+
# end
|
333
|
+
#
|
334
|
+
# on "bar" do
|
335
|
+
# # Not found
|
336
|
+
# end
|
337
|
+
#
|
338
|
+
# on "baz" do
|
339
|
+
# # Not found
|
340
|
+
#
|
341
|
+
# handle 404 do
|
342
|
+
# res.text "Couldn't find baz"
|
343
|
+
# end
|
344
|
+
# end
|
345
|
+
#
|
346
|
+
# A request to "/foo" will return a 404, because the request
|
347
|
+
# method was not matched. But as the `on "foo"` block ends
|
348
|
+
# before the handler is installed, the result will be a blank
|
349
|
+
# screen. On the other hand, a request to "/bar" will return a
|
350
|
+
# 404 with the plain text "Not found!".
|
351
|
+
#
|
352
|
+
# Finally, a request to "/baz" will return a 404 with the plain text
|
353
|
+
# "Couldn't find baz", because by the time the `on "baz"` block ends
|
354
|
+
# a new handler is installed, and thus the previous one is overwritten.
|
355
|
+
#
|
356
|
+
# Any status code can be handled this way, even status `200`.
|
357
|
+
# In that case the handler will behave as a filter to be run
|
358
|
+
# after each successful request.
|
359
|
+
#
|
360
|
+
def handle(status, &block)
|
361
|
+
inbox[status] = block
|
362
|
+
end
|
363
|
+
|
364
|
+
def finish!
|
365
|
+
inbox[res.status]&.call
|
366
|
+
halt(res.finish)
|
367
|
+
end
|
368
|
+
|
300
369
|
def consume(arg)
|
301
370
|
@syro_path.consume(arg)
|
302
371
|
end
|
@@ -319,7 +388,7 @@ class Syro
|
|
319
388
|
end
|
320
389
|
|
321
390
|
def default
|
322
|
-
yield;
|
391
|
+
yield; finish!
|
323
392
|
end
|
324
393
|
|
325
394
|
def on(arg)
|
@@ -363,11 +432,10 @@ class Syro
|
|
363
432
|
end
|
364
433
|
|
365
434
|
def initialize(deck = Deck, &code)
|
366
|
-
@deck = deck
|
367
|
-
@code = code
|
435
|
+
@deck = deck.implement(&code)
|
368
436
|
end
|
369
437
|
|
370
438
|
def call(env, inbox = env.fetch(Syro::INBOX, {}))
|
371
|
-
@deck.new
|
439
|
+
@deck.new.call(env, inbox)
|
372
440
|
end
|
373
441
|
end
|
data/syro.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "syro"
|
3
|
-
s.version = "3.
|
3
|
+
s.version = "3.2.1"
|
4
4
|
s.summary = "Simple router"
|
5
5
|
s.description = "Simple router for web applications"
|
6
6
|
s.authors = ["Michel Martens"]
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.files = `git ls-files`.split("\n")
|
12
12
|
|
13
13
|
s.add_dependency "seg"
|
14
|
-
s.add_dependency "rack", "
|
14
|
+
s.add_dependency "rack", ">= 1.6.0"
|
15
15
|
s.add_development_dependency "cutest"
|
16
16
|
s.add_development_dependency "rack-test"
|
17
17
|
end
|
data/test/all.rb
CHANGED
@@ -79,6 +79,48 @@ 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
|
+
|
102
|
+
path_info = Syro.new do
|
103
|
+
on "foo" do
|
104
|
+
get do
|
105
|
+
res.text req.path
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
get do
|
110
|
+
res.text req.path
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
script_name = Syro.new do
|
115
|
+
on "path" do
|
116
|
+
run(path_info)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
exception = Syro.new do
|
121
|
+
get { res.text(this_method_does_not_exist) }
|
122
|
+
end
|
123
|
+
|
82
124
|
app = Syro.new do
|
83
125
|
get do
|
84
126
|
res.write "GET /"
|
@@ -194,6 +236,10 @@ app = Syro.new do
|
|
194
236
|
run(json)
|
195
237
|
end
|
196
238
|
|
239
|
+
on "handlers" do
|
240
|
+
run(handlers)
|
241
|
+
end
|
242
|
+
|
197
243
|
on "private" do
|
198
244
|
res.status = 401
|
199
245
|
res.write("Unauthorized")
|
@@ -214,6 +260,14 @@ app = Syro.new do
|
|
214
260
|
on "json" do
|
215
261
|
res.json "json!"
|
216
262
|
end
|
263
|
+
|
264
|
+
on "script" do
|
265
|
+
run(script_name)
|
266
|
+
end
|
267
|
+
|
268
|
+
on "exception" do
|
269
|
+
run(exception)
|
270
|
+
end
|
217
271
|
end
|
218
272
|
|
219
273
|
setup do
|
@@ -369,3 +423,38 @@ test "content type" do |f|
|
|
369
423
|
f.get("/json")
|
370
424
|
assert_equal "application/json", f.last_response.headers["Content-Type"]
|
371
425
|
end
|
426
|
+
|
427
|
+
test "status code handling" do |f|
|
428
|
+
f.get("/handlers")
|
429
|
+
assert_equal 404, f.last_response.status
|
430
|
+
assert_equal "text/plain", f.last_response.headers["Content-Type"]
|
431
|
+
assert_equal "Not found!", f.last_response.body
|
432
|
+
|
433
|
+
f.get("/handlers/without_handler")
|
434
|
+
assert_equal 404, f.last_response.status
|
435
|
+
assert_equal nil, f.last_response.headers["Content-Type"]
|
436
|
+
assert_equal "", f.last_response.body
|
437
|
+
|
438
|
+
f.get("/handlers/with_handler")
|
439
|
+
assert_equal 404, f.last_response.status
|
440
|
+
assert_equal "text/plain", f.last_response.headers["Content-Type"]
|
441
|
+
assert_equal "Not found!", f.last_response.body
|
442
|
+
|
443
|
+
f.get("/handlers/with_local_handler")
|
444
|
+
assert_equal 404, f.last_response.status
|
445
|
+
assert_equal "text/plain", f.last_response.headers["Content-Type"]
|
446
|
+
assert_equal "Also not found!", f.last_response.body
|
447
|
+
end
|
448
|
+
|
449
|
+
test "script name and path info" do |f|
|
450
|
+
f.get("/script/path")
|
451
|
+
assert_equal 200, f.last_response.status
|
452
|
+
assert_equal "/script/path", f.last_response.body
|
453
|
+
end
|
454
|
+
|
455
|
+
test "deck exceptions reference a named class" do |f|
|
456
|
+
f.get("/exception")
|
457
|
+
rescue NameError => exception
|
458
|
+
ensure
|
459
|
+
assert exception.to_s.include?("Syro::Deck")
|
460
|
+
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.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: seg
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.6.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.6.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: cutest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
requirements: []
|
105
|
-
|
106
|
-
rubygems_version: 2.4.5.1
|
105
|
+
rubygems_version: 3.0.3
|
107
106
|
signing_key:
|
108
107
|
specification_version: 4
|
109
108
|
summary: Simple router
|