syntropy 0.37.0 → 0.38.0
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 +8 -0
- data/Gemfile +4 -0
- data/TODO.md +4 -0
- data/bin/syntropy +12 -2
- data/cmd/help.rb +4 -0
- data/cmd/version.rb +14 -0
- data/examples/blog/app/posts/[id]/edit.rb +1 -1
- data/examples/blog/app/posts/[id]/index.rb +1 -1
- data/examples/blog/app/posts/index.rb +1 -1
- data/examples/blog/app/posts/new.rb +1 -1
- data/examples/github/app/[org]/[repo]/index.rb +0 -0
- data/examples/github/app/[org]/[repo]/issues/[id].rb +0 -0
- data/examples/github/app/[org]/index.rb +0 -0
- data/examples/github/app/collections.rb +0 -0
- data/examples/github/app/explore.rb +0 -0
- data/examples/github/app/index.rb +0 -0
- data/lib/syntropy/app.rb +6 -2
- data/lib/syntropy/controller_extensions.rb +136 -0
- data/lib/syntropy/module_loader.rb +46 -40
- data/lib/syntropy/routing_tree.rb +14 -14
- data/lib/syntropy/test.rb +28 -10
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +0 -3
- data/test/bm_router_proc.rb +14 -15
- data/test/fixtures/app/bad_mod_arity.rb +3 -0
- data/test/fixtures/app/by_method.rb +1 -1
- data/test/fixtures/app/post_ct.rb +1 -1
- data/test/fixtures/app_errors/_error.rb +3 -0
- data/test/fixtures/app_errors/foo/_error.rb +3 -0
- data/test/fixtures/app_errors/foo/bar/_error.rb +3 -0
- data/test/fixtures/app_errors/foo/bar/baz/index.rb +3 -0
- data/test/fixtures/app_errors/foo/bar/index.rb +3 -0
- data/test/fixtures/app_errors/foo/index.rb +3 -0
- data/test/fixtures/app_errors/index.rb +3 -0
- data/test/fixtures/app_hooks/_hook.rb +4 -0
- data/test/fixtures/app_hooks/foo/_hook.rb +4 -0
- data/test/fixtures/app_hooks/foo/bar/_hook.rb +4 -0
- data/test/fixtures/app_hooks/foo/bar/baz/_hook.rb +4 -0
- data/test/fixtures/app_hooks/foo/bar/baz/index.rb +3 -0
- data/test/fixtures/app_hooks/foo/bar/index.rb +3 -0
- data/test/fixtures/app_hooks/foo/index.rb +3 -0
- data/test/fixtures/app_hooks/index.rb +3 -0
- data/test/fixtures/app_multi_site/_site.rb +1 -1
- data/test/fixtures/controllers/by_host/bar.com/index.rb +3 -0
- data/test/fixtures/controllers/by_host/foo.com/index.rb +3 -0
- data/test/fixtures/controllers/by_host_dir.rb +1 -0
- data/test/fixtures/controllers/by_host_dir_map.rb +4 -0
- data/test/fixtures/controllers/by_host_map.rb +4 -0
- data/test/fixtures/controllers/by_http_method.rb +9 -0
- data/test/fixtures/controllers/jsonrpc_endpoint.rb +0 -0
- data/test/test_app.rb +86 -1
- data/test/test_controller.rb +71 -0
- data/test/test_module_loader.rb +42 -3
- data/test/test_routing_tree.rb +1 -0
- data/test/test_test.rb +1 -1
- metadata +33 -2
- data/lib/syntropy/utils.rb +0 -87
data/test/bm_router_proc.rb
CHANGED
|
@@ -138,8 +138,8 @@ def make_tmp_file_tree(dir, spec)
|
|
|
138
138
|
dir
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
|
|
142
|
-
make_tmp_file_tree(app_root, {
|
|
141
|
+
$app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
|
|
142
|
+
make_tmp_file_tree($app_root, {
|
|
143
143
|
'index.rb': "export ->(req) { req.redirect('/hello') }",
|
|
144
144
|
'hello': {
|
|
145
145
|
'index.rb': "export ->(req) { req.respond('Hello!', 'Content-Type' => 'text/html') }",
|
|
@@ -147,13 +147,13 @@ make_tmp_file_tree(app_root, {
|
|
|
147
147
|
}
|
|
148
148
|
})
|
|
149
149
|
|
|
150
|
-
machine = UM.new
|
|
151
|
-
syntropy_app = Syntropy::App.new(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
156
|
-
proc = ->(req) { syntropy_app.(req) }
|
|
150
|
+
# machine = UM.new
|
|
151
|
+
# syntropy_app = Syntropy::App.new(
|
|
152
|
+
# app_root: app_root,
|
|
153
|
+
# mount_path: '/',
|
|
154
|
+
# machine: machine
|
|
155
|
+
# )
|
|
156
|
+
# proc = ->(req) { syntropy_app.(req) }
|
|
157
157
|
|
|
158
158
|
module ::Kernel
|
|
159
159
|
def mock_req(headers, body = nil)
|
|
@@ -161,11 +161,11 @@ module ::Kernel
|
|
|
161
161
|
end
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
puts '*' * 40
|
|
164
|
+
# puts '*' * 40
|
|
165
165
|
|
|
166
|
-
req = mock_req(':method' => 'GET', ':path' => '/hello/world')
|
|
167
|
-
proc.(req)
|
|
168
|
-
p [req.response_status, req.response_headers, req.response_body]
|
|
166
|
+
# req = mock_req(':method' => 'GET', ':path' => '/hello/world')
|
|
167
|
+
# proc.(req)
|
|
168
|
+
# p [req.response_status, req.response_headers, req.response_body]
|
|
169
169
|
|
|
170
170
|
################################################################################
|
|
171
171
|
|
|
@@ -185,9 +185,8 @@ BM.run do
|
|
|
185
185
|
def setup
|
|
186
186
|
machine = UM.new
|
|
187
187
|
syntropy_app = Syntropy::App.new(
|
|
188
|
-
app_root: app_root,
|
|
188
|
+
app_root: $app_root,
|
|
189
189
|
mount_path: '/',
|
|
190
|
-
# watch_files: 0.05,
|
|
191
190
|
machine: machine
|
|
192
191
|
)
|
|
193
192
|
@app = ->(req) { syntropy_app.(req) }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export dispatch_by_host('.')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export dispatch_by_host('by_host')
|
|
File without changes
|
data/test/test_app.rb
CHANGED
|
@@ -119,6 +119,11 @@ class AppTest < Minitest::Test
|
|
|
119
119
|
}
|
|
120
120
|
assert_equal HTTP::INTERNAL_SERVER_ERROR, req.response_status
|
|
121
121
|
|
|
122
|
+
req = @test_harness.no_raise_internal_server_error {
|
|
123
|
+
@test_harness.request(':method' => 'GET', ':path' => '/test/bad_mod_arity')
|
|
124
|
+
}
|
|
125
|
+
assert_equal HTTP::INTERNAL_SERVER_ERROR, req.response_status
|
|
126
|
+
|
|
122
127
|
req = @test_harness.request(':method' => 'GET', ':path' => '/test/.well-known/foo')
|
|
123
128
|
assert_equal HTTP::OK, req.response_status
|
|
124
129
|
assert_equal 'foo', req.response_body
|
|
@@ -183,6 +188,86 @@ class AppTest < Minitest::Test
|
|
|
183
188
|
end
|
|
184
189
|
end
|
|
185
190
|
|
|
191
|
+
class MiddlewareHooksTest < Minitest::Test
|
|
192
|
+
HTTP = Syntropy::HTTP
|
|
193
|
+
|
|
194
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app_hooks')
|
|
195
|
+
|
|
196
|
+
def setup
|
|
197
|
+
@machine = UM.new
|
|
198
|
+
|
|
199
|
+
@tmp_path = '/test/tmp'
|
|
200
|
+
@tmp_fn = File.join(APP_ROOT, 'tmp.rb')
|
|
201
|
+
|
|
202
|
+
@app = Syntropy::App.new(
|
|
203
|
+
app_root: APP_ROOT,
|
|
204
|
+
mount_path: '/',
|
|
205
|
+
watch_files: 0.05,
|
|
206
|
+
machine: @machine
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
@test_harness = Syntropy::TestHarness.new(@app)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def test_middleware_composition
|
|
213
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/')
|
|
214
|
+
assert_equal HTTP::OK, req.response_status
|
|
215
|
+
assert_equal 'root: root', req.response_body
|
|
216
|
+
|
|
217
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo')
|
|
218
|
+
assert_equal HTTP::OK, req.response_status
|
|
219
|
+
assert_equal 'foo: root foo', req.response_body
|
|
220
|
+
|
|
221
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo/bar')
|
|
222
|
+
assert_equal HTTP::OK, req.response_status
|
|
223
|
+
assert_equal 'bar: root foo bar', req.response_body
|
|
224
|
+
|
|
225
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo/bar/baz')
|
|
226
|
+
assert_equal HTTP::OK, req.response_status
|
|
227
|
+
assert_equal 'baz: root foo bar baz', req.response_body
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
class ErrorHandlerTest < Minitest::Test
|
|
232
|
+
HTTP = Syntropy::HTTP
|
|
233
|
+
|
|
234
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app_errors')
|
|
235
|
+
|
|
236
|
+
def setup
|
|
237
|
+
@machine = UM.new
|
|
238
|
+
|
|
239
|
+
@tmp_path = '/test/tmp'
|
|
240
|
+
@tmp_fn = File.join(APP_ROOT, 'tmp.rb')
|
|
241
|
+
|
|
242
|
+
@app = Syntropy::App.new(
|
|
243
|
+
app_root: APP_ROOT,
|
|
244
|
+
mount_path: '/',
|
|
245
|
+
watch_files: 0.05,
|
|
246
|
+
machine: @machine
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
@test_harness = Syntropy::TestHarness.new(@app)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def test_error_handlers
|
|
253
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/')
|
|
254
|
+
assert_equal HTTP::TEAPOT, req.response_status
|
|
255
|
+
assert_equal 'root: root', req.response_body
|
|
256
|
+
|
|
257
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo')
|
|
258
|
+
assert_equal HTTP::TEAPOT, req.response_status
|
|
259
|
+
assert_equal 'foo: foo', req.response_body
|
|
260
|
+
|
|
261
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo/bar')
|
|
262
|
+
assert_equal HTTP::TEAPOT, req.response_status
|
|
263
|
+
assert_equal 'bar: bar', req.response_body
|
|
264
|
+
|
|
265
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/foo/bar/baz')
|
|
266
|
+
assert_equal HTTP::TEAPOT, req.response_status
|
|
267
|
+
assert_equal 'bar: baz', req.response_body
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
186
271
|
class CustomAppTest < Minitest::Test
|
|
187
272
|
HTTP = Syntropy::HTTP
|
|
188
273
|
|
|
@@ -220,7 +305,7 @@ class MultiSiteAppTest < Minitest::Test
|
|
|
220
305
|
@test_harness = Syntropy::TestHarness.new(@app)
|
|
221
306
|
end
|
|
222
307
|
|
|
223
|
-
def
|
|
308
|
+
def test_dispatch_by_host
|
|
224
309
|
req = @test_harness.request(':method' => 'GET', ':path' => '/', 'host' => 'blah')
|
|
225
310
|
assert_nil req.response_body
|
|
226
311
|
assert_equal HTTP::BAD_REQUEST, req.response_status
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
require 'syntropy/test'
|
|
5
|
+
|
|
6
|
+
class DispatchByHostTest < Syntropy::Test
|
|
7
|
+
self.env = {
|
|
8
|
+
app_root: File.join(__dir__, 'fixtures/controllers'),
|
|
9
|
+
mount_path: '/'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def test_dispatch_by_host_dir
|
|
13
|
+
req = get('/by_host_dir', 'host' => 'sqdf')
|
|
14
|
+
assert_equal HTTP::BAD_REQUEST, req.response_status
|
|
15
|
+
|
|
16
|
+
req = get('/by_host_dir', 'host' => 'foo.com')
|
|
17
|
+
assert_equal HTTP::OK, req.response_status
|
|
18
|
+
assert_equal 'foo', req.response_body
|
|
19
|
+
|
|
20
|
+
req = get('/by_host_dir', 'host' => 'bar.com')
|
|
21
|
+
assert_equal HTTP::OK, req.response_status
|
|
22
|
+
assert_equal 'bar', req.response_body
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_dispatch_by_host_map
|
|
26
|
+
req = get('/by_host_map', 'host' => 'sqdf')
|
|
27
|
+
assert_equal HTTP::BAD_REQUEST, req.response_status
|
|
28
|
+
|
|
29
|
+
req = get('/by_host_map', 'host' => 'foofoo')
|
|
30
|
+
assert_equal HTTP::OK, req.response_status
|
|
31
|
+
assert_equal 'foo', req.response_body
|
|
32
|
+
|
|
33
|
+
req = get('/by_host_map', 'host' => 'barbar')
|
|
34
|
+
assert_equal HTTP::OK, req.response_status
|
|
35
|
+
assert_equal 'bar', req.response_body
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_dispatch_by_host_dir_map
|
|
39
|
+
req = get('/by_host_dir_map', 'host' => 'sqdf')
|
|
40
|
+
assert_equal HTTP::BAD_REQUEST, req.response_status
|
|
41
|
+
|
|
42
|
+
req = get('/by_host_dir_map', 'host' => 'foo.com')
|
|
43
|
+
assert_equal HTTP::OK, req.response_status
|
|
44
|
+
assert_equal 'foo', req.response_body
|
|
45
|
+
|
|
46
|
+
req = get('/by_host_dir_map', 'host' => 'foofoo')
|
|
47
|
+
assert_equal HTTP::OK, req.response_status
|
|
48
|
+
assert_equal 'foo', req.response_body
|
|
49
|
+
|
|
50
|
+
req = get('/by_host_dir_map', 'host' => 'bar.com')
|
|
51
|
+
assert_equal HTTP::OK, req.response_status
|
|
52
|
+
assert_equal 'bar', req.response_body
|
|
53
|
+
|
|
54
|
+
req = get('/by_host_dir_map', 'host' => 'barbar')
|
|
55
|
+
assert_equal HTTP::OK, req.response_status
|
|
56
|
+
assert_equal 'bar', req.response_body
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_dispatch_by_http_method
|
|
60
|
+
req = get('/by_http_method')
|
|
61
|
+
assert_equal HTTP::OK, req.response_status
|
|
62
|
+
assert_equal 'get', req.response_body
|
|
63
|
+
|
|
64
|
+
req = post('/by_http_method', nil, nil)
|
|
65
|
+
assert_equal HTTP::OK, req.response_status
|
|
66
|
+
assert_equal 'post', req.response_body
|
|
67
|
+
|
|
68
|
+
req = patch('/by_http_method', nil, nil)
|
|
69
|
+
assert_equal HTTP::METHOD_NOT_ALLOWED, req.response_status
|
|
70
|
+
end
|
|
71
|
+
end
|
data/test/test_module_loader.rb
CHANGED
|
@@ -19,7 +19,7 @@ class ModuleTest < Minitest::Test
|
|
|
19
19
|
assert_raises(Syntropy::Error) { @loader.load('_lib/missing-export') }
|
|
20
20
|
|
|
21
21
|
mod = @loader.load('_lib/callable')
|
|
22
|
-
assert_kind_of Syntropy::
|
|
22
|
+
assert_kind_of Syntropy::ModuleContext, mod
|
|
23
23
|
assert_equal 'barbarbar', mod.call(3)
|
|
24
24
|
assert_raises(NoMethodError) { mod.foo(2) }
|
|
25
25
|
|
|
@@ -35,13 +35,13 @@ class ModuleTest < Minitest::Test
|
|
|
35
35
|
|
|
36
36
|
assert_equal :foo, mod[:a1]
|
|
37
37
|
assert_equal :foo, mod[:a2]
|
|
38
|
-
assert_kind_of Syntropy::
|
|
38
|
+
assert_kind_of Syntropy::ModuleContext, mod[:foo]
|
|
39
39
|
assert_equal 'barbarbar', mod[:callable].(3)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def test_export_self
|
|
43
43
|
mod = @loader.load('_lib/self')
|
|
44
|
-
assert_kind_of Syntropy::
|
|
44
|
+
assert_kind_of Syntropy::ModuleContext, mod
|
|
45
45
|
assert_equal :bar, mod.foo
|
|
46
46
|
end
|
|
47
47
|
|
|
@@ -113,3 +113,42 @@ class ModuleTest < Minitest::Test
|
|
|
113
113
|
assert_equal [], list
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class ModuleExtensionsTest < Minitest::Test
|
|
119
|
+
module E1
|
|
120
|
+
def e1_foo = :foo
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
module E2
|
|
124
|
+
def e2_bar = :bar
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
module E3
|
|
128
|
+
def e3_baz = :baz
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_module_extension_single
|
|
132
|
+
@machine = UM.new
|
|
133
|
+
@root = File.join(__dir__, 'fixtures/app')
|
|
134
|
+
@env = { app_root: @root, baz: 42, machine: @machine, app: 42 }
|
|
135
|
+
@loader = Syntropy::ModuleLoader.new(@env, extensions: E1)
|
|
136
|
+
|
|
137
|
+
mod = @loader.load('_lib/self')
|
|
138
|
+
assert_equal true, mod.respond_to?(:e1_foo)
|
|
139
|
+
assert_equal :foo, mod.e1_foo
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_module_extension_multi
|
|
143
|
+
@machine = UM.new
|
|
144
|
+
@root = File.join(__dir__, 'fixtures/app')
|
|
145
|
+
@env = { app_root: @root, baz: 42, machine: @machine, app: 42 }
|
|
146
|
+
@loader = Syntropy::ModuleLoader.new(@env, extensions: [E2, E3])
|
|
147
|
+
|
|
148
|
+
mod = @loader.load('_lib/self')
|
|
149
|
+
assert_equal true, mod.respond_to?(:e2_bar)
|
|
150
|
+
assert_equal :bar, mod.e2_bar
|
|
151
|
+
assert_equal true, mod.respond_to?(:e3_baz)
|
|
152
|
+
assert_equal :baz, mod.e3_baz
|
|
153
|
+
end
|
|
154
|
+
end
|
data/test/test_routing_tree.rb
CHANGED
|
@@ -105,6 +105,7 @@ class RoutingTreeTest < Minitest::Test
|
|
|
105
105
|
issues = repo[:children]['issues']
|
|
106
106
|
assert_equal repo, issues[:parent]
|
|
107
107
|
assert_equal '/docs/[org]/[repo]/issues', issues[:path]
|
|
108
|
+
refute_nil issues[:hook]
|
|
108
109
|
assert_nil issues[:param]
|
|
109
110
|
assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/index.rb'), issues[:target][:fn]
|
|
110
111
|
assert_equal ['[]'], issues[:children].keys.sort_by(&:to_s)
|
data/test/test_test.rb
CHANGED
|
@@ -34,7 +34,7 @@ class TestTest < Syntropy::Test
|
|
|
34
34
|
|
|
35
35
|
def test_load_module
|
|
36
36
|
mod = load_module('_lib/env')
|
|
37
|
-
assert_kind_of Syntropy::
|
|
37
|
+
assert_kind_of Syntropy::ModuleContext, mod
|
|
38
38
|
assert_equal app, mod.app
|
|
39
39
|
|
|
40
40
|
assert_raises(Syntropy::Error) { load_module('_lib/blah')}
|
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.38.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
@@ -189,6 +189,7 @@ files:
|
|
|
189
189
|
- cmd/new/template/test/test_app.rb
|
|
190
190
|
- cmd/serve.rb
|
|
191
191
|
- cmd/test.rb
|
|
192
|
+
- cmd/version.rb
|
|
192
193
|
- docker-compose.yml
|
|
193
194
|
- examples/basic/bad.rb
|
|
194
195
|
- examples/basic/card.rb
|
|
@@ -214,6 +215,12 @@ files:
|
|
|
214
215
|
- examples/blog/config/production.rb
|
|
215
216
|
- examples/blog/config/test.rb
|
|
216
217
|
- examples/blog/test/test_posts.rb
|
|
218
|
+
- examples/github/app/[org]/[repo]/index.rb
|
|
219
|
+
- examples/github/app/[org]/[repo]/issues/[id].rb
|
|
220
|
+
- examples/github/app/[org]/index.rb
|
|
221
|
+
- examples/github/app/collections.rb
|
|
222
|
+
- examples/github/app/explore.rb
|
|
223
|
+
- examples/github/app/index.rb
|
|
217
224
|
- examples/mcp-oauth/.ruby-version
|
|
218
225
|
- examples/mcp-oauth/Gemfile
|
|
219
226
|
- examples/mcp-oauth/README.md
|
|
@@ -240,6 +247,7 @@ files:
|
|
|
240
247
|
- lib/syntropy/applets/builtin/json_api.js
|
|
241
248
|
- lib/syntropy/applets/builtin/ping.rb
|
|
242
249
|
- lib/syntropy/applets/builtin/req.rb
|
|
250
|
+
- lib/syntropy/controller_extensions.rb
|
|
243
251
|
- lib/syntropy/dev_mode.rb
|
|
244
252
|
- lib/syntropy/errors.rb
|
|
245
253
|
- lib/syntropy/http.rb
|
|
@@ -270,7 +278,6 @@ files:
|
|
|
270
278
|
- lib/syntropy/storage/schema.rb
|
|
271
279
|
- lib/syntropy/storage/store.rb
|
|
272
280
|
- lib/syntropy/test.rb
|
|
273
|
-
- lib/syntropy/utils.rb
|
|
274
281
|
- lib/syntropy/version.rb
|
|
275
282
|
- syntropy.gemspec
|
|
276
283
|
- test/bm_router_proc.rb
|
|
@@ -291,6 +298,7 @@ files:
|
|
|
291
298
|
- test/fixtures/app/api+.rb
|
|
292
299
|
- test/fixtures/app/assets/style.css
|
|
293
300
|
- test/fixtures/app/bad_mod.rb
|
|
301
|
+
- test/fixtures/app/bad_mod_arity.rb
|
|
294
302
|
- test/fixtures/app/bar.rb
|
|
295
303
|
- test/fixtures/app/baz.rb
|
|
296
304
|
- test/fixtures/app/by_method.rb
|
|
@@ -308,6 +316,21 @@ files:
|
|
|
308
316
|
- test/fixtures/app/singleton.rb
|
|
309
317
|
- test/fixtures/app/tmp.rb
|
|
310
318
|
- test/fixtures/app_custom/_site.rb
|
|
319
|
+
- test/fixtures/app_errors/_error.rb
|
|
320
|
+
- test/fixtures/app_errors/foo/_error.rb
|
|
321
|
+
- test/fixtures/app_errors/foo/bar/_error.rb
|
|
322
|
+
- test/fixtures/app_errors/foo/bar/baz/index.rb
|
|
323
|
+
- test/fixtures/app_errors/foo/bar/index.rb
|
|
324
|
+
- test/fixtures/app_errors/foo/index.rb
|
|
325
|
+
- test/fixtures/app_errors/index.rb
|
|
326
|
+
- test/fixtures/app_hooks/_hook.rb
|
|
327
|
+
- test/fixtures/app_hooks/foo/_hook.rb
|
|
328
|
+
- test/fixtures/app_hooks/foo/bar/_hook.rb
|
|
329
|
+
- test/fixtures/app_hooks/foo/bar/baz/_hook.rb
|
|
330
|
+
- test/fixtures/app_hooks/foo/bar/baz/index.rb
|
|
331
|
+
- test/fixtures/app_hooks/foo/bar/index.rb
|
|
332
|
+
- test/fixtures/app_hooks/foo/index.rb
|
|
333
|
+
- test/fixtures/app_hooks/index.rb
|
|
311
334
|
- test/fixtures/app_multi_site/_site.rb
|
|
312
335
|
- test/fixtures/app_multi_site/bar.baz/index.html
|
|
313
336
|
- test/fixtures/app_multi_site/foo.bar/index.html
|
|
@@ -315,6 +338,13 @@ files:
|
|
|
315
338
|
- test/fixtures/app_setup/index.rb
|
|
316
339
|
- test/fixtures/app_with_schema/_schema/2026-01-02-foo.rb
|
|
317
340
|
- test/fixtures/app_with_schema/_schema/2026-05-30-bar.rb
|
|
341
|
+
- test/fixtures/controllers/by_host/bar.com/index.rb
|
|
342
|
+
- test/fixtures/controllers/by_host/foo.com/index.rb
|
|
343
|
+
- test/fixtures/controllers/by_host_dir.rb
|
|
344
|
+
- test/fixtures/controllers/by_host_dir_map.rb
|
|
345
|
+
- test/fixtures/controllers/by_host_map.rb
|
|
346
|
+
- test/fixtures/controllers/by_http_method.rb
|
|
347
|
+
- test/fixtures/controllers/jsonrpc_endpoint.rb
|
|
318
348
|
- test/fixtures/schema/2026-01-02-foo.rb
|
|
319
349
|
- test/fixtures/schema/2026-05-30-bar.rb
|
|
320
350
|
- test/helper.rb
|
|
@@ -322,6 +352,7 @@ files:
|
|
|
322
352
|
- test/test_app.rb
|
|
323
353
|
- test/test_caching.rb
|
|
324
354
|
- test/test_connection_pool.rb
|
|
355
|
+
- test/test_controller.rb
|
|
325
356
|
- test/test_errors.rb
|
|
326
357
|
- test/test_http_client.rb
|
|
327
358
|
- test/test_http_client_connection.rb
|
data/lib/syntropy/utils.rb
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'securerandom'
|
|
4
|
-
|
|
5
|
-
module Syntropy
|
|
6
|
-
# Utilities for use in modules
|
|
7
|
-
module Utilities
|
|
8
|
-
def tmp_path(prefix = 'syntropy')
|
|
9
|
-
"/tmp/#{prefix}-#{SecureRandom.hex(16)}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Returns a request handler that routes request according to the host
|
|
13
|
-
# header. Looks for site directories (named by host name) in the app's root
|
|
14
|
-
# directory. A map may be given in order to provide additional hostnames to
|
|
15
|
-
# site directories.
|
|
16
|
-
#
|
|
17
|
-
# @param env [Hash] app environment hash
|
|
18
|
-
# @param map [Hash, nil] additional hostname map
|
|
19
|
-
# @return [Proc] router proc
|
|
20
|
-
def route_by_host(env, map = nil)
|
|
21
|
-
sites = find_hostname_sites(env)
|
|
22
|
-
|
|
23
|
-
# add map refs
|
|
24
|
-
map&.each { |k, v| sites[k] = sites[v] }
|
|
25
|
-
|
|
26
|
-
lambda { |req|
|
|
27
|
-
site = sites[req.host]
|
|
28
|
-
site ? site.call(req) : req.respond(nil, ':status' => HTTP::BAD_REQUEST)
|
|
29
|
-
}
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Returns a list of parsed markdown pages at the given path.
|
|
33
|
-
#
|
|
34
|
-
# @param env [Hash] app environment hash
|
|
35
|
-
# @param ref [String] directory path
|
|
36
|
-
# @return [Array<Hash>] array of page entries
|
|
37
|
-
def page_list(env, ref)
|
|
38
|
-
full_path = File.join(env[:app_root], ref)
|
|
39
|
-
raise 'Not a directory' if !File.directory?(full_path)
|
|
40
|
-
|
|
41
|
-
Dir[File.join(full_path, '*.md')].sort.map {
|
|
42
|
-
atts, markdown = Syntropy::Markdown.parse(it, env)
|
|
43
|
-
{ atts:, markdown: }
|
|
44
|
-
}
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Instantiates a Syntropy app for the given environment hash.
|
|
48
|
-
#
|
|
49
|
-
# @return [Syntropy::App]
|
|
50
|
-
def app(**)
|
|
51
|
-
Syntropy::App.new(**)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
BUILTIN_APPLET_app_root = File.expand_path(File.join(__dir__, 'applets/builtin'))
|
|
55
|
-
|
|
56
|
-
# Creates a builtin applet with the given environment hash. By default the
|
|
57
|
-
# builtin applet is mounted at /.syntropy.
|
|
58
|
-
#
|
|
59
|
-
# @param env [Hash] app environment
|
|
60
|
-
# @param mount_path [String] mount path for the builtin applet
|
|
61
|
-
# @return [Syntropy::App] applet
|
|
62
|
-
def builtin_applet(env, mount_path: '/.syntropy')
|
|
63
|
-
app(
|
|
64
|
-
machine: env[:machine],
|
|
65
|
-
app_root: BUILTIN_APPLET_app_root,
|
|
66
|
-
mount_path: mount_path,
|
|
67
|
-
builtin_applet_path: nil,
|
|
68
|
-
watch_files: nil
|
|
69
|
-
)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
# Finds sites in the root directory for the given environment hash.
|
|
75
|
-
#
|
|
76
|
-
# @param env [Hash] app environment hash
|
|
77
|
-
# @return [Hash] hash mapping hostname to app
|
|
78
|
-
def find_hostname_sites(env)
|
|
79
|
-
Dir[File.join(env[:app_root], '*')]
|
|
80
|
-
.select { File.directory?(it) && File.basename(it) !~ /^_/ }
|
|
81
|
-
.each_with_object({}) { |fn, h|
|
|
82
|
-
name = File.basename(fn)
|
|
83
|
-
h[name] = Syntropy::App.new(**env.merge(app_root: fn))
|
|
84
|
-
}
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|