syntropy 0.33.0 → 0.34.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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/cmd/console.rb +18 -7
  4. data/cmd/serve.rb +26 -18
  5. data/cmd/test.rb +37 -24
  6. data/examples/blog/.gitignore +1 -0
  7. data/examples/blog/app/_lib/database.rb +13 -0
  8. data/examples/blog/app/_lib/{post_store.rb → posts.rb} +3 -1
  9. data/examples/blog/app/posts/[id]/edit.rb +2 -2
  10. data/examples/blog/app/posts/[id]/index.rb +4 -4
  11. data/examples/blog/app/posts/index.rb +4 -4
  12. data/examples/blog/app/posts/new.rb +1 -1
  13. data/examples/blog/config/development.rb +5 -0
  14. data/examples/blog/config/production.rb +4 -0
  15. data/examples/blog/config/test.rb +5 -0
  16. data/examples/blog/test/test_posts.rb +65 -0
  17. data/examples/mcp-oauth/app/oauth/token.rb +1 -1
  18. data/lib/syntropy/app.rb +48 -40
  19. data/lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb +1 -1
  20. data/lib/syntropy/db/schema.rb +1 -1
  21. data/lib/syntropy/db/store.rb +2 -0
  22. data/lib/syntropy/errors.rb +6 -2
  23. data/lib/syntropy/http/client.rb +1 -0
  24. data/lib/syntropy/http/server_connection.rb +0 -4
  25. data/lib/syntropy/json_api.rb +27 -1
  26. data/lib/syntropy/logger.rb +81 -27
  27. data/lib/syntropy/markdown.rb +61 -32
  28. data/lib/syntropy/mime_types.rb +9 -5
  29. data/lib/syntropy/module_loader.rb +20 -9
  30. data/lib/syntropy/papercraft_extensions.rb +2 -2
  31. data/lib/syntropy/request/mock_adapter.rb +10 -8
  32. data/lib/syntropy/request/request_info.rb +91 -0
  33. data/lib/syntropy/request/response.rb +1 -12
  34. data/lib/syntropy/request/validation.rb +1 -0
  35. data/lib/syntropy/request.rb +51 -19
  36. data/lib/syntropy/routing_tree.rb +27 -28
  37. data/lib/syntropy/session.rb +198 -0
  38. data/lib/syntropy/side_run.rb +25 -2
  39. data/lib/syntropy/test.rb +105 -10
  40. data/lib/syntropy/utils.rb +53 -18
  41. data/lib/syntropy/version.rb +1 -1
  42. data/lib/syntropy.rb +44 -10
  43. data/test/bm_router_proc.rb +4 -4
  44. data/test/fixtures/app/class_instance.rb +5 -0
  45. data/test/fixtures/app/http.rb +5 -0
  46. data/test/fixtures/app/post_ct.rb +5 -0
  47. data/test/fixtures/app/singleton.rb +3 -0
  48. data/test/test_app.rb +13 -52
  49. data/test/test_caching.rb +2 -2
  50. data/test/test_db_schema.rb +1 -1
  51. data/test/test_http_server_connection.rb +3 -3
  52. data/test/test_module_loader.rb +5 -2
  53. data/test/test_response.rb +0 -19
  54. data/test/test_routing_tree.rb +69 -69
  55. data/test/test_server.rb +5 -9
  56. data/test/test_test.rb +70 -0
  57. metadata +52 -42
  58. data/examples/blog/app/_setup.rb +0 -4
  59. data/lib/syntropy/request/session.rb +0 -113
  60. /data/test/{app → fixtures/app}/.well-known/foo.rb +0 -0
  61. /data/test/{app → fixtures/app}/_hook.rb +0 -0
  62. /data/test/{app → fixtures/app}/_layout/default.rb +0 -0
  63. /data/test/{app → fixtures/app}/_lib/callable.rb +0 -0
  64. /data/test/{app → fixtures/app}/_lib/dep.rb +0 -0
  65. /data/test/{app → fixtures/app}/_lib/env.rb +0 -0
  66. /data/test/{app → fixtures/app}/_lib/klass.rb +0 -0
  67. /data/test/{app → fixtures/app}/_lib/missing-export.rb +0 -0
  68. /data/test/{app → fixtures/app}/_lib/self.rb +0 -0
  69. /data/test/{app → fixtures/app}/about/_error.rb +0 -0
  70. /data/test/{app → fixtures/app}/about/foo.md +0 -0
  71. /data/test/{app → fixtures/app}/about/index.rb +0 -0
  72. /data/test/{app → fixtures/app}/about/raise.rb +0 -0
  73. /data/test/{app → fixtures/app}/api+.rb +0 -0
  74. /data/test/{app → fixtures/app}/assets/style.css +0 -0
  75. /data/test/{app → fixtures/app}/bad_mod.rb +0 -0
  76. /data/test/{app → fixtures/app}/bar.rb +0 -0
  77. /data/test/{app → fixtures/app}/baz.rb +0 -0
  78. /data/test/{app → fixtures/app}/by_method.rb +0 -0
  79. /data/test/{app → fixtures/app}/deps.rb +0 -0
  80. /data/test/{app → fixtures/app}/index.html +0 -0
  81. /data/test/{app → fixtures/app}/mod/bar/index+.rb +0 -0
  82. /data/test/{app → fixtures/app}/mod/foo/index.rb +0 -0
  83. /data/test/{app → fixtures/app}/mod/path/a.rb +0 -0
  84. /data/test/{app → fixtures/app}/mod/path/b.rb +0 -0
  85. /data/test/{app → fixtures/app}/params/[foo].rb +0 -0
  86. /data/test/{app → fixtures/app}/rss.rb +0 -0
  87. /data/test/{app → fixtures/app}/tmp.rb +0 -0
  88. /data/test/{app_custom → fixtures/app_custom}/_site.rb +0 -0
  89. /data/test/{app_multi_site → fixtures/app_multi_site}/_site.rb +0 -0
  90. /data/test/{app_multi_site → fixtures/app_multi_site}/bar.baz/index.html +0 -0
  91. /data/test/{app_multi_site → fixtures/app_multi_site}/foo.bar/index.html +0 -0
  92. /data/test/{app_setup → fixtures/app_setup}/_setup.rb +0 -0
  93. /data/test/{app_setup → fixtures/app_setup}/index.rb +0 -0
  94. /data/test/{app_with_schema → fixtures/app_with_schema}/_schema/2026-01-02-foo.rb +0 -0
  95. /data/test/{app_with_schema → fixtures/app_with_schema}/_schema/2026-05-30-bar.rb +0 -0
  96. /data/test/{schema → fixtures/schema}/2026-01-02-foo.rb +0 -0
  97. /data/test/{schema → fixtures/schema}/2026-05-30-bar.rb +0 -0
@@ -54,19 +54,19 @@ class RoutingTreeTest < Minitest::Test
54
54
  }
55
55
 
56
56
  def setup
57
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
58
- make_tmp_file_tree(@root_dir, FILE_TREE)
59
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/docs')
57
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
58
+ make_tmp_file_tree(@app_root, FILE_TREE)
59
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/docs')
60
60
  end
61
61
 
62
62
  def test_compute_clean_url_path
63
63
  c = ->(fn) { @rt.send(:compute_clean_url_path, fn) }
64
- assert_equal '/', c.(File.join(@rt.root_dir, '/index.rb'))
65
- assert_equal '/about', c.(File.join(@rt.root_dir, '/about.md'))
66
- assert_equal '/[org]', c.(File.join(@rt.root_dir, '/[org]'))
67
- assert_equal '/favicon.ico', c.(File.join(@rt.root_dir, '/favicon.ico'))
68
- assert_equal '/assets/style.css', c.(File.join(@rt.root_dir, '/assets/style.css'))
69
- assert_equal '/foo.js', c.(File.join(@rt.root_dir, '/foo.js'))
64
+ assert_equal '/', c.(File.join(@rt.app_root, '/index.rb'))
65
+ assert_equal '/about', c.(File.join(@rt.app_root, '/about.md'))
66
+ assert_equal '/[org]', c.(File.join(@rt.app_root, '/[org]'))
67
+ assert_equal '/favicon.ico', c.(File.join(@rt.app_root, '/favicon.ico'))
68
+ assert_equal '/assets/style.css', c.(File.join(@rt.app_root, '/assets/style.css'))
69
+ assert_equal '/foo.js', c.(File.join(@rt.app_root, '/foo.js'))
70
70
  end
71
71
 
72
72
  def test_routing_tree_generation
@@ -80,40 +80,40 @@ class RoutingTreeTest < Minitest::Test
80
80
  ], root[:children].keys.sort_by(&:to_s)
81
81
 
82
82
  entry = @rt.static_map['/docs']
83
- assert_equal File.join(@rt.root_dir, 'index.rb'), entry[:target][:fn]
83
+ assert_equal File.join(@rt.app_root, 'index.rb'), entry[:target][:fn]
84
84
 
85
85
  about = root[:children]['about']
86
86
  assert_equal '/docs/about', about[:path]
87
87
  assert_equal root, about[:parent]
88
- assert_equal File.join(@rt.root_dir, 'about.md'), about[:target][:fn]
88
+ assert_equal File.join(@rt.app_root, 'about.md'), about[:target][:fn]
89
89
  assert_nil about[:children]
90
90
 
91
91
  org = root[:children]['[]']
92
92
  assert_equal '/docs/[org]', org[:path]
93
93
  assert_equal 'org', org[:param]
94
94
  refute_nil org[:target]
95
- assert_equal File.join(@rt.root_dir, '[org]/index.rb'), org[:target][:fn]
95
+ assert_equal File.join(@rt.app_root, '[org]/index.rb'), org[:target][:fn]
96
96
  assert_equal ['[]'], org[:children].keys.sort_by(&:to_s)
97
97
 
98
98
  repo = org[:children]['[]']
99
99
  assert_equal org, repo[:parent]
100
100
  assert_equal '/docs/[org]/[repo]', repo[:path]
101
101
  assert_equal 'repo', repo[:param]
102
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/index.rb'), repo[:target][:fn]
102
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/index.rb'), repo[:target][:fn]
103
103
  assert_equal ['commits', 'issues'], repo[:children].keys.sort_by(&:to_s)
104
104
 
105
105
  issues = repo[:children]['issues']
106
106
  assert_equal repo, issues[:parent]
107
107
  assert_equal '/docs/[org]/[repo]/issues', issues[:path]
108
108
  assert_nil issues[:param]
109
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/index.rb'), issues[:target][:fn]
109
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/index.rb'), issues[:target][:fn]
110
110
  assert_equal ['[]'], issues[:children].keys.sort_by(&:to_s)
111
111
 
112
112
  id = issues[:children]['[]']
113
113
  assert_equal issues, id[:parent]
114
114
  assert_equal '/docs/[org]/[repo]/issues/[id]', id[:path]
115
115
  assert_equal 'id', id[:param]
116
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/[id]/index.rb'), id[:target][:fn]
116
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/[id]/index.rb'), id[:target][:fn]
117
117
  assert_equal [], id[:children].keys.sort_by(&:to_s)
118
118
 
119
119
  posts = root[:children]['posts']
@@ -126,7 +126,7 @@ class RoutingTreeTest < Minitest::Test
126
126
  assert_equal posts, id[:parent]
127
127
  assert_equal '/docs/posts/[id]', id[:path]
128
128
  assert_equal 'id', id[:param]
129
- assert_equal File.join(@rt.root_dir, 'posts/[id].rb'), id[:target][:fn]
129
+ assert_equal File.join(@rt.app_root, 'posts/[id].rb'), id[:target][:fn]
130
130
  assert_nil id[:children]
131
131
 
132
132
  old = root[:children]['old']
@@ -154,35 +154,35 @@ class RoutingTreeTest < Minitest::Test
154
154
  ], keys
155
155
 
156
156
  o = map['/docs/.well-known/foo']
157
- assert_equal File.join(@rt.root_dir, '.well-known/foo.rb'), o[:target][:fn]
157
+ assert_equal File.join(@rt.app_root, '.well-known/foo.rb'), o[:target][:fn]
158
158
 
159
159
  o = map['/docs/assets/css/style.css']
160
- assert_equal File.join(@rt.root_dir, 'assets/css/style.css'), o[:target][:fn]
160
+ assert_equal File.join(@rt.app_root, 'assets/css/style.css'), o[:target][:fn]
161
161
 
162
162
  o = map['/docs/assets/img/foo.jpg']
163
- assert_equal File.join(@rt.root_dir, 'assets/img/foo.jpg'), o[:target][:fn]
163
+ assert_equal File.join(@rt.app_root, 'assets/img/foo.jpg'), o[:target][:fn]
164
164
 
165
165
  o = map['/docs/old/baz']
166
- assert_equal File.join(@rt.root_dir, 'old/baz.html'), o[:target][:fn]
166
+ assert_equal File.join(@rt.app_root, 'old/baz.html'), o[:target][:fn]
167
167
 
168
168
  o = map['/docs/posts']
169
- assert_equal File.join(@rt.root_dir, 'posts/index.rb'), o[:target][:fn]
169
+ assert_equal File.join(@rt.app_root, 'posts/index.rb'), o[:target][:fn]
170
170
  refute_nil o[:parent]
171
171
  assert_equal '/docs', o[:parent][:path]
172
172
 
173
173
  o = map['/docs/old/baz']
174
- assert_equal File.join(@rt.root_dir, 'old/baz.html'), o[:target][:fn]
174
+ assert_equal File.join(@rt.app_root, 'old/baz.html'), o[:target][:fn]
175
175
 
176
176
  o = map['/docs/old']
177
- assert_equal File.join(@rt.root_dir, 'old/index.html'), o[:target][:fn]
177
+ assert_equal File.join(@rt.app_root, 'old/index.html'), o[:target][:fn]
178
178
  refute_nil o[:parent]
179
179
  assert_equal '/docs', o[:parent][:path]
180
180
 
181
181
  o = map['/docs']
182
- assert_equal File.join(@rt.root_dir, 'index.rb'), o[:target][:fn]
182
+ assert_equal File.join(@rt.app_root, 'index.rb'), o[:target][:fn]
183
183
 
184
184
  o = map['/docs/about']
185
- assert_equal File.join(@rt.root_dir, 'about.md'), o[:target][:fn]
185
+ assert_equal File.join(@rt.app_root, 'about.md'), o[:target][:fn]
186
186
  end
187
187
 
188
188
  def test_dynamic_map
@@ -210,7 +210,7 @@ class RoutingTreeTest < Minitest::Test
210
210
  '[org]/[repo]/issues/[id]/index.rb',
211
211
  'api+.rb',
212
212
  'posts/[id].rb'
213
- ].map { File.join(@rt.root_dir, it) }, keys.map { map[it][:target][:fn] }
213
+ ].map { File.join(@rt.app_root, it) }, keys.map { map[it][:target][:fn] }
214
214
  end
215
215
 
216
216
  def test_router_proc
@@ -244,35 +244,35 @@ class RoutingTreeTest < Minitest::Test
244
244
  assert_nil route
245
245
 
246
246
  route = router.('/docs/assets/img/foo.jpg', {})
247
- assert_equal File.join(@rt.root_dir, 'assets/img/foo.jpg'), route[:target][:fn]
247
+ assert_equal File.join(@rt.app_root, 'assets/img/foo.jpg'), route[:target][:fn]
248
248
 
249
249
  route = router.('/docs/assets/img/bar.jpg', {})
250
250
  assert_nil route
251
251
 
252
252
  route = router.('/docs/about', {})
253
- assert_equal File.join(@rt.root_dir, 'about.md'), route[:target][:fn]
253
+ assert_equal File.join(@rt.app_root, 'about.md'), route[:target][:fn]
254
254
 
255
255
  route = router.('/docs/foo', params = {})
256
- assert_equal File.join(@rt.root_dir, '[org]/index.rb'), route[:target][:fn]
256
+ assert_equal File.join(@rt.app_root, '[org]/index.rb'), route[:target][:fn]
257
257
  assert_equal 'foo', params['org']
258
258
 
259
259
  route = router.('/docs/foo/bar', params = {})
260
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/index.rb'), route[:target][:fn]
260
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/index.rb'), route[:target][:fn]
261
261
  assert_equal 'foo', params['org']
262
262
  assert_equal 'bar', params['repo']
263
263
 
264
264
  route = router.('/docs/bar/baz/commits', params = {})
265
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/commits/index.rb'), route[:target][:fn]
265
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/commits/index.rb'), route[:target][:fn]
266
266
  assert_equal 'bar', params['org']
267
267
  assert_equal 'baz', params['repo']
268
268
 
269
269
  route = router.('/docs/foo/bar/issues', params = {})
270
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/index.rb'), route[:target][:fn]
270
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/index.rb'), route[:target][:fn]
271
271
  assert_equal 'foo', params['org']
272
272
  assert_equal 'bar', params['repo']
273
273
 
274
274
  route = router.('/docs/bar/baz/issues/14', params = {})
275
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/[id]/index.rb'), route[:target][:fn]
275
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/[id]/index.rb'), route[:target][:fn]
276
276
  assert_equal 'bar', params['org']
277
277
  assert_equal 'baz', params['repo']
278
278
  assert_equal '14', params['id']
@@ -284,24 +284,24 @@ class RoutingTreeTest < Minitest::Test
284
284
  assert_nil route
285
285
 
286
286
  route = router.('/docs/api', {})
287
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
287
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
288
288
 
289
289
  route = router.('/docs/api/foo/bar', {})
290
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
290
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
291
291
 
292
292
  route = router.('/docs/api/foo/bar', {})
293
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
293
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
294
294
 
295
295
  route = router.('/docs/posts', {})
296
- assert_equal File.join(@rt.root_dir, 'posts/index.rb'), route[:target][:fn]
296
+ assert_equal File.join(@rt.app_root, 'posts/index.rb'), route[:target][:fn]
297
297
 
298
298
  route = router.('/docs/posts/foo', params = {})
299
- assert_equal File.join(@rt.root_dir, 'posts/[id].rb'), route[:target][:fn]
299
+ assert_equal File.join(@rt.app_root, 'posts/[id].rb'), route[:target][:fn]
300
300
  assert_equal 'foo', params['id']
301
301
  end
302
302
 
303
303
  def test_routing_root_mounted
304
- rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/')
304
+ rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/')
305
305
  router = rt.router_proc
306
306
 
307
307
  route = router.('/docs/df/papercraft/issues/14', {})
@@ -326,35 +326,35 @@ class RoutingTreeTest < Minitest::Test
326
326
  assert_nil route
327
327
 
328
328
  route = router.('/assets/img/foo.jpg', {})
329
- assert_equal File.join(@rt.root_dir, 'assets/img/foo.jpg'), route[:target][:fn]
329
+ assert_equal File.join(@rt.app_root, 'assets/img/foo.jpg'), route[:target][:fn]
330
330
 
331
331
  route = router.('/assets/img/bar.jpg', {})
332
332
  assert_nil route
333
333
 
334
334
  route = router.('/about', {})
335
- assert_equal File.join(@rt.root_dir, 'about.md'), route[:target][:fn]
335
+ assert_equal File.join(@rt.app_root, 'about.md'), route[:target][:fn]
336
336
 
337
337
  route = router.('/foo', params = {})
338
- assert_equal File.join(@rt.root_dir, '[org]/index.rb'), route[:target][:fn]
338
+ assert_equal File.join(@rt.app_root, '[org]/index.rb'), route[:target][:fn]
339
339
  assert_equal 'foo', params['org']
340
340
 
341
341
  route = router.('/foo/bar', params = {})
342
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/index.rb'), route[:target][:fn]
342
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/index.rb'), route[:target][:fn]
343
343
  assert_equal 'foo', params['org']
344
344
  assert_equal 'bar', params['repo']
345
345
 
346
346
  route = router.('/bar/baz/commits', params = {})
347
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/commits/index.rb'), route[:target][:fn]
347
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/commits/index.rb'), route[:target][:fn]
348
348
  assert_equal 'bar', params['org']
349
349
  assert_equal 'baz', params['repo']
350
350
 
351
351
  route = router.('/foo/bar/issues', params = {})
352
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/index.rb'), route[:target][:fn]
352
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/index.rb'), route[:target][:fn]
353
353
  assert_equal 'foo', params['org']
354
354
  assert_equal 'bar', params['repo']
355
355
 
356
356
  route = router.('/bar/baz/issues/14', params = {})
357
- assert_equal File.join(@rt.root_dir, '[org]/[repo]/issues/[id]/index.rb'), route[:target][:fn]
357
+ assert_equal File.join(@rt.app_root, '[org]/[repo]/issues/[id]/index.rb'), route[:target][:fn]
358
358
  assert_equal 'bar', params['org']
359
359
  assert_equal 'baz', params['repo']
360
360
  assert_equal '14', params['id']
@@ -366,24 +366,24 @@ class RoutingTreeTest < Minitest::Test
366
366
  assert_nil route
367
367
 
368
368
  route = router.('/api', {})
369
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
369
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
370
370
 
371
371
  route = router.('/api/foo/bar', {})
372
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
372
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
373
373
 
374
374
  route = router.('/api/foo/bar', {})
375
- assert_equal File.join(@rt.root_dir, 'api+.rb'), route[:target][:fn]
375
+ assert_equal File.join(@rt.app_root, 'api+.rb'), route[:target][:fn]
376
376
 
377
377
  route = router.('/posts', {})
378
- assert_equal File.join(@rt.root_dir, 'posts/index.rb'), route[:target][:fn]
378
+ assert_equal File.join(@rt.app_root, 'posts/index.rb'), route[:target][:fn]
379
379
 
380
380
  route = router.('/posts/foo', params = {})
381
- assert_equal File.join(@rt.root_dir, 'posts/[id].rb'), route[:target][:fn]
381
+ assert_equal File.join(@rt.app_root, 'posts/[id].rb'), route[:target][:fn]
382
382
  assert_equal 'foo', params['id']
383
383
  end
384
384
 
385
385
  def test_mount_applet
386
- rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/')
386
+ rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/')
387
387
  applet = ->(req) { :foo }
388
388
  rt.mount_applet('/foo/bar', applet)
389
389
  router = rt.router_proc
@@ -396,7 +396,7 @@ class RoutingTreeTest < Minitest::Test
396
396
  end
397
397
 
398
398
  def test_mount_applet_nested_mount_path
399
- rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/my/site')
399
+ rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/my/site')
400
400
  applet = ->(req) { :foo }
401
401
  rt.mount_applet('/my/site/foo/bar', applet)
402
402
  router = rt.router_proc
@@ -409,7 +409,7 @@ class RoutingTreeTest < Minitest::Test
409
409
  end
410
410
 
411
411
  def test_mount_applet_clash
412
- rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/')
412
+ rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/')
413
413
  applet = ->(req) { :foo }
414
414
  assert_raises(Syntropy::Error) {
415
415
  rt.mount_applet('/about', applet)
@@ -429,9 +429,9 @@ class RoutingTreeWildcardIndexTest < Minitest::Test
429
429
  }
430
430
  }
431
431
 
432
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
433
- make_tmp_file_tree(@root_dir, file_tree)
434
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/docs')
432
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
433
+ make_tmp_file_tree(@app_root, file_tree)
434
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/docs')
435
435
 
436
436
  router = @rt.router_proc
437
437
 
@@ -455,9 +455,9 @@ class RoutingTreeWildcardIndexTest < Minitest::Test
455
455
  }
456
456
  }
457
457
 
458
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
459
- make_tmp_file_tree(@root_dir, file_tree)
460
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/')
458
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
459
+ make_tmp_file_tree(@app_root, file_tree)
460
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/')
461
461
 
462
462
  router = @rt.router_proc
463
463
 
@@ -480,9 +480,9 @@ class RoutingTreeWildcardIndexTest < Minitest::Test
480
480
  }
481
481
  }
482
482
 
483
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
484
- make_tmp_file_tree(@root_dir, file_tree)
485
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/docs')
483
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
484
+ make_tmp_file_tree(@app_root, file_tree)
485
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/docs')
486
486
  router = @rt.router_proc
487
487
 
488
488
  route = router.('/docs', {})
@@ -513,9 +513,9 @@ class RoutingTreeWildcardIndexTest < Minitest::Test
513
513
  }
514
514
  }
515
515
 
516
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
517
- make_tmp_file_tree(@root_dir, file_tree)
518
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/docs')
516
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
517
+ make_tmp_file_tree(@app_root, file_tree)
518
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/docs')
519
519
  router = @rt.router_proc
520
520
 
521
521
  route = router.('/docs', {})
@@ -552,9 +552,9 @@ class RoutingTreeWildcardIndexTest < Minitest::Test
552
552
  }
553
553
  }
554
554
 
555
- @root_dir = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
556
- make_tmp_file_tree(@root_dir, file_tree)
557
- @rt = Syntropy::RoutingTree.new(root_dir: File.join(@root_dir, 'site'), mount_path: '/docs')
555
+ @app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
556
+ make_tmp_file_tree(@app_root, file_tree)
557
+ @rt = Syntropy::RoutingTree.new(app_root: File.join(@app_root, 'site'), mount_path: '/docs')
558
558
  router = @rt.router_proc
559
559
 
560
560
  route = router.('/docs', {})
data/test/test_server.rb CHANGED
@@ -150,8 +150,7 @@ class ServerTest < Minitest::Test
150
150
  ':path' => '/foo',
151
151
  'server' => 'foo.com',
152
152
  'content-length' => '3',
153
- ':body-done-reading' => true,
154
- ':tx' => 56,
153
+ ':body-done-reading' => true
155
154
  }, headers)
156
155
  body = @bodies.shift
157
156
  assert_equal 'abc', body
@@ -163,8 +162,7 @@ class ServerTest < Minitest::Test
163
162
  ':path' => '/bar',
164
163
  'server' => 'bar.com',
165
164
  'content-length' => '6',
166
- ':body-done-reading' => true,
167
- ':tx' => 56,
165
+ ':body-done-reading' => true
168
166
  }, headers)
169
167
  body = @bodies.shift
170
168
  assert_equal 'defghi', body
@@ -177,7 +175,7 @@ class ServerTest < Minitest::Test
177
175
  @reqs << req
178
176
  @bodies << (b = req.read)
179
177
  req.respond("method: #{req.method}")
180
- rescue => e
178
+ rescue StandardError => e
181
179
  p e
182
180
  p e.backtrace
183
181
  exit!
@@ -218,8 +216,7 @@ class ServerTest < Minitest::Test
218
216
  ':path' => '/foo',
219
217
  'server' => 'foo.com',
220
218
  'transfer-encoding' => 'chunked',
221
- ':body-done-reading' => true,
222
- ':tx' => 56
219
+ ':body-done-reading' => true
223
220
  }, headers)
224
221
  body = @bodies.shift
225
222
  assert_equal 'abcde', body
@@ -231,8 +228,7 @@ class ServerTest < Minitest::Test
231
228
  ':path' => '/bar',
232
229
  'server' => 'bar.com',
233
230
  'transfer-encoding' => 'chunked',
234
- ':body-done-reading' => true,
235
- ':tx' => 56
231
+ ':body-done-reading' => true
236
232
  }, headers)
237
233
  body = @bodies.shift
238
234
  assert_equal '123456789abcdefghijklmnopqrstuv', body
data/test/test_test.rb ADDED
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'syntropy/test'
5
+
6
+ class TestTest < Syntropy::Test
7
+ self.env = {
8
+ app_root: File.join(__dir__, 'fixtures/app'),
9
+ mount_path: '/syntest'
10
+ }
11
+
12
+ def test_http_request
13
+ req = http_request({
14
+ ':method' => 'GET',
15
+ ':path' => '/syntest'
16
+ })
17
+ assert_kind_of Syntropy::Request, req
18
+ assert_equal HTTP::OK, req.response_status
19
+ end
20
+
21
+ def test_env
22
+ assert_kind_of Hash, env
23
+ assert_equal File.join(__dir__, 'fixtures/app'), env[:app_root]
24
+ end
25
+
26
+ def test_app
27
+ assert_kind_of Syntropy::App, app
28
+ assert_equal File.join(__dir__, 'fixtures/app'), app.app_root
29
+ end
30
+
31
+ def test_machine
32
+ assert_kind_of UM, machine
33
+ end
34
+
35
+ def test_load_module
36
+ mod = load_module('_lib/env')
37
+ assert_kind_of Syntropy::Module, mod
38
+ assert_equal app, mod.app
39
+
40
+ assert_raises(Syntropy::Error) { load_module('_lib/blah')}
41
+ end
42
+
43
+ def test_get
44
+ req = get('/syntest/bar')
45
+ assert_kind_of Syntropy::Request, req
46
+ assert_equal HTTP::OK, req.response_status
47
+ assert_equal 'foobar', req.response_body
48
+ end
49
+
50
+ def test_post
51
+ req = post('/syntest/post_ct', 'text/plain', 'foo')
52
+ assert_kind_of Syntropy::Request, req
53
+ assert_equal HTTP::OK, req.response_status
54
+ assert_equal 'text/plain:foo', req.response_body
55
+ end
56
+
57
+ def test_post_json
58
+ req = post_json('/syntest/post_ct', { a: 42, b: [3]})
59
+ assert_kind_of Syntropy::Request, req
60
+ assert_equal HTTP::OK, req.response_status
61
+ assert_equal 'application/json:{"a":42,"b":[3]}', req.response_body
62
+ end
63
+
64
+ def test_post_form
65
+ req = post_form('/syntest/post_ct', { a: 'b&c', d: 1})
66
+ assert_kind_of Syntropy::Request, req
67
+ assert_equal HTTP::OK, req.response_status
68
+ assert_equal 'application/x-www-form-urlencoded:a=b%26c&d=1', req.response_body
69
+ end
70
+ end
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.33.0
4
+ version: 0.34.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -204,15 +204,20 @@ files:
204
204
  - examples/basic/favicon.ico
205
205
  - examples/basic/index.md
206
206
  - examples/basic/templates.rb
207
+ - examples/blog/.gitignore
207
208
  - examples/blog/app/_layout/default.rb
208
- - examples/blog/app/_lib/post_store.rb
209
+ - examples/blog/app/_lib/database.rb
210
+ - examples/blog/app/_lib/posts.rb
209
211
  - examples/blog/app/_schema/2026-01-01-initial.rb
210
- - examples/blog/app/_setup.rb
211
212
  - examples/blog/app/index.rb
212
213
  - examples/blog/app/posts/[id]/edit.rb
213
214
  - examples/blog/app/posts/[id]/index.rb
214
215
  - examples/blog/app/posts/index.rb
215
216
  - examples/blog/app/posts/new.rb
217
+ - examples/blog/config/development.rb
218
+ - examples/blog/config/production.rb
219
+ - examples/blog/config/test.rb
220
+ - examples/blog/test/test_posts.rb
216
221
  - examples/mcp-oauth/.ruby-version
217
222
  - examples/mcp-oauth/Gemfile
218
223
  - examples/mcp-oauth/README.md
@@ -261,56 +266,60 @@ files:
261
266
  - lib/syntropy/request/mock_adapter.rb
262
267
  - lib/syntropy/request/request_info.rb
263
268
  - lib/syntropy/request/response.rb
264
- - lib/syntropy/request/session.rb
265
269
  - lib/syntropy/request/validation.rb
266
270
  - lib/syntropy/routing_tree.rb
271
+ - lib/syntropy/session.rb
267
272
  - lib/syntropy/side_run.rb
268
273
  - lib/syntropy/test.rb
269
274
  - lib/syntropy/utils.rb
270
275
  - lib/syntropy/version.rb
271
276
  - syntropy.gemspec
272
- - test/app/.well-known/foo.rb
273
- - test/app/_hook.rb
274
- - test/app/_layout/default.rb
275
- - test/app/_lib/callable.rb
276
- - test/app/_lib/dep.rb
277
- - test/app/_lib/env.rb
278
- - test/app/_lib/klass.rb
279
- - test/app/_lib/missing-export.rb
280
- - test/app/_lib/self.rb
281
- - test/app/about/_error.rb
282
- - test/app/about/foo.md
283
- - test/app/about/index.rb
284
- - test/app/about/raise.rb
285
- - test/app/api+.rb
286
- - test/app/assets/style.css
287
- - test/app/bad_mod.rb
288
- - test/app/bar.rb
289
- - test/app/baz.rb
290
- - test/app/by_method.rb
291
- - test/app/deps.rb
292
- - test/app/index.html
293
- - test/app/mod/bar/index+.rb
294
- - test/app/mod/foo/index.rb
295
- - test/app/mod/path/a.rb
296
- - test/app/mod/path/b.rb
297
- - test/app/params/[foo].rb
298
- - test/app/rss.rb
299
- - test/app/tmp.rb
300
- - test/app_custom/_site.rb
301
- - test/app_multi_site/_site.rb
302
- - test/app_multi_site/bar.baz/index.html
303
- - test/app_multi_site/foo.bar/index.html
304
- - test/app_setup/_setup.rb
305
- - test/app_setup/index.rb
306
- - test/app_with_schema/_schema/2026-01-02-foo.rb
307
- - test/app_with_schema/_schema/2026-05-30-bar.rb
308
277
  - test/bm_router_proc.rb
309
278
  - test/bm_server.rb
279
+ - test/fixtures/app/.well-known/foo.rb
280
+ - test/fixtures/app/_hook.rb
281
+ - test/fixtures/app/_layout/default.rb
282
+ - test/fixtures/app/_lib/callable.rb
283
+ - test/fixtures/app/_lib/dep.rb
284
+ - test/fixtures/app/_lib/env.rb
285
+ - test/fixtures/app/_lib/klass.rb
286
+ - test/fixtures/app/_lib/missing-export.rb
287
+ - test/fixtures/app/_lib/self.rb
288
+ - test/fixtures/app/about/_error.rb
289
+ - test/fixtures/app/about/foo.md
290
+ - test/fixtures/app/about/index.rb
291
+ - test/fixtures/app/about/raise.rb
292
+ - test/fixtures/app/api+.rb
293
+ - test/fixtures/app/assets/style.css
294
+ - test/fixtures/app/bad_mod.rb
295
+ - test/fixtures/app/bar.rb
296
+ - test/fixtures/app/baz.rb
297
+ - test/fixtures/app/by_method.rb
298
+ - test/fixtures/app/class_instance.rb
299
+ - test/fixtures/app/deps.rb
300
+ - test/fixtures/app/http.rb
301
+ - test/fixtures/app/index.html
302
+ - test/fixtures/app/mod/bar/index+.rb
303
+ - test/fixtures/app/mod/foo/index.rb
304
+ - test/fixtures/app/mod/path/a.rb
305
+ - test/fixtures/app/mod/path/b.rb
306
+ - test/fixtures/app/params/[foo].rb
307
+ - test/fixtures/app/post_ct.rb
308
+ - test/fixtures/app/rss.rb
309
+ - test/fixtures/app/singleton.rb
310
+ - test/fixtures/app/tmp.rb
311
+ - test/fixtures/app_custom/_site.rb
312
+ - test/fixtures/app_multi_site/_site.rb
313
+ - test/fixtures/app_multi_site/bar.baz/index.html
314
+ - test/fixtures/app_multi_site/foo.bar/index.html
315
+ - test/fixtures/app_setup/_setup.rb
316
+ - test/fixtures/app_setup/index.rb
317
+ - test/fixtures/app_with_schema/_schema/2026-01-02-foo.rb
318
+ - test/fixtures/app_with_schema/_schema/2026-05-30-bar.rb
319
+ - test/fixtures/schema/2026-01-02-foo.rb
320
+ - test/fixtures/schema/2026-05-30-bar.rb
310
321
  - test/helper.rb
311
322
  - test/run.rb
312
- - test/schema/2026-01-02-foo.rb
313
- - test/schema/2026-05-30-bar.rb
314
323
  - test/test_app.rb
315
324
  - test/test_caching.rb
316
325
  - test/test_db_connection_pool.rb
@@ -330,6 +339,7 @@ files:
330
339
  - test/test_routing_tree.rb
331
340
  - test/test_server.rb
332
341
  - test/test_side_run.rb
342
+ - test/test_test.rb
333
343
  homepage: https://github.com/digital-fabric/syntropy
334
344
  licenses:
335
345
  - MIT
@@ -1,4 +0,0 @@
1
- @app.setup_db(
2
- db_path: File.join(@app.root_dir, '../blog.db'),
3
- schema_root: '_schema'
4
- )