syntropy 0.31.0 → 0.32.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +13 -0
  4. data/TODO.md +46 -1
  5. data/cmd/console.rb +77 -0
  6. data/cmd/serve.rb +1 -1
  7. data/examples/blog/app/_layout/default.rb +11 -0
  8. data/examples/blog/app/_lib/post_store.rb +47 -0
  9. data/examples/blog/app/_schema/2026-01-01-initial.rb +9 -0
  10. data/examples/blog/app/_setup.rb +4 -0
  11. data/examples/blog/app/index.rb +7 -0
  12. data/examples/blog/app/posts/[id]/edit.rb +33 -0
  13. data/examples/blog/app/posts/[id]/index.rb +58 -0
  14. data/examples/blog/app/posts/index.rb +38 -0
  15. data/examples/blog/app/posts/new.rb +29 -0
  16. data/examples/mcp-oauth/README.md +3 -3
  17. data/examples/mcp-oauth/app/mcp.rb +55 -8
  18. data/examples/mcp-oauth/app/oauth/authorize.rb +0 -8
  19. data/examples/mcp-oauth/app/oauth/register.rb +0 -1
  20. data/lib/syntropy/app.rb +23 -9
  21. data/lib/syntropy/db/connection_pool.rb +71 -0
  22. data/lib/syntropy/db/schema.rb +92 -0
  23. data/lib/syntropy/db/store.rb +31 -0
  24. data/lib/syntropy/http/io_extensions.rb +33 -5
  25. data/lib/syntropy/http/server_connection.rb +6 -53
  26. data/lib/syntropy/{module.rb → module_loader.rb} +47 -8
  27. data/lib/syntropy/request/request_info.rb +3 -4
  28. data/lib/syntropy/request/validation.rb +1 -2
  29. data/lib/syntropy/test.rb +13 -1
  30. data/lib/syntropy/version.rb +1 -1
  31. data/lib/syntropy.rb +4 -2
  32. data/syntropy.gemspec +2 -1
  33. data/test/app/_hook.rb +1 -1
  34. data/test/app/by_method.rb +9 -0
  35. data/test/app_setup/_setup.rb +7 -0
  36. data/test/app_setup/index.rb +1 -0
  37. data/test/app_with_schema/_schema/2026-01-02-foo.rb +12 -0
  38. data/test/app_with_schema/_schema/2026-05-30-bar.rb +7 -0
  39. data/test/schema/2026-01-02-foo.rb +12 -0
  40. data/test/schema/2026-05-30-bar.rb +7 -0
  41. data/test/test_app.rb +58 -3
  42. data/test/{test_connection_pool.rb → test_db_connection_pool.rb} +7 -2
  43. data/test/test_db_schema.rb +96 -0
  44. data/test/test_db_store.rb +24 -0
  45. data/test/test_http_protocol.rb +250 -0
  46. data/test/test_http_server_connection.rb +10 -19
  47. data/test/test_json_api.rb +1 -1
  48. data/test/{test_module.rb → test_module_loader.rb} +31 -0
  49. data/test/test_request.rb +7 -4
  50. data/test/test_server.rb +9 -13
  51. metadata +48 -12
  52. data/lib/syntropy/connection_pool.rb +0 -61
data/test/test_server.rb CHANGED
@@ -89,12 +89,12 @@ class ServerTest < Minitest::Test
89
89
  req.respond("method: #{req.method}")
90
90
  }
91
91
 
92
- write_http_request "GET /foo HTTP/1.1\r\nServer: foo.com\r\n\r\nSCHmet /bar HTTP/1.1\r\n\r\n"
92
+ write_http_request "GET /foo HTTP/1.1\r\nServer: foo.com\r\n\r\nPUT /bar HTTP/1.1\r\n\r\n"
93
93
 
94
94
  @machine.sleep(0.1)
95
95
  response = read_client_side
96
96
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nmethod: get\r\n0\r\n\r\n" +
97
- "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\ne\r\nmethod: schmet\r\n0\r\n\r\n"
97
+ "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nmethod: put\r\n0\r\n\r\n"
98
98
  assert_equal(expected, response)
99
99
  end
100
100
 
@@ -107,7 +107,7 @@ class ServerTest < Minitest::Test
107
107
  raise
108
108
  end
109
109
 
110
- write_http_request "GET /foo HTTP/1.1\r\nServer: foo.com\r\n\r\nSCHMET /bar HTTP/1.1\r\n\r\n"
110
+ write_http_request "GET /foo HTTP/1.1\r\nServer: foo.com\r\n\r\nPUT /bar HTTP/1.1\r\n\r\n"
111
111
 
112
112
  @machine.sleep(0.01)
113
113
  @server.stop!
@@ -132,7 +132,7 @@ class ServerTest < Minitest::Test
132
132
  Server: foo.com
133
133
  Content-Length: 3
134
134
 
135
- abcSCHMOST /bar HTTP/1.1
135
+ abcPOST /bar HTTP/1.1
136
136
  Server: bar.com
137
137
  Content-Length: 6
138
138
 
@@ -148,7 +148,6 @@ class ServerTest < Minitest::Test
148
148
  assert_equal({
149
149
  ':method' => 'post',
150
150
  ':path' => '/foo',
151
- ':protocol' => 'http/1.1',
152
151
  'server' => 'foo.com',
153
152
  'content-length' => '3',
154
153
  ':body-done-reading' => true,
@@ -160,13 +159,12 @@ class ServerTest < Minitest::Test
160
159
  req1 = @reqs.shift
161
160
  headers = req1.headers
162
161
  assert_equal({
163
- ':method' => 'schmost',
162
+ ':method' => 'post',
164
163
  ':path' => '/bar',
165
- ':protocol' => 'http/1.1',
166
164
  'server' => 'bar.com',
167
165
  'content-length' => '6',
168
166
  ':body-done-reading' => true,
169
- ':tx' => 59,
167
+ ':tx' => 56,
170
168
  }, headers)
171
169
  body = @bodies.shift
172
170
  assert_equal 'defghi', body
@@ -196,7 +194,7 @@ class ServerTest < Minitest::Test
196
194
  de
197
195
  0
198
196
 
199
- SCHMOST /bar HTTP/1.1
197
+ POST /bar HTTP/1.1
200
198
  Server: bar.com
201
199
  Transfer-Encoding: chunked
202
200
 
@@ -218,7 +216,6 @@ class ServerTest < Minitest::Test
218
216
  assert_equal({
219
217
  ':method' => 'post',
220
218
  ':path' => '/foo',
221
- ':protocol' => 'http/1.1',
222
219
  'server' => 'foo.com',
223
220
  'transfer-encoding' => 'chunked',
224
221
  ':body-done-reading' => true,
@@ -230,13 +227,12 @@ class ServerTest < Minitest::Test
230
227
  req1 = @reqs.shift
231
228
  headers = req1.headers
232
229
  assert_equal({
233
- ':method' => 'schmost',
230
+ ':method' => 'post',
234
231
  ':path' => '/bar',
235
- ':protocol' => 'http/1.1',
236
232
  'server' => 'bar.com',
237
233
  'transfer-encoding' => 'chunked',
238
234
  ':body-done-reading' => true,
239
- ':tx' => 59
235
+ ':tx' => 56
240
236
  }, headers)
241
237
  body = @bodies.shift
242
238
  assert_equal '123456789abcdefghijklmnopqrstuv', body
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.31.0
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -52,21 +52,21 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: 1.0.2
54
54
  - !ruby/object:Gem::Dependency
55
- name: escape_utils
55
+ name: json
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - '='
58
+ - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 1.3.0
60
+ version: '0'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - '='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: 1.3.0
67
+ version: '0'
68
68
  - !ruby/object:Gem::Dependency
69
- name: json
69
+ name: logger
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
@@ -80,7 +80,7 @@ dependencies:
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  - !ruby/object:Gem::Dependency
83
- name: logger
83
+ name: irb
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
@@ -121,6 +121,20 @@ dependencies:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
123
  version: 13.3.1
124
+ - !ruby/object:Gem::Dependency
125
+ name: solargraph
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
124
138
  email: sharon@noteflakes.com
125
139
  executables:
126
140
  - syntropy
@@ -140,6 +154,7 @@ files:
140
154
  - TODO.md
141
155
  - bin/syntropy
142
156
  - cmd/_banner.rb
157
+ - cmd/console.rb
143
158
  - cmd/help.rb
144
159
  - cmd/serve.rb
145
160
  - cmd/setup/template/site/.gitignore
@@ -175,6 +190,15 @@ files:
175
190
  - examples/basic/favicon.ico
176
191
  - examples/basic/index.md
177
192
  - examples/basic/templates.rb
193
+ - examples/blog/app/_layout/default.rb
194
+ - examples/blog/app/_lib/post_store.rb
195
+ - examples/blog/app/_schema/2026-01-01-initial.rb
196
+ - examples/blog/app/_setup.rb
197
+ - examples/blog/app/index.rb
198
+ - examples/blog/app/posts/[id]/edit.rb
199
+ - examples/blog/app/posts/[id]/index.rb
200
+ - examples/blog/app/posts/index.rb
201
+ - examples/blog/app/posts/new.rb
178
202
  - examples/mcp-oauth/.ruby-version
179
203
  - examples/mcp-oauth/Gemfile
180
204
  - examples/mcp-oauth/README.md
@@ -202,7 +226,9 @@ files:
202
226
  - lib/syntropy/applets/builtin/json_api.js
203
227
  - lib/syntropy/applets/builtin/ping.rb
204
228
  - lib/syntropy/applets/builtin/req.rb
205
- - lib/syntropy/connection_pool.rb
229
+ - lib/syntropy/db/connection_pool.rb
230
+ - lib/syntropy/db/schema.rb
231
+ - lib/syntropy/db/store.rb
206
232
  - lib/syntropy/dev_mode.rb
207
233
  - lib/syntropy/errors.rb
208
234
  - lib/syntropy/http.rb
@@ -216,7 +242,7 @@ files:
216
242
  - lib/syntropy/logger.rb
217
243
  - lib/syntropy/markdown.rb
218
244
  - lib/syntropy/mime_types.rb
219
- - lib/syntropy/module.rb
245
+ - lib/syntropy/module_loader.rb
220
246
  - lib/syntropy/papercraft_extensions.rb
221
247
  - lib/syntropy/request.rb
222
248
  - lib/syntropy/request/mock_adapter.rb
@@ -247,6 +273,7 @@ files:
247
273
  - test/app/bad_mod.rb
248
274
  - test/app/bar.rb
249
275
  - test/app/baz.rb
276
+ - test/app/by_method.rb
250
277
  - test/app/deps.rb
251
278
  - test/app/index.html
252
279
  - test/app/mod/bar/index+.rb
@@ -260,20 +287,29 @@ files:
260
287
  - test/app_multi_site/_site.rb
261
288
  - test/app_multi_site/bar.baz/index.html
262
289
  - test/app_multi_site/foo.bar/index.html
290
+ - test/app_setup/_setup.rb
291
+ - test/app_setup/index.rb
292
+ - test/app_with_schema/_schema/2026-01-02-foo.rb
293
+ - test/app_with_schema/_schema/2026-05-30-bar.rb
263
294
  - test/bm_router_proc.rb
264
295
  - test/bm_server.rb
265
296
  - test/helper.rb
266
297
  - test/run.rb
298
+ - test/schema/2026-01-02-foo.rb
299
+ - test/schema/2026-05-30-bar.rb
267
300
  - test/test_app.rb
268
301
  - test/test_caching.rb
269
- - test/test_connection_pool.rb
302
+ - test/test_db_connection_pool.rb
303
+ - test/test_db_schema.rb
304
+ - test/test_db_store.rb
270
305
  - test/test_errors.rb
271
306
  - test/test_http_client.rb
272
307
  - test/test_http_client_connection.rb
308
+ - test/test_http_protocol.rb
273
309
  - test/test_http_server_connection.rb
274
310
  - test/test_json_api.rb
275
311
  - test/test_mock_adapter.rb
276
- - test/test_module.rb
312
+ - test/test_module_loader.rb
277
313
  - test/test_request.rb
278
314
  - test/test_response.rb
279
315
  - test/test_routing_tree.rb
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'extralite'
4
-
5
- module Syntropy
6
- class ConnectionPool
7
- attr_reader :count
8
-
9
- def initialize(machine, fn, max_conn)
10
- @machine = machine
11
- @fn = fn
12
- @count = 0
13
- @max_conn = max_conn
14
- @queue = UM::Queue.new
15
- @key = :"db_#{fn}"
16
- end
17
-
18
- def with_db
19
- if (db = Thread.current[@key])
20
- @machine.snooze
21
- return yield(db)
22
- end
23
-
24
- db = checkout
25
- begin
26
- Thread.current[@key] = db
27
- yield(db)
28
- ensure
29
- Thread.current[@key] = nil
30
- checkin(db)
31
- end
32
- end
33
-
34
- def query(sql, *, **, &)
35
- with_db { it.query(sql, *, **, &) }
36
- end
37
-
38
- def execute(sql, *, **)
39
- with_db { it.execute(sql, *, **) }
40
- end
41
-
42
- private
43
-
44
- def checkout
45
- return make_db_instance if @queue.count == 0 && @count < @max_conn
46
-
47
- @machine.shift(@queue)
48
- end
49
-
50
- def checkin(db)
51
- @machine.push(@queue, db)
52
- end
53
-
54
- def make_db_instance
55
- Extralite::Database.new(@fn, wal: true).tap do
56
- @count += 1
57
- it.on_progress(mode: :at_least_once, period: 320, tick: 10) { @machine.snooze }
58
- end
59
- end
60
- end
61
- end