syntropy 0.36.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 +23 -0
- data/Gemfile +4 -0
- data/TODO.md +4 -0
- data/bin/syntropy +12 -2
- data/cmd/help.rb +4 -0
- data/cmd/new/template/.gitignore +2 -1
- data/cmd/new/template/config/Caddyfile +5 -0
- data/cmd/new/template/docker-compose.yml +28 -3
- data/cmd/new.rb +7 -1
- data/cmd/serve.rb +3 -1
- data/cmd/version.rb +14 -0
- data/examples/basic/counter_api.rb +1 -1
- 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/http/io_extensions.rb +9 -0
- data/lib/syntropy/http/server_connection.rb +1 -0
- data/lib/syntropy/json_api.rb +5 -0
- data/lib/syntropy/module_loader.rb +46 -42
- data/lib/syntropy/routing_tree.rb +14 -14
- data/lib/syntropy/storage/schema.rb +3 -3
- data/lib/syntropy/test.rb +29 -11
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +3 -6
- data/test/bm_router_proc.rb +14 -15
- data/test/fixtures/app/_lib/klass.rb +1 -1
- data/test/fixtures/app/api+.rb +1 -1
- 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_http_protocol.rb +54 -0
- data/test/test_module_loader.rb +43 -5
- data/test/test_routing_tree.rb +1 -0
- data/test/test_test.rb +1 -1
- metadata +34 -2
- data/lib/syntropy/utils.rb +0 -87
data/test/test_module_loader.rb
CHANGED
|
@@ -19,14 +19,13 @@ 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
|
|
|
26
26
|
mod = @loader.load('_lib/klass')
|
|
27
27
|
assert_equal :bar, mod.foo
|
|
28
|
-
|
|
29
|
-
assert_equal 43, mod.bar
|
|
28
|
+
assert_equal 42, mod.bar
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
def test_import_paths
|
|
@@ -36,13 +35,13 @@ class ModuleTest < Minitest::Test
|
|
|
36
35
|
|
|
37
36
|
assert_equal :foo, mod[:a1]
|
|
38
37
|
assert_equal :foo, mod[:a2]
|
|
39
|
-
assert_kind_of Syntropy::
|
|
38
|
+
assert_kind_of Syntropy::ModuleContext, mod[:foo]
|
|
40
39
|
assert_equal 'barbarbar', mod[:callable].(3)
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
def test_export_self
|
|
44
43
|
mod = @loader.load('_lib/self')
|
|
45
|
-
assert_kind_of Syntropy::
|
|
44
|
+
assert_kind_of Syntropy::ModuleContext, mod
|
|
46
45
|
assert_equal :bar, mod.foo
|
|
47
46
|
end
|
|
48
47
|
|
|
@@ -114,3 +113,42 @@ class ModuleTest < Minitest::Test
|
|
|
114
113
|
assert_equal [], list
|
|
115
114
|
end
|
|
116
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
|
|
@@ -181,6 +181,7 @@ files:
|
|
|
181
181
|
- cmd/new/template/app/assets/style.css
|
|
182
182
|
- cmd/new/template/app/index.rb
|
|
183
183
|
- cmd/new/template/app/test.rb
|
|
184
|
+
- cmd/new/template/config/Caddyfile
|
|
184
185
|
- cmd/new/template/config/development.rb
|
|
185
186
|
- cmd/new/template/config/production.rb
|
|
186
187
|
- cmd/new/template/config/test.rb
|
|
@@ -188,6 +189,7 @@ files:
|
|
|
188
189
|
- cmd/new/template/test/test_app.rb
|
|
189
190
|
- cmd/serve.rb
|
|
190
191
|
- cmd/test.rb
|
|
192
|
+
- cmd/version.rb
|
|
191
193
|
- docker-compose.yml
|
|
192
194
|
- examples/basic/bad.rb
|
|
193
195
|
- examples/basic/card.rb
|
|
@@ -213,6 +215,12 @@ files:
|
|
|
213
215
|
- examples/blog/config/production.rb
|
|
214
216
|
- examples/blog/config/test.rb
|
|
215
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
|
|
216
224
|
- examples/mcp-oauth/.ruby-version
|
|
217
225
|
- examples/mcp-oauth/Gemfile
|
|
218
226
|
- examples/mcp-oauth/README.md
|
|
@@ -239,6 +247,7 @@ files:
|
|
|
239
247
|
- lib/syntropy/applets/builtin/json_api.js
|
|
240
248
|
- lib/syntropy/applets/builtin/ping.rb
|
|
241
249
|
- lib/syntropy/applets/builtin/req.rb
|
|
250
|
+
- lib/syntropy/controller_extensions.rb
|
|
242
251
|
- lib/syntropy/dev_mode.rb
|
|
243
252
|
- lib/syntropy/errors.rb
|
|
244
253
|
- lib/syntropy/http.rb
|
|
@@ -269,7 +278,6 @@ files:
|
|
|
269
278
|
- lib/syntropy/storage/schema.rb
|
|
270
279
|
- lib/syntropy/storage/store.rb
|
|
271
280
|
- lib/syntropy/test.rb
|
|
272
|
-
- lib/syntropy/utils.rb
|
|
273
281
|
- lib/syntropy/version.rb
|
|
274
282
|
- syntropy.gemspec
|
|
275
283
|
- test/bm_router_proc.rb
|
|
@@ -290,6 +298,7 @@ files:
|
|
|
290
298
|
- test/fixtures/app/api+.rb
|
|
291
299
|
- test/fixtures/app/assets/style.css
|
|
292
300
|
- test/fixtures/app/bad_mod.rb
|
|
301
|
+
- test/fixtures/app/bad_mod_arity.rb
|
|
293
302
|
- test/fixtures/app/bar.rb
|
|
294
303
|
- test/fixtures/app/baz.rb
|
|
295
304
|
- test/fixtures/app/by_method.rb
|
|
@@ -307,6 +316,21 @@ files:
|
|
|
307
316
|
- test/fixtures/app/singleton.rb
|
|
308
317
|
- test/fixtures/app/tmp.rb
|
|
309
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
|
|
310
334
|
- test/fixtures/app_multi_site/_site.rb
|
|
311
335
|
- test/fixtures/app_multi_site/bar.baz/index.html
|
|
312
336
|
- test/fixtures/app_multi_site/foo.bar/index.html
|
|
@@ -314,6 +338,13 @@ files:
|
|
|
314
338
|
- test/fixtures/app_setup/index.rb
|
|
315
339
|
- test/fixtures/app_with_schema/_schema/2026-01-02-foo.rb
|
|
316
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
|
|
317
348
|
- test/fixtures/schema/2026-01-02-foo.rb
|
|
318
349
|
- test/fixtures/schema/2026-05-30-bar.rb
|
|
319
350
|
- test/helper.rb
|
|
@@ -321,6 +352,7 @@ files:
|
|
|
321
352
|
- test/test_app.rb
|
|
322
353
|
- test/test_caching.rb
|
|
323
354
|
- test/test_connection_pool.rb
|
|
355
|
+
- test/test_controller.rb
|
|
324
356
|
- test/test_errors.rb
|
|
325
357
|
- test/test_http_client.rb
|
|
326
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
|