syro 3.0.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|