syntropy 0.5 → 0.6
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/TODO.md +25 -36
- data/lib/syntropy/app.rb +17 -6
- data/lib/syntropy/router.rb +34 -2
- data/lib/syntropy/version.rb +1 -1
- data/test/app/_hook.rb +5 -0
- data/test/app/about/_error.rb +6 -0
- data/test/app/about/raise.rb +3 -0
- data/test/test_app.rb +12 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 553553edc3b0c81902bc3a77470bc6e9789fcd757066dcd5b4e790d38f7a28bf
|
4
|
+
data.tar.gz: fdb2cec5f581ba49d5156cce188f31a4811d29767c71833bfcfa37899ee0efc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7340ecb01725dcc15a78a66fef5f87a113c2e9759a2305753241b0c1cf738f45b3fd6fea2dcf7bca55196cc3fc309db2ade3e7bb12292fc5aa3abe63362403f9
|
7
|
+
data.tar.gz: 48427e653e2c99022177e5475ef53b66c57143288f43e4997c40f1ba464728b310c5e0df343e7f03e3ed79f9fa8637e305b6a22296b19fb15068b7228cf0531f
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -1,44 +1,33 @@
|
|
1
|
-
-
|
2
|
-
|
3
|
-
-
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
- middleware is defined in `_hook.rb` modules
|
8
|
-
- interface: ->(req, next)
|
9
|
-
- a special case for handling errors is `_error.rb`
|
10
|
-
- interface: ->(req, err)
|
11
|
-
- dispatching routes
|
12
|
-
- error handling:
|
13
|
-
- on uncaught error, if an `_error.rb` file exists in the same directory
|
14
|
-
or up the file tree
|
15
|
-
- middleware:
|
16
|
-
- a closure is created from the composition of the different hooks
|
17
|
-
defined, from the route's directory and up the file
|
18
|
-
- error handlers and middleware closures are cached as part of the route's
|
19
|
-
entry
|
20
|
-
- on file change for any _hook.rb or _error.rb files, all route entries in
|
21
|
-
the corresponding subtree are invalidated
|
22
|
-
|
23
|
-
|
24
|
-
- Middleware
|
1
|
+
- Some standard middleware:
|
2
|
+
|
3
|
+
- request rewriter
|
4
|
+
- logger
|
5
|
+
- auth
|
6
|
+
- selector + terminator
|
25
7
|
|
26
8
|
```Ruby
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
9
|
+
# For the chainable DSL shown below, we need to create a custom class:
|
10
|
+
class Syntropy::Middleware::Selector
|
11
|
+
def initialize(select_proc, terminator_proc = nil)
|
12
|
+
@select_proc = select_proc
|
13
|
+
@terminator_proc = terminator_proc
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_proc
|
17
|
+
->(req, proc) {
|
18
|
+
@select_proc.(req) ? @terminator_proc.(req) : proc(req)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def terminate(&proc)
|
23
|
+
@terminator_proc = proc
|
24
|
+
end
|
32
25
|
end
|
33
26
|
|
34
|
-
|
35
|
-
|
36
|
-
# Just a normal callable:
|
37
|
-
#
|
38
|
-
export ->(req, err) do
|
39
|
-
render_error_page(req, err.http_status)
|
40
|
-
end
|
27
|
+
def Syntropy
|
28
|
+
```
|
41
29
|
|
30
|
+
```Ruby
|
42
31
|
# a _site.rb file can be used to wrap a whole app
|
43
32
|
# site/_site.rb
|
44
33
|
|
data/lib/syntropy/app.rb
CHANGED
@@ -65,21 +65,32 @@ module Syntropy
|
|
65
65
|
private
|
66
66
|
|
67
67
|
def render_entry(req, entry)
|
68
|
+
kind = entry[:kind]
|
69
|
+
return respond_not_found(req) if kind == :not_found
|
70
|
+
|
71
|
+
entry[:proc] ||= calculate_route_proc(entry)
|
72
|
+
entry[:proc].(req)
|
73
|
+
end
|
74
|
+
|
75
|
+
def calculate_route_proc(entry)
|
76
|
+
render_proc = route_render_proc(entry)
|
77
|
+
@router.calc_route_proc_with_hooks(entry, render_proc)
|
78
|
+
end
|
79
|
+
|
80
|
+
def route_render_proc(entry)
|
68
81
|
case entry[:kind]
|
69
|
-
when :not_found
|
70
|
-
respond_not_found(req, entry)
|
71
82
|
when :static
|
72
|
-
respond_static(req, entry)
|
83
|
+
->(req) { respond_static(req, entry) }
|
73
84
|
when :markdown
|
74
|
-
respond_markdown(req, entry)
|
85
|
+
->(req) { respond_markdown(req, entry) }
|
75
86
|
when :module
|
76
|
-
|
87
|
+
load_module(entry)
|
77
88
|
else
|
78
89
|
raise 'Invalid entry kind'
|
79
90
|
end
|
80
91
|
end
|
81
92
|
|
82
|
-
def respond_not_found(req
|
93
|
+
def respond_not_found(req)
|
83
94
|
headers = { ':status' => Qeweney::Status::NOT_FOUND }
|
84
95
|
case req.method
|
85
96
|
when 'head'
|
data/lib/syntropy/router.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
module Syntropy
|
4
4
|
class Router
|
5
|
-
attr_reader :cache
|
6
|
-
|
7
5
|
def initialize(opts, module_loader = nil)
|
8
6
|
raise 'Invalid location given' if !File.directory?(opts[:location])
|
9
7
|
|
@@ -32,6 +30,10 @@ module Syntropy
|
|
32
30
|
@machine.spin { file_watcher_loop }
|
33
31
|
end
|
34
32
|
|
33
|
+
def calc_route_proc_with_hooks(entry, proc)
|
34
|
+
compose_up_tree_hooks(entry[:fn], proc)
|
35
|
+
end
|
36
|
+
|
35
37
|
private
|
36
38
|
|
37
39
|
HIDDEN_RE = /^_/
|
@@ -204,5 +206,35 @@ module Syntropy
|
|
204
206
|
def remove_entry_cache_keys(entry)
|
205
207
|
entry[:cache_keys]&.each_key { @cache.delete(it) }.clear
|
206
208
|
end
|
209
|
+
|
210
|
+
def compose_up_tree_hooks(path, proc)
|
211
|
+
parent = File.dirname(path)
|
212
|
+
proc = hook_wrap_if_exists(File.join(parent, '_hook.rb'), proc)
|
213
|
+
proc = error_handler_wrap_if_exists(File.join(parent, '_error.rb'), proc)
|
214
|
+
return proc if parent == @root
|
215
|
+
|
216
|
+
compose_up_tree_hooks(parent, proc)
|
217
|
+
end
|
218
|
+
|
219
|
+
def hook_wrap_if_exists(hook_fn, proc)
|
220
|
+
return proc if !File.file?(hook_fn)
|
221
|
+
|
222
|
+
ref = path_rel(hook_fn).gsub(/\.rb$/, '')
|
223
|
+
hook_proc = @module_loader.load(ref)
|
224
|
+
->(req) { hook_proc.(req, proc) }
|
225
|
+
end
|
226
|
+
|
227
|
+
def error_handler_wrap_if_exists(error_handler_fn, proc)
|
228
|
+
return proc if !File.file?(error_handler_fn)
|
229
|
+
|
230
|
+
ref = path_rel(error_handler_fn).gsub(/\.rb$/, '')
|
231
|
+
error_proc = @module_loader.load(ref)
|
232
|
+
|
233
|
+
proc do |req|
|
234
|
+
proc.(req)
|
235
|
+
rescue StandardError => e
|
236
|
+
error_proc.(req, e)
|
237
|
+
end
|
238
|
+
end
|
207
239
|
end
|
208
240
|
end
|
data/lib/syntropy/version.rb
CHANGED
data/test/app/_hook.rb
ADDED
data/test/test_app.rb
CHANGED
@@ -140,6 +140,18 @@ class AppTest < Minitest::Test
|
|
140
140
|
ensure
|
141
141
|
IO.write(@tmp_fn, orig_body) if orig_body
|
142
142
|
end
|
143
|
+
|
144
|
+
def test_middleware
|
145
|
+
req = make_request(':method' => 'HEAD', ':path' => '/test?foo=42')
|
146
|
+
assert_equal Status::OK, req.response_status
|
147
|
+
assert_nil req.response_body
|
148
|
+
assert_equal '42', req.ctx[:foo]
|
149
|
+
|
150
|
+
req = make_request(':method' => 'HEAD', ':path' => '/test/about/raise?foo=43')
|
151
|
+
assert_equal Status::INTERNAL_SERVER_ERROR, req.response_status
|
152
|
+
assert_equal '<h1>Raised error</h1>', req.response_body
|
153
|
+
assert_equal '43', req.ctx[:foo]
|
154
|
+
end
|
143
155
|
end
|
144
156
|
|
145
157
|
class CustomAppTest < Minitest::Test
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntropy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -202,12 +202,15 @@ files:
|
|
202
202
|
- lib/syntropy/side_run.rb
|
203
203
|
- lib/syntropy/version.rb
|
204
204
|
- syntropy.gemspec
|
205
|
+
- test/app/_hook.rb
|
205
206
|
- test/app/_layout/default.rb
|
206
207
|
- test/app/_lib/callable.rb
|
207
208
|
- test/app/_lib/klass.rb
|
208
209
|
- test/app/_lib/missing-export.rb
|
210
|
+
- test/app/about/_error.rb
|
209
211
|
- test/app/about/foo.md
|
210
212
|
- test/app/about/index.rb
|
213
|
+
- test/app/about/raise.rb
|
211
214
|
- test/app/api+.rb
|
212
215
|
- test/app/assets/style.css
|
213
216
|
- test/app/bar.rb
|