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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a39afb5d39d1a1c9b95e2e242b9ce55144ba6923ad4b0addee3c6c005d314ead
4
- data.tar.gz: 0b067b50a4f27381ba495a32d8c8e471e4a64374d6eee3c62d25fb30aaa10a24
3
+ metadata.gz: 29b7fe87a7350db0c154f0ee25b1c6992c81aead3938cec537e383dc5e3f6a62
4
+ data.tar.gz: 7dcf8de792102d368aefed72ced1ac3c2e5afd1fe0aea3ac106150fa59862a6b
5
5
  SHA512:
6
- metadata.gz: 9768274a2d09c8f4068625006660403e98655cfa7d7d742ed75f3ce0e31abfc0410f301d16d8d8910fcc94d7947008238a730b19b514342cbb67dac8669a4e76
7
- data.tar.gz: 76a2d90674f7ebc34f8162e3435d81edb1ca56022ef7d490bcc6fcfa0041529f1ace321233451dd7df40867b05eb83327984634461f0986dd650db3e0913af6c
6
+ metadata.gz: 904b3740de777c83a631b4b0b37f72ee22b698b2f1618110a906c6ca5adf979f0c46c84af08d1ae228f8b9aa90bcb54093e88de9c18dcf3961d72ea7e0d94d2c
7
+ data.tar.gz: '0081303c531b38423d94f43423efcdcd80852201b0826f0078b276618b03dc7cde09e24dd599e8cee58ddf4ae8ce1f226d4684b4aa8592407728b9f911e30cc5'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.34.0 2026-06-03
2
+
3
+ - Streamline options for CLI commands
4
+ - Remove `App#setup_db`
5
+ - Add support for config modules (e.g. `config/development.rb`)
6
+ - Add support for running modes: production, development, test
7
+
1
8
  # 0.33.0 2026-06-02
2
9
 
3
10
  - Fix `ModuleLoader` to load a module only once
data/cmd/console.rb CHANGED
@@ -2,16 +2,28 @@
2
2
 
3
3
  require_relative '../lib/syntropy'
4
4
  require 'optparse'
5
+ require 'fileutils'
5
6
 
6
7
  env = {
8
+ app_root: File.join(FileUtils.pwd, 'app'),
9
+ config_root: File.join(FileUtils.pwd, 'config'),
10
+ mode: ENV['SYNTROPY_MODE'] || 'development',
7
11
  mount_path: '/',
8
- logger: true,
9
12
  builtin_applet_path: '/.syntropy',
13
+ logger: true,
10
14
  watch_files: true
11
15
  }
12
16
 
13
17
  parser = OptionParser.new do |o|
14
- o.banner = 'Usage: syntropy serve [options] DIR'
18
+ o.banner = 'Usage: syntropy serve [options]'
19
+
20
+ o.on('-a', '--app PATH', 'Set app directory (default: ./app') do |path|
21
+ env[:app_root] = path
22
+ end
23
+
24
+ o.on('-c', '--config PATH', 'Set config directory (default: ./config') do |path|
25
+ env[:config_root] = path
26
+ end
15
27
 
16
28
  o.on('-h', '--help', 'Show this help message') do
17
29
  puts o
@@ -19,7 +31,6 @@ parser = OptionParser.new do |o|
19
31
  end
20
32
 
21
33
  o.on('-m', '--mount PATH', 'Set mount path (default: /)') do |path|
22
- p mount: path
23
34
  env[:mount_path] = path
24
35
  env[:builtin_applet_path] = File.join(path, '.syntropy')
25
36
  end
@@ -43,11 +54,11 @@ rescue StandardError => e
43
54
  exit
44
55
  end
45
56
 
46
- $syntropy_dev_mode = env[:dev_mode]
47
- env[:root_dir] = (ARGV.shift || '.').gsub(/\/$/, '')
57
+ Syntropy.dev_mode = env[:mode] == 'development'
58
+ Syntropy.load_config(env)
48
59
 
49
- if !File.directory?(env[:root_dir])
50
- puts "#{File.expand_path(env[:root_dir])} Not a directory"
60
+ if !File.directory?(env[:app_root])
61
+ puts "#{File.expand_path(env[:app_root])} Not a directory"
51
62
  exit
52
63
  end
53
64
 
data/cmd/serve.rb CHANGED
@@ -2,19 +2,27 @@
2
2
 
3
3
  require_relative '../lib/syntropy'
4
4
  require 'optparse'
5
+ require 'fileutils'
5
6
 
6
7
  env = {
7
- mount_path: '/',
8
- logger: true,
9
- builtin_applet_path: '/.syntropy',
10
- server_extensions: {
8
+ app_root: File.join(FileUtils.pwd, 'app'),
9
+ config_root: File.join(FileUtils.pwd, 'config'),
10
+ mode: ENV['SYNTROPY_MODE'] || 'development',
11
+ mount_path: '/',
12
+ builtin_applet_path: '/.syntropy',
13
+ logger: true,
14
+ server_extensions: {
11
15
  date: true,
12
16
  name: 'Syntropy'
13
17
  }
14
18
  }
15
19
 
16
20
  parser = OptionParser.new do |o|
17
- o.banner = 'Usage: syntropy serve [options] DIR'
21
+ o.banner = 'Usage: syntropy serve [options]'
22
+
23
+ o.on('-a', '--app PATH', 'Set app directory (default: ./app') do |path|
24
+ env[:app_root] = path
25
+ end
18
26
 
19
27
  o.on('-b', '--bind BIND', String,
20
28
  'Bind address (default: http://0.0.0.0:1234). You can specify this flag multiple times to bind to multiple addresses.') do
@@ -22,14 +30,8 @@ parser = OptionParser.new do |o|
22
30
  env[:bind] << it
23
31
  end
24
32
 
25
- o.on('-s', '--silent', 'Silent mode') do
26
- env[:banner] = nil
27
- env[:logger] = nil
28
- end
29
-
30
- o.on('-d', '--dev', 'Development mode') do
31
- env[:dev_mode] = true
32
- env[:watch_files] = true
33
+ o.on('-c', '--config PATH', 'Set config directory (default: ./config') do |path|
34
+ env[:config_root] = path
33
35
  end
34
36
 
35
37
  o.on('-h', '--help', 'Show this help message') do
@@ -50,6 +52,11 @@ parser = OptionParser.new do |o|
50
52
  env[:server_extensions] = nil
51
53
  end
52
54
 
55
+ o.on('-s', '--silent', 'Silent mode') do
56
+ env[:banner] = nil
57
+ env[:logger] = nil
58
+ end
59
+
53
60
  o.on('-v', '--version', 'Show version') do
54
61
  require 'syntropy/version'
55
62
  puts "Syntropy version #{Syntropy::VERSION}"
@@ -71,11 +78,12 @@ rescue StandardError => e
71
78
  exit
72
79
  end
73
80
 
74
- $syntropy_dev_mode = env[:dev_mode]
75
- env[:root_dir] = (ARGV.shift || '.').gsub(/\/$/, '')
81
+ Syntropy.dev_mode = env[:mode] == 'development'
82
+ Syntropy.load_config(env)
83
+ env[:watch_files] = Syntropy.dev_mode
76
84
 
77
- if !File.directory?(env[:root_dir])
78
- puts "#{File.expand_path(env[:root_dir])} Not a directory"
85
+ if !File.directory?(env[:app_root])
86
+ puts "#{File.expand_path(env[:app_root])} Not a directory"
79
87
  exit
80
88
  end
81
89
 
@@ -87,7 +95,7 @@ env[:machine] = Syntropy.machine = UM.new
87
95
  env[:logger] = env[:logger] && Syntropy::Logger.new(env[:machine], **env)
88
96
 
89
97
  require 'syntropy/version'
90
- require 'syntropy/dev_mode' if env[:dev_mode]
98
+ require 'syntropy/dev_mode' if Syntropy.dev_mode
91
99
 
92
100
  app = Syntropy::App.load(env)
93
101
  Syntropy.run(env) { app.call(it) }
data/cmd/test.rb CHANGED
@@ -5,15 +5,25 @@ require 'optparse'
5
5
 
6
6
  pwd = FileUtils.pwd
7
7
  env = {
8
- root_dir: File.join(pwd, 'app'),
9
- test_dir: File.join(pwd, 'test'),
10
- mount_path: '/'
8
+ app_root: File.join(FileUtils.pwd, 'app'),
9
+ config_root: File.join(FileUtils.pwd, 'config'),
10
+ test_root: File.join(pwd, 'test'),
11
+ mode: 'test',
12
+ mount_path: '/'
11
13
  }
12
14
  MINITEST_ARGV = []
13
15
 
14
16
  parser = OptionParser.new do |o|
15
17
  o.banner = 'Usage: syntropy test [options]'
16
18
 
19
+ o.on('-a', '--app PATH', 'Set app directory (default: ./app') do |path|
20
+ env[:app_root] = path
21
+ end
22
+
23
+ o.on('-c', '--config PATH', 'Set config directory (default: ./config') do |path|
24
+ env[:config_root] = path
25
+ end
26
+
17
27
  o.on('-h', '--help', 'Show this help message') do
18
28
  puts o
19
29
  exit
@@ -24,35 +34,31 @@ parser = OptionParser.new do |o|
24
34
  env[:builtin_applet_path] = File.join(path, '.syntropy')
25
35
  end
26
36
 
27
- o.on('-w', '--watch', 'Watch for file changes') do
28
- env[:watch_mode] = true
37
+ o.on('-n', '--name NAME', 'Specify test to run') do |name|
38
+ MINITEST_ARGV << '--name' << name
29
39
  end
30
40
 
31
- o.on('-a', '--app PATH', 'Set app root (default: ./app)') do |path|
32
- env[:root_dir] = path
41
+ o.on('-s', '--seed SEED', 'Specify random seed') do |seed|
42
+ MINITEST_ARGV << '--seed' << seed
33
43
  end
34
44
 
35
- o.on('-t', '--test PATH', 'Set test root (default: ./test)') do |path|
36
- env[:test_dir] = path
37
- end
38
-
39
- o.on('-n', '--name NAME', 'Specify test to run') do |name|
40
- MINITEST_ARGV << '--name' << name
45
+ o.on('-t', '--test PATH', 'Set test directory (default: ./test)') do |path|
46
+ env[:test_root] = path
41
47
  end
42
48
 
43
49
  o.on('-V', '--verbose', 'Verbose test output') do
44
50
  MINITEST_ARGV << '--verbose'
45
51
  end
46
52
 
47
- o.on('-s', '--seed SEED', 'Specify random seed') do |seed|
48
- MINITEST_ARGV << '--seed' << seed
49
- end
50
-
51
53
  o.on('-v', '--version', 'Show version') do
52
54
  require 'syntropy/version'
53
55
  puts "Syntropy version #{Syntropy::VERSION}"
54
56
  exit
55
57
  end
58
+
59
+ o.on('-w', '--watch', 'Watch for file changes') do
60
+ env[:watch_mode] = true
61
+ end
56
62
  end
57
63
 
58
64
  argv_copy = ARGV.dup
@@ -71,26 +77,33 @@ end
71
77
  require_relative '../lib/syntropy'
72
78
  require_relative '../lib/syntropy/test'
73
79
 
80
+ Syntropy.load_config(env)
81
+
74
82
  $stdout.sync = true
75
83
  $stderr.sync = true
76
84
 
77
- Dir.glob("#{env[:test_dir]}/test_*.rb").each { require(it) }
85
+ Dir.glob("#{File.expand_path(env[:test_root])}/test_*.rb").each { require(it) }
86
+
87
+ def restart_on_file_change(machine, dir, restart_argv)
78
88
 
79
- def watch_for_file_changes(machine)
80
- machine.write(UM::STDOUT_FILENO, "Waiting for file changes in #{FileUtils.pwd}\n")
81
- machine.file_watch(FileUtils.pwd, UM::IN_CREATE | UM::IN_DELETE | UM::IN_CLOSE_WRITE) {
89
+ machine.file_watch(dir, UM::IN_CREATE | UM::IN_DELETE | UM::IN_CLOSE_WRITE) {
82
90
  machine.write(UM::STDOUT_FILENO, "File changed: #{it[:fn]}\n")
83
91
  break
84
92
  }
93
+ exec('ruby', __FILE__, *restart_argv)
85
94
  end
86
95
 
87
- Syntropy::Test.env=(env)
96
+ Syntropy::Test.env = (env)
88
97
  Minitest.run MINITEST_ARGV
89
98
 
90
99
  if env[:watch_mode]
91
100
  m = UM.new(size: 4)
92
101
  m.write(UM::STDOUT_FILENO, "\n")
93
102
  trap('SIGINT') { m.write(UM::STDOUT_FILENO, "\n"); exit! }
94
- watch_for_file_changes(m)
95
- exec("ruby", __FILE__, *argv_copy)
103
+
104
+ machine.write(UM::STDOUT_FILENO, "Waiting for file changes...\n")
105
+ m.join(
106
+ m.spin { restart_on_file_change(m, env[:app_root], argv_copy) },
107
+ m.spin { restart_on_file_change(m, env[:test_root], argv_copy) }
108
+ )
96
109
  end
@@ -0,0 +1 @@
1
+ storage/*
@@ -0,0 +1,13 @@
1
+ export self
2
+
3
+ def connection_pool
4
+ @connection_pool ||= DB::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
5
+ end
6
+
7
+ def schema
8
+ DB::Schema.new(module_loader: @module_loader, schema_root: '_schema')
9
+ end
10
+
11
+ def migrate!
12
+ schema.apply(connection_pool)
13
+ end
@@ -1,3 +1,5 @@
1
+ DB = import '/_lib/database'
2
+
1
3
  class PostStore < Syntropy::DB::Store
2
4
  # @return [Integer] post id
3
5
  def create(title, body)
@@ -44,4 +46,4 @@ class PostStore < Syntropy::DB::Store
44
46
  end
45
47
  end
46
48
 
47
- export PostStore.new(@app.connection_pool)
49
+ export PostStore.new(DB.connection_pool)
@@ -1,11 +1,11 @@
1
- @post_store = import '/_lib/post_store'
1
+ @posts = import '/_lib/posts'
2
2
  @layout = import '/_layout/default'
3
3
 
4
4
  export http_methods
5
5
 
6
6
  def get(req)
7
7
  id = req.route_params['id'].to_i
8
- post = @post_store.get(id)
8
+ post = @posts.get(id)
9
9
  raise Syntropy::Error.not_found if !post
10
10
 
11
11
  req.respond_html(
@@ -1,11 +1,11 @@
1
- @post_store = import '/_lib/post_store'
1
+ @posts = import '/_lib/posts'
2
2
  @layout = import '/_layout/default'
3
3
 
4
4
  export http_methods
5
5
 
6
6
  def get(req)
7
7
  id = req.route_params['id'].to_i
8
- post = @post_store.get(id)
8
+ post = @posts.get(id)
9
9
  raise Syntropy::Error.not_found if !post
10
10
 
11
11
  req.respond_html(
@@ -21,7 +21,7 @@ def post(req)
21
21
  title = req.validate(data['title'], String, /.+/)
22
22
  body = req.validate(data['body'], String, /.+/)
23
23
 
24
- updated = @post_store.update(id, title, body)
24
+ updated = @posts.update(id, title, body)
25
25
  raise BadRequestError, "Failed to update post" if updated != 1
26
26
 
27
27
  req.flash[:notice] = 'Post was successfully updated.'
@@ -31,7 +31,7 @@ end
31
31
  def delete(req)
32
32
  id = req.route_params['id'].to_i
33
33
 
34
- deleted = @post_store.delete(id)
34
+ deleted = @posts.delete(id)
35
35
  raise BadRequestError, "Failed to delete post" if deleted != 1
36
36
 
37
37
  req.flash[:notice] = 'Post was successfully destroyed.'
@@ -1,10 +1,10 @@
1
- @post_store = import '_lib/post_store'
1
+ @posts = import '_lib/posts'
2
2
  @layout = import '_layout/default'
3
3
 
4
4
  export http_methods
5
5
 
6
6
  def get(req)
7
- posts = @post_store.get_all
7
+ posts = @posts.get_all
8
8
  req.respond_html(
9
9
  @template.render(posts:, req:)
10
10
  )
@@ -14,14 +14,14 @@ def post(req)
14
14
  data = req.get_form_data
15
15
  title = req.validate(data['title'], String, /.+/)
16
16
  body = req.validate(data['body'], String, /.+/)
17
- id = @post_store.create(title, body)
17
+ id = @posts.create(title, body)
18
18
 
19
19
  req.flash[:notice] = 'Post was successfully created.'
20
20
  req.redirect("posts/#{id}")
21
21
  end
22
22
 
23
23
  @template = @layout.apply { |**props|
24
- h1 "My blog"
24
+ h1 "My awesome blog"
25
25
  p props[:req]&.flash[:notice], style: 'color: green'
26
26
  props[:posts].each { |post|
27
27
  div {
@@ -1,4 +1,4 @@
1
- @post_store = import '/_lib/post_store'
1
+ @posts = import '/_lib/posts'
2
2
  @layout = import '/_layout/default'
3
3
 
4
4
  export http_methods
@@ -0,0 +1,5 @@
1
+ export(
2
+ storage: {
3
+ path: ENV['DATABASE_PATH'] || 'storage/development.db'
4
+ }
5
+ )
@@ -0,0 +1,4 @@
1
+ export(
2
+ storage:
3
+ path: ENV['DATABASE_PATH'] || 'storage/production.db'
4
+ )
@@ -0,0 +1,5 @@
1
+ export({
2
+ storage: {
3
+ path: ENV['DATABASE_PATH'] || Syntropy.tmp_path('test-db')
4
+ }
5
+ })
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PostsTest < Syntropy::Test
4
+ def setup
5
+ super
6
+ @posts = load_module('/_lib/posts')
7
+ end
8
+
9
+ def test_get_all
10
+ assert_equal [], @posts.get_all
11
+
12
+ @posts.create('foo', 'bar')
13
+
14
+ assert_equal [
15
+ { id: 1, title: 'foo', body: 'bar' }
16
+ ], @posts.get_all
17
+ end
18
+
19
+ def test_get
20
+ assert_nil @posts.get(1)
21
+ assert_nil @posts.get(2)
22
+
23
+ @posts.create('foo', 'bar')
24
+
25
+ assert_equal(
26
+ { id: 1, title: 'foo', body: 'bar' },
27
+ @posts.get(1)
28
+ )
29
+ assert_nil @posts.get(2)
30
+
31
+ @posts.create('bar', 'baz')
32
+
33
+ assert_equal(
34
+ { id: 1, title: 'foo', body: 'bar' },
35
+ @posts.get(1)
36
+ )
37
+ assert_equal(
38
+ { id: 2, title: 'bar', body: 'baz' },
39
+ @posts.get(2)
40
+ )
41
+ end
42
+
43
+ def test_update
44
+ assert_equal 0, @posts.update(1, 'qqq', 'ttt')
45
+
46
+ @posts.create('foo', 'bar')
47
+ assert_equal 1, @posts.update(1, 'qqq', 'ttt')
48
+
49
+ assert_equal [
50
+ { id: 1, title: 'qqq', body: 'ttt' }
51
+ ], @posts.get_all
52
+ end
53
+
54
+ def test_delete
55
+ assert_equal 0, @posts.delete(1)
56
+
57
+ @posts.create('foo', 'bar')
58
+ @posts.create('bar', 'baz')
59
+
60
+ assert_equal 1, @posts.delete(1)
61
+ assert_equal [
62
+ { id: 2, title: 'bar', body: 'baz' }
63
+ ], @posts.get_all
64
+ end
65
+ end
@@ -65,7 +65,7 @@ rescue ValidationError => e
65
65
  },
66
66
  ':status' => Syntropy::HTTP::BAD_REQUEST
67
67
  )
68
- rescue => e
68
+ rescue StandardError => e
69
69
  status = Syntropy::Error.http_status(e)
70
70
  raise if status == HTTP::INTERNAL_SERVER_ERROR
71
71