syntropy 0.34.4 → 0.36.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 +10 -0
- data/TODO.md +0 -2
- data/bin/syntropy +1 -1
- data/cmd/console.rb +1 -1
- data/{examples → cmd/new}/template/.gitignore +1 -0
- data/cmd/new/template/Dockerfile +25 -0
- data/{examples → cmd/new}/template/Gemfile +1 -1
- data/cmd/new/template/README.md +40 -0
- data/cmd/new/template/app/_lib/storage.rb +13 -0
- data/cmd/new/template/docker-compose.yml +46 -0
- data/cmd/new.rb +46 -0
- data/examples/blog/app/_lib/posts.rb +3 -3
- data/examples/blog/app/_lib/storage.rb +13 -0
- data/lib/syntropy/module_loader.rb +5 -1
- data/lib/syntropy/{db → storage}/connection_pool.rb +2 -1
- data/lib/syntropy/storage/kv_store.rb +68 -0
- data/lib/syntropy/storage/prepared_query.rb +36 -0
- data/lib/syntropy/{db → storage}/schema.rb +1 -1
- data/lib/syntropy/{db → storage}/store.rb +1 -1
- data/lib/syntropy/storage.rb +6 -0
- data/lib/syntropy/test.rb +3 -1
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +2 -4
- data/test/{test_db_connection_pool.rb → test_connection_pool.rb} +4 -4
- data/test/test_kv_store.rb +84 -0
- data/test/{test_db_schema.rb → test_schema.rb} +5 -5
- data/test/{test_db_store.rb → test_store.rb} +3 -3
- metadata +28 -43
- data/cmd/setup/template/site/.gitignore +0 -57
- data/cmd/setup/template/site/Dockerfile +0 -32
- data/cmd/setup/template/site/Gemfile +0 -3
- data/cmd/setup/template/site/README.md +0 -0
- data/cmd/setup/template/site/bin/console +0 -0
- data/cmd/setup/template/site/bin/restart +0 -0
- data/cmd/setup/template/site/bin/server +0 -0
- data/cmd/setup/template/site/bin/start +0 -0
- data/cmd/setup/template/site/bin/stop +0 -0
- data/cmd/setup/template/site/docker-compose.yml +0 -51
- data/cmd/setup/template/site/proxy/Dockerfile +0 -5
- data/cmd/setup/template/site/proxy/etc/Caddyfile +0 -7
- data/cmd/setup/template/site/proxy/etc/tls_auto +0 -2
- data/cmd/setup/template/site/proxy/etc/tls_cloudflare +0 -4
- data/cmd/setup/template/site/proxy/etc/tls_custom +0 -1
- data/cmd/setup/template/site/proxy/etc/tls_selfsigned +0 -1
- data/cmd/setup/template/site/site/_layout/default.rb +0 -11
- data/cmd/setup/template/site/site/about.md +0 -6
- data/cmd/setup/template/site/site/articles/cage.rb +0 -29
- data/cmd/setup/template/site/site/articles/index.rb +0 -3
- data/cmd/setup/template/site/site/assets/css/style.css +0 -40
- data/cmd/setup/template/site/site/assets/img/syntropy.png +0 -0
- data/cmd/setup/template/site/site/index.rb +0 -15
- data/examples/blog/app/_lib/database.rb +0 -13
- data/examples/template/app/_lib/database.rb +0 -13
- /data/{examples → cmd/new}/template/app/_layout/default.rb +0 -0
- /data/{examples → cmd/new}/template/app/_schema/2026-01-01-initial.rb +0 -0
- /data/{examples → cmd/new}/template/app/assets/style.css +0 -0
- /data/{examples → cmd/new}/template/app/index.rb +0 -0
- /data/{examples → cmd/new}/template/app/test.rb +0 -0
- /data/{examples → cmd/new}/template/config/development.rb +0 -0
- /data/{examples → cmd/new}/template/config/production.rb +0 -0
- /data/{examples → cmd/new}/template/config/test.rb +0 -0
- /data/{examples → cmd/new}/template/test/test_app.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f92ed1375642f12fb92654d872bfde1d07c7ad74be97507af3c1616390b6ce14
|
|
4
|
+
data.tar.gz: 5072d514bc07149f1d26bc900bcc9379970ebbbaf1b88eaa23933189fb684b37
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f77aed02801a7b1c10f67a5ed7fbac9196580bd482c19ca660c81beaf5f2adcba86047635e35f9750d003538b12401962888193c058fbc3023ae88eae9038506
|
|
7
|
+
data.tar.gz: f923ab3aa4e535d5a85a563acf7f97534639ca1ed3d02e2c2b94d9cecef57e06cefc3a72a1ca782d0118b012189298bc3c743b017c0ee2d06be8bbf55d03dc89
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# 0.36.0 2026-06-04
|
|
2
|
+
|
|
3
|
+
- Rename `DB` to `Storage`
|
|
4
|
+
- Add `PreparedQuery`, `KVStore`
|
|
5
|
+
|
|
6
|
+
# 0.35.0 2026-06-04
|
|
7
|
+
|
|
8
|
+
- Add `syntropy new` command
|
|
9
|
+
- Finalize work on new app template
|
|
10
|
+
|
|
1
11
|
# 0.34.4 2026-06-03
|
|
2
12
|
|
|
3
13
|
- Really fix running test in watch mode with docker compose
|
data/TODO.md
CHANGED
data/bin/syntropy
CHANGED
data/cmd/console.rb
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
FROM ruby:4.0-slim AS base
|
|
2
|
+
WORKDIR /syntropy
|
|
3
|
+
RUN apt-get update -qq && apt-get install -y \
|
|
4
|
+
curl \
|
|
5
|
+
build-essential \
|
|
6
|
+
libpq-dev \
|
|
7
|
+
libsqlite3-dev \
|
|
8
|
+
libssl-dev \
|
|
9
|
+
libyaml-dev \
|
|
10
|
+
pkg-config && \
|
|
11
|
+
rm -rf /var/lib/apt/lists /var/cache/apt/archives
|
|
12
|
+
|
|
13
|
+
ENV BUNDLE_PATH="/usr/local/bundle"
|
|
14
|
+
COPY Gemfile Gemfile.lock ./
|
|
15
|
+
RUN bundle install
|
|
16
|
+
|
|
17
|
+
RUN groupadd --system --gid 1000 syntropy && \
|
|
18
|
+
useradd syntropy --uid 1000 --gid 1000 --create-home --shell /bin/bash
|
|
19
|
+
USER 1000:1000
|
|
20
|
+
|
|
21
|
+
EXPOSE 1234
|
|
22
|
+
|
|
23
|
+
# Start the main process
|
|
24
|
+
# CMD ["bash"]
|
|
25
|
+
CMD ["bundle", "exec", "syntropy", "serve"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# My awesome Syntropy app
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
$ bundle install
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Running the web server
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
$ bundle exec syntropy serve
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Starting the app console
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
$ bundle exec syntropy console
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Running tests
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
$ bundle exec syntropy tests
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Usage with Docker Compose
|
|
28
|
+
|
|
29
|
+
You can also run the app on Docker Compose:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# run the app server
|
|
33
|
+
$ docker compose up
|
|
34
|
+
|
|
35
|
+
# run the console
|
|
36
|
+
$ docker compose run --remove-orphans console
|
|
37
|
+
|
|
38
|
+
# run tests
|
|
39
|
+
$ docker compose run --remove-orphans test
|
|
40
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export self
|
|
2
|
+
|
|
3
|
+
def connection_pool
|
|
4
|
+
@connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def schema
|
|
8
|
+
Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def migrate!
|
|
12
|
+
schema.apply(connection_pool)
|
|
13
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#version: "3.8"
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
app_server:
|
|
5
|
+
build: .
|
|
6
|
+
security_opt:
|
|
7
|
+
- seccomp:unconfined
|
|
8
|
+
volumes:
|
|
9
|
+
- .:/syntropy
|
|
10
|
+
ports:
|
|
11
|
+
- "1234:1234"
|
|
12
|
+
stop_signal: SIGINT
|
|
13
|
+
stop_grace_period: 10s
|
|
14
|
+
restart: always
|
|
15
|
+
healthcheck:
|
|
16
|
+
test: "curl 'http://localhost:1234/'"
|
|
17
|
+
interval: "30s"
|
|
18
|
+
timeout: "3s"
|
|
19
|
+
start_period: "5s"
|
|
20
|
+
retries: 3
|
|
21
|
+
console:
|
|
22
|
+
build: .
|
|
23
|
+
command: bundle exec syntropy console
|
|
24
|
+
stdin_open: true # docker run -i
|
|
25
|
+
tty: true
|
|
26
|
+
security_opt:
|
|
27
|
+
- seccomp:unconfined
|
|
28
|
+
profiles:
|
|
29
|
+
- dev
|
|
30
|
+
volumes:
|
|
31
|
+
- .:/syntropy
|
|
32
|
+
stop_signal: SIGINT
|
|
33
|
+
restart: never
|
|
34
|
+
test:
|
|
35
|
+
build: .
|
|
36
|
+
command: bundle exec syntropy test -w
|
|
37
|
+
stdin_open: true # docker run -i
|
|
38
|
+
tty: true
|
|
39
|
+
security_opt:
|
|
40
|
+
- seccomp:unconfined
|
|
41
|
+
profiles:
|
|
42
|
+
- dev
|
|
43
|
+
volumes:
|
|
44
|
+
- .:/syntropy
|
|
45
|
+
stop_signal: SIGINT
|
|
46
|
+
restart: never
|
data/cmd/new.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
parser = OptionParser.new do |o|
|
|
7
|
+
o.banner = 'Usage: syntropy new NAME [options]'
|
|
8
|
+
|
|
9
|
+
o.on('-h', '--help', 'Show this help message') do
|
|
10
|
+
puts o
|
|
11
|
+
exit
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
parser.parse!
|
|
17
|
+
rescue OptionParser::InvalidOption
|
|
18
|
+
puts parser
|
|
19
|
+
exit
|
|
20
|
+
rescue StandardError => e
|
|
21
|
+
p e
|
|
22
|
+
puts e.message
|
|
23
|
+
puts e.backtrace.join("\n")
|
|
24
|
+
exit
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
path = ARGV.shift
|
|
28
|
+
if !path
|
|
29
|
+
$stdout << 'Please enter a name for your app: '
|
|
30
|
+
path = $stdin.gets
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
full_path = File.expand_path(path)
|
|
34
|
+
puts "Creating app in #{full_path}"
|
|
35
|
+
|
|
36
|
+
template_path = File.join(__dir__, 'new/template')
|
|
37
|
+
|
|
38
|
+
begin
|
|
39
|
+
`mkdir -p "#{path}"`
|
|
40
|
+
`cp -r #{template_path}/* "#{path}/"`
|
|
41
|
+
puts "Your app is ready in #{path}"
|
|
42
|
+
rescue => e
|
|
43
|
+
p e
|
|
44
|
+
p e.backtrace
|
|
45
|
+
exit(1)
|
|
46
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
Storage = import '/_lib/storage'
|
|
2
2
|
|
|
3
|
-
class PostStore < Syntropy::
|
|
3
|
+
class PostStore < Syntropy::Storage::Store
|
|
4
4
|
# @return [Integer] post id
|
|
5
5
|
def create(title, body)
|
|
6
6
|
query_single_value <<~SQL, title:, body:
|
|
@@ -46,4 +46,4 @@ class PostStore < Syntropy::DB::Store
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
export PostStore.new(
|
|
49
|
+
export PostStore.new(Storage.connection_pool)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export self
|
|
2
|
+
|
|
3
|
+
def connection_pool
|
|
4
|
+
@connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def schema
|
|
8
|
+
Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def migrate!
|
|
12
|
+
schema.apply(connection_pool)
|
|
13
|
+
end
|
|
@@ -199,7 +199,8 @@ module Syntropy
|
|
|
199
199
|
env[:logger]&.info(message: "Loaded module at #{fn}")
|
|
200
200
|
m
|
|
201
201
|
rescue SyntaxError => e
|
|
202
|
-
|
|
202
|
+
env[:logger]&.error(message: "Error while loading module at #{fn}", error: e)
|
|
203
|
+
STDERR.puts("\n#{e.message}") if !Syntropy.test_mode
|
|
203
204
|
|
|
204
205
|
if (m = e.message.match(/^(.+)\: syntax/))
|
|
205
206
|
location = m[1]
|
|
@@ -209,6 +210,9 @@ module Syntropy
|
|
|
209
210
|
else
|
|
210
211
|
raise e
|
|
211
212
|
end
|
|
213
|
+
rescue => e
|
|
214
|
+
env[:logger]&.error(message: "Error while loading module at #{fn}", error: e)
|
|
215
|
+
raise e
|
|
212
216
|
end
|
|
213
217
|
|
|
214
218
|
# Initializes a module with the given environment hash.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'syntropy/storage/store'
|
|
4
|
+
|
|
5
|
+
module Syntropy
|
|
6
|
+
module Storage
|
|
7
|
+
# The KVStore class implements an SQLite-backed key-value store
|
|
8
|
+
class KVStore < Store
|
|
9
|
+
attr_reader :q_get, :q_set
|
|
10
|
+
|
|
11
|
+
def self.apply_schema(db, table_name)
|
|
12
|
+
db.execute <<~SQL
|
|
13
|
+
create table if not exists #{table_name} (key text primary key, value, expires float);
|
|
14
|
+
create index if not exists idx_#{table_name}_expires on #{table_name} (expires) where expires is not null;
|
|
15
|
+
SQL
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize(connection_pool, table_name)
|
|
19
|
+
super(connection_pool)
|
|
20
|
+
@table_name = table_name
|
|
21
|
+
|
|
22
|
+
setup_queries
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get(db, key)
|
|
26
|
+
db[@q_get].bind(key).next
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set(db, key, value)
|
|
30
|
+
db[@q_set].execute(key, value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def setex(db, key, value, ttl)
|
|
34
|
+
db[@q_setex].execute(key, value, ttl ? Time.now.to_f + ttl : nil)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sweep(db)
|
|
38
|
+
db[@q_sweep].execute(Time.now.to_f)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def setup_queries
|
|
44
|
+
@q_get = Storage.prepare_splat <<~SQL
|
|
45
|
+
select value from #{@table_name}
|
|
46
|
+
where key = ?
|
|
47
|
+
SQL
|
|
48
|
+
|
|
49
|
+
@q_set = Storage.prepare <<~SQL
|
|
50
|
+
insert into #{@table_name} (key, value)
|
|
51
|
+
values($1, $2)
|
|
52
|
+
on conflict (key) do update set value = $2, expires = null
|
|
53
|
+
SQL
|
|
54
|
+
|
|
55
|
+
@q_setex = Storage.prepare <<~SQL
|
|
56
|
+
insert into #{@table_name} (key, value, expires)
|
|
57
|
+
values($1, $2, $3)
|
|
58
|
+
on conflict (key) do update set value = $2, expires = $3
|
|
59
|
+
SQL
|
|
60
|
+
|
|
61
|
+
@q_sweep = Storage.prepare <<~SQL
|
|
62
|
+
delete from #{@table_name}
|
|
63
|
+
where expires < ?
|
|
64
|
+
SQL
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'extralite'
|
|
4
|
+
|
|
5
|
+
module Syntropy
|
|
6
|
+
module Storage
|
|
7
|
+
class << self
|
|
8
|
+
def prepare(sql)
|
|
9
|
+
PreparedQuery.new(sql)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def prepare_splat(sql)
|
|
13
|
+
PreparedQuery.new(sql, :prepare_splat)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Represents information about a prepared query
|
|
18
|
+
class PreparedQuery
|
|
19
|
+
attr_reader :sql, :mode
|
|
20
|
+
|
|
21
|
+
def initialize(sql, mode = :prepare)
|
|
22
|
+
@sql = sql
|
|
23
|
+
@mode = mode
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Extensions for Extralite::Database
|
|
28
|
+
module ExtraliteDatabaseExtensions
|
|
29
|
+
def [](pq)
|
|
30
|
+
(@prepared_queries ||= {})[pq] ||= send(pq.mode, pq.sql)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
::Extralite::Database.include(ExtraliteDatabaseExtensions)
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/syntropy/test.rb
CHANGED
|
@@ -118,7 +118,7 @@ module Syntropy
|
|
|
118
118
|
)
|
|
119
119
|
@test_harness = Syntropy::TestHarness.new(@app)
|
|
120
120
|
|
|
121
|
-
@db = load_module('/_lib/
|
|
121
|
+
@db = load_module('/_lib/storage', raise_on_missing: false)
|
|
122
122
|
@db&.migrate!
|
|
123
123
|
end
|
|
124
124
|
|
|
@@ -241,3 +241,5 @@ module Syntropy
|
|
|
241
241
|
|
|
242
242
|
Request.include TestRequestExtensions
|
|
243
243
|
end
|
|
244
|
+
|
|
245
|
+
Syntropy.test_mode = true
|
data/lib/syntropy/version.rb
CHANGED
data/lib/syntropy.rb
CHANGED
|
@@ -9,9 +9,7 @@ require 'syntropy/logger'
|
|
|
9
9
|
require 'syntropy/http'
|
|
10
10
|
require 'syntropy/mime_types'
|
|
11
11
|
require 'syntropy/app'
|
|
12
|
-
require 'syntropy/
|
|
13
|
-
require 'syntropy/db/schema'
|
|
14
|
-
require 'syntropy/db/store'
|
|
12
|
+
require 'syntropy/storage'
|
|
15
13
|
require 'syntropy/errors'
|
|
16
14
|
require 'syntropy/markdown'
|
|
17
15
|
require 'syntropy/module_loader'
|
|
@@ -29,7 +27,7 @@ module Syntropy
|
|
|
29
27
|
extend Utilities
|
|
30
28
|
|
|
31
29
|
class << self
|
|
32
|
-
attr_accessor :machine, :dev_mode
|
|
30
|
+
attr_accessor :machine, :dev_mode, :test_mode
|
|
33
31
|
|
|
34
32
|
# Runs the given block on a separate thread. Use this method for running
|
|
35
33
|
# code that is not fiber-aware (i.e. does not use UringMachine).
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class ConnectionPoolTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
|
-
@cp = Syntropy::
|
|
9
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
10
10
|
|
|
11
11
|
FileUtils.rm(@fn) rescue nil
|
|
12
12
|
@standalone_db = Extralite::Database.new(@fn)
|
|
@@ -19,7 +19,7 @@ class DBConnectionPoolTest < Minitest::Test
|
|
|
19
19
|
@cp.close
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def test_connection_pool_with_db
|
|
23
23
|
assert_equal 0, @cp.count
|
|
24
24
|
|
|
25
25
|
@cp.with_db do |db|
|
|
@@ -74,7 +74,7 @@ class DBConnectionPoolTest < Minitest::Test
|
|
|
74
74
|
assert_equal 4, @cp.count
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def
|
|
77
|
+
def test_connection_pool_with_db_reentrant
|
|
78
78
|
dbs = @cp.with_db do |db1|
|
|
79
79
|
@cp.with_db do |db2|
|
|
80
80
|
[db1, db2]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
require 'syntropy/storage/kv_store'
|
|
5
|
+
|
|
6
|
+
class KVStoreTest < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
@machine = UM.new
|
|
9
|
+
@fn = "/tmp/#{rand(100000)}.db"
|
|
10
|
+
FileUtils.rm(@fn) rescue nil
|
|
11
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def teardown
|
|
15
|
+
@cp.close
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_connection_pool_prepare
|
|
19
|
+
pq = Syntropy::Storage.prepare('select ? as a, 42 as b')
|
|
20
|
+
assert_kind_of Syntropy::Storage::PreparedQuery, pq
|
|
21
|
+
assert_equal 'select ? as a, 42 as b', pq.sql
|
|
22
|
+
assert_equal :prepare, pq.mode
|
|
23
|
+
|
|
24
|
+
assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
|
|
25
|
+
assert_equal [{ a: 'foo', b: 42 }], @cp.with_db { it[pq].bind('foo').to_a }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_connection_pool_prepare_splat
|
|
29
|
+
pq = Syntropy::Storage.prepare_splat('select ?')
|
|
30
|
+
assert_kind_of Syntropy::Storage::PreparedQuery, pq
|
|
31
|
+
assert_equal 'select ?', pq.sql
|
|
32
|
+
assert_equal :prepare_splat, pq.mode
|
|
33
|
+
|
|
34
|
+
assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
|
|
35
|
+
assert_equal ['foo'], @cp.with_db { it[pq].bind('foo').to_a }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_kv_store_apply_schema
|
|
39
|
+
assert_respond_to Syntropy::Storage::KVStore, :apply_schema
|
|
40
|
+
|
|
41
|
+
assert_raises(Extralite::SQLError) { @cp.query('select * from kv') }
|
|
42
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
43
|
+
assert_equal [], @cp.query('select * from kv')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_kv_store_get_set
|
|
47
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
48
|
+
kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
|
|
49
|
+
|
|
50
|
+
@cp.with_db do |db|
|
|
51
|
+
assert_nil kv_store.get(db, 'foo')
|
|
52
|
+
assert_nil kv_store.get(db, 'bar')
|
|
53
|
+
|
|
54
|
+
kv_store.set(db, 'foo', '123')
|
|
55
|
+
|
|
56
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
57
|
+
assert_nil kv_store.get(db, 'bar')
|
|
58
|
+
|
|
59
|
+
kv_store.set(db, 'bar', '456')
|
|
60
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
61
|
+
assert_equal '456', kv_store.get(db, 'bar')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_kv_store_setex_sweep
|
|
66
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
67
|
+
kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
|
|
68
|
+
|
|
69
|
+
@cp.with_db do |db|
|
|
70
|
+
kv_store.set(db, 'foo', '123')
|
|
71
|
+
kv_store.setex(db, 'bar', '456', 0.05)
|
|
72
|
+
assert_equal 0, kv_store.sweep(db)
|
|
73
|
+
|
|
74
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
75
|
+
assert_equal '456', kv_store.get(db, 'bar')
|
|
76
|
+
|
|
77
|
+
sleep 0.1
|
|
78
|
+
assert_equal 1, kv_store.sweep(db)
|
|
79
|
+
|
|
80
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
81
|
+
assert_nil kv_store.get(db, 'bar')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class SchemaTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
9
|
FileUtils.rm(@fn) rescue nil
|
|
10
|
-
@cp = Syntropy::
|
|
10
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def teardown
|
|
@@ -15,7 +15,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def test_db_schema_initial
|
|
18
|
-
schema = Syntropy::
|
|
18
|
+
schema = Syntropy::Storage::Schema.new do
|
|
19
19
|
initial do |db|
|
|
20
20
|
db.execute <<~SQL
|
|
21
21
|
create table posts (
|
|
@@ -35,7 +35,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def test_db_schema_version_blocks
|
|
38
|
-
schema = Syntropy::
|
|
38
|
+
schema = Syntropy::Storage::Schema.new do
|
|
39
39
|
initial do |db|
|
|
40
40
|
db.execute <<~SQL
|
|
41
41
|
create table posts (
|
|
@@ -79,7 +79,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
79
79
|
module_loader = Syntropy::ModuleLoader.new({
|
|
80
80
|
app_root: File.join(__dir__, 'fixtures/schema')
|
|
81
81
|
})
|
|
82
|
-
schema = Syntropy::
|
|
82
|
+
schema = Syntropy::Storage::Schema.new(module_loader:, schema_root: '/')
|
|
83
83
|
|
|
84
84
|
assert_nil schema.current_version(@cp)
|
|
85
85
|
schema.apply(@cp)
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class StoreTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
9
|
FileUtils.rm(@fn) rescue nil
|
|
10
|
-
@cp = Syntropy::
|
|
10
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def teardown
|
|
@@ -15,7 +15,7 @@ class DBStoreTest < Minitest::Test
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def test_db_store
|
|
18
|
-
store = Syntropy::
|
|
18
|
+
store = Syntropy::Storage::Store.new(@cp)
|
|
19
19
|
|
|
20
20
|
assert_equal [{a: 42}], store.query("select ? as a", 42)
|
|
21
21
|
assert_equal({a: 42}, store.query_single_row("select ? as a", 42))
|
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.36.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
@@ -170,30 +170,23 @@ files:
|
|
|
170
170
|
- cmd/_banner.rb
|
|
171
171
|
- cmd/console.rb
|
|
172
172
|
- cmd/help.rb
|
|
173
|
+
- cmd/new.rb
|
|
174
|
+
- cmd/new/template/.gitignore
|
|
175
|
+
- cmd/new/template/Dockerfile
|
|
176
|
+
- cmd/new/template/Gemfile
|
|
177
|
+
- cmd/new/template/README.md
|
|
178
|
+
- cmd/new/template/app/_layout/default.rb
|
|
179
|
+
- cmd/new/template/app/_lib/storage.rb
|
|
180
|
+
- cmd/new/template/app/_schema/2026-01-01-initial.rb
|
|
181
|
+
- cmd/new/template/app/assets/style.css
|
|
182
|
+
- cmd/new/template/app/index.rb
|
|
183
|
+
- cmd/new/template/app/test.rb
|
|
184
|
+
- cmd/new/template/config/development.rb
|
|
185
|
+
- cmd/new/template/config/production.rb
|
|
186
|
+
- cmd/new/template/config/test.rb
|
|
187
|
+
- cmd/new/template/docker-compose.yml
|
|
188
|
+
- cmd/new/template/test/test_app.rb
|
|
173
189
|
- cmd/serve.rb
|
|
174
|
-
- cmd/setup/template/site/.gitignore
|
|
175
|
-
- cmd/setup/template/site/Dockerfile
|
|
176
|
-
- cmd/setup/template/site/Gemfile
|
|
177
|
-
- cmd/setup/template/site/README.md
|
|
178
|
-
- cmd/setup/template/site/bin/console
|
|
179
|
-
- cmd/setup/template/site/bin/restart
|
|
180
|
-
- cmd/setup/template/site/bin/server
|
|
181
|
-
- cmd/setup/template/site/bin/start
|
|
182
|
-
- cmd/setup/template/site/bin/stop
|
|
183
|
-
- cmd/setup/template/site/docker-compose.yml
|
|
184
|
-
- cmd/setup/template/site/proxy/Dockerfile
|
|
185
|
-
- cmd/setup/template/site/proxy/etc/Caddyfile
|
|
186
|
-
- cmd/setup/template/site/proxy/etc/tls_auto
|
|
187
|
-
- cmd/setup/template/site/proxy/etc/tls_cloudflare
|
|
188
|
-
- cmd/setup/template/site/proxy/etc/tls_custom
|
|
189
|
-
- cmd/setup/template/site/proxy/etc/tls_selfsigned
|
|
190
|
-
- cmd/setup/template/site/site/_layout/default.rb
|
|
191
|
-
- cmd/setup/template/site/site/about.md
|
|
192
|
-
- cmd/setup/template/site/site/articles/cage.rb
|
|
193
|
-
- cmd/setup/template/site/site/articles/index.rb
|
|
194
|
-
- cmd/setup/template/site/site/assets/css/style.css
|
|
195
|
-
- cmd/setup/template/site/site/assets/img/syntropy.png
|
|
196
|
-
- cmd/setup/template/site/site/index.rb
|
|
197
190
|
- cmd/test.rb
|
|
198
191
|
- docker-compose.yml
|
|
199
192
|
- examples/basic/bad.rb
|
|
@@ -206,8 +199,8 @@ files:
|
|
|
206
199
|
- examples/basic/templates.rb
|
|
207
200
|
- examples/blog/.gitignore
|
|
208
201
|
- examples/blog/app/_layout/default.rb
|
|
209
|
-
- examples/blog/app/_lib/database.rb
|
|
210
202
|
- examples/blog/app/_lib/posts.rb
|
|
203
|
+
- examples/blog/app/_lib/storage.rb
|
|
211
204
|
- examples/blog/app/_schema/2026-01-01-initial.rb
|
|
212
205
|
- examples/blog/app/assets/style.css
|
|
213
206
|
- examples/blog/app/index.rb
|
|
@@ -235,18 +228,6 @@ files:
|
|
|
235
228
|
- examples/mcp-oauth/app/signin.rb
|
|
236
229
|
- examples/mcp-oauth/test/test_app.rb
|
|
237
230
|
- examples/mcp-oauth/test/test_oauth.rb
|
|
238
|
-
- examples/template/.gitignore
|
|
239
|
-
- examples/template/Gemfile
|
|
240
|
-
- examples/template/app/_layout/default.rb
|
|
241
|
-
- examples/template/app/_lib/database.rb
|
|
242
|
-
- examples/template/app/_schema/2026-01-01-initial.rb
|
|
243
|
-
- examples/template/app/assets/style.css
|
|
244
|
-
- examples/template/app/index.rb
|
|
245
|
-
- examples/template/app/test.rb
|
|
246
|
-
- examples/template/config/development.rb
|
|
247
|
-
- examples/template/config/production.rb
|
|
248
|
-
- examples/template/config/test.rb
|
|
249
|
-
- examples/template/test/test_app.rb
|
|
250
231
|
- lib/syntropy.rb
|
|
251
232
|
- lib/syntropy/app.rb
|
|
252
233
|
- lib/syntropy/applets/builtin/auto_refresh/watch.js
|
|
@@ -258,9 +239,6 @@ files:
|
|
|
258
239
|
- lib/syntropy/applets/builtin/json_api.js
|
|
259
240
|
- lib/syntropy/applets/builtin/ping.rb
|
|
260
241
|
- lib/syntropy/applets/builtin/req.rb
|
|
261
|
-
- lib/syntropy/db/connection_pool.rb
|
|
262
|
-
- lib/syntropy/db/schema.rb
|
|
263
|
-
- lib/syntropy/db/store.rb
|
|
264
242
|
- lib/syntropy/dev_mode.rb
|
|
265
243
|
- lib/syntropy/errors.rb
|
|
266
244
|
- lib/syntropy/http.rb
|
|
@@ -284,6 +262,12 @@ files:
|
|
|
284
262
|
- lib/syntropy/routing_tree.rb
|
|
285
263
|
- lib/syntropy/session.rb
|
|
286
264
|
- lib/syntropy/side_run.rb
|
|
265
|
+
- lib/syntropy/storage.rb
|
|
266
|
+
- lib/syntropy/storage/connection_pool.rb
|
|
267
|
+
- lib/syntropy/storage/kv_store.rb
|
|
268
|
+
- lib/syntropy/storage/prepared_query.rb
|
|
269
|
+
- lib/syntropy/storage/schema.rb
|
|
270
|
+
- lib/syntropy/storage/store.rb
|
|
287
271
|
- lib/syntropy/test.rb
|
|
288
272
|
- lib/syntropy/utils.rb
|
|
289
273
|
- lib/syntropy/version.rb
|
|
@@ -336,23 +320,24 @@ files:
|
|
|
336
320
|
- test/run.rb
|
|
337
321
|
- test/test_app.rb
|
|
338
322
|
- test/test_caching.rb
|
|
339
|
-
- test/
|
|
340
|
-
- test/test_db_schema.rb
|
|
341
|
-
- test/test_db_store.rb
|
|
323
|
+
- test/test_connection_pool.rb
|
|
342
324
|
- test/test_errors.rb
|
|
343
325
|
- test/test_http_client.rb
|
|
344
326
|
- test/test_http_client_connection.rb
|
|
345
327
|
- test/test_http_protocol.rb
|
|
346
328
|
- test/test_http_server_connection.rb
|
|
347
329
|
- test/test_json_api.rb
|
|
330
|
+
- test/test_kv_store.rb
|
|
348
331
|
- test/test_mock_adapter.rb
|
|
349
332
|
- test/test_module_loader.rb
|
|
350
333
|
- test/test_request.rb
|
|
351
334
|
- test/test_request_session.rb
|
|
352
335
|
- test/test_response.rb
|
|
353
336
|
- test/test_routing_tree.rb
|
|
337
|
+
- test/test_schema.rb
|
|
354
338
|
- test/test_server.rb
|
|
355
339
|
- test/test_side_run.rb
|
|
340
|
+
- test/test_store.rb
|
|
356
341
|
- test/test_test.rb
|
|
357
342
|
homepage: https://github.com/digital-fabric/syntropy
|
|
358
343
|
licenses:
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
*.gem
|
|
2
|
-
*.rbc
|
|
3
|
-
/.config
|
|
4
|
-
/coverage/
|
|
5
|
-
/InstalledFiles
|
|
6
|
-
/pkg/
|
|
7
|
-
/spec/reports/
|
|
8
|
-
/spec/examples.txt
|
|
9
|
-
/test/tmp/
|
|
10
|
-
/test/version_tmp/
|
|
11
|
-
/tmp/
|
|
12
|
-
|
|
13
|
-
# Used by dotenv library to load environment variables.
|
|
14
|
-
# .env
|
|
15
|
-
|
|
16
|
-
# Ignore Byebug command history file.
|
|
17
|
-
.byebug_history
|
|
18
|
-
|
|
19
|
-
## Specific to RubyMotion:
|
|
20
|
-
.dat*
|
|
21
|
-
.repl_history
|
|
22
|
-
build/
|
|
23
|
-
*.bridgesupport
|
|
24
|
-
build-iPhoneOS/
|
|
25
|
-
build-iPhoneSimulator/
|
|
26
|
-
|
|
27
|
-
## Specific to RubyMotion (use of CocoaPods):
|
|
28
|
-
#
|
|
29
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
|
30
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
|
31
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
32
|
-
#
|
|
33
|
-
# vendor/Pods/
|
|
34
|
-
|
|
35
|
-
## Documentation cache and generated files:
|
|
36
|
-
/.yardoc/
|
|
37
|
-
/_yardoc/
|
|
38
|
-
/doc/
|
|
39
|
-
/rdoc/
|
|
40
|
-
|
|
41
|
-
## Environment normalization:
|
|
42
|
-
/.bundle/
|
|
43
|
-
/vendor/bundle
|
|
44
|
-
/lib/bundler/man/
|
|
45
|
-
|
|
46
|
-
# for a library or gem, you might want to ignore these files since the code is
|
|
47
|
-
# intended to run in multiple environments; otherwise, check them in:
|
|
48
|
-
# Gemfile.lock
|
|
49
|
-
# .ruby-version
|
|
50
|
-
# .ruby-gemset
|
|
51
|
-
|
|
52
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
53
|
-
.rvmrc
|
|
54
|
-
|
|
55
|
-
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
56
|
-
# .rubocop-https?--*
|
|
57
|
-
log
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
ARG RUBY_BASE_IMAGE=ruby:3.4.1-alpine
|
|
2
|
-
ARG GEM_CACHE_IMAGE=${RUBY_BASE_IMAGE}
|
|
3
|
-
|
|
4
|
-
# base image
|
|
5
|
-
FROM ${RUBY_BASE_IMAGE} AS base
|
|
6
|
-
RUN apk add --update sqlite-dev openssl-dev tzdata bash curl zip git
|
|
7
|
-
RUN apk add --update build-base
|
|
8
|
-
RUN gem install bundler:2.6.9
|
|
9
|
-
|
|
10
|
-
# gem cache
|
|
11
|
-
FROM ${GEM_CACHE_IMAGE} AS gem-cache
|
|
12
|
-
RUN mkdir -p /usr/local/bundle
|
|
13
|
-
|
|
14
|
-
FROM base AS gems
|
|
15
|
-
COPY --from=gem-cache /usr/local/bundle /usr/local/bundle
|
|
16
|
-
COPY Gemfile Gemfile.lock ./
|
|
17
|
-
RUN bundle install --jobs=4 --retry=5
|
|
18
|
-
|
|
19
|
-
# Final backend image
|
|
20
|
-
FROM base AS deploy
|
|
21
|
-
|
|
22
|
-
RUN adduser -D app
|
|
23
|
-
RUN chown app:app /home/app
|
|
24
|
-
WORKDIR /home/app
|
|
25
|
-
USER app
|
|
26
|
-
|
|
27
|
-
RUN mkdir -p /tmp
|
|
28
|
-
COPY --from=gems --chown=app:app /usr/local/bundle /usr/local/bundle
|
|
29
|
-
|
|
30
|
-
EXPOSE 1234
|
|
31
|
-
|
|
32
|
-
CMD ["bundle", "exec", "syntropy", "."]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
services:
|
|
2
|
-
backend:
|
|
3
|
-
build: .
|
|
4
|
-
privileged: true
|
|
5
|
-
restart: always
|
|
6
|
-
ports:
|
|
7
|
-
- 127.0.0.1:1234:1234
|
|
8
|
-
# expose:
|
|
9
|
-
# - 1234
|
|
10
|
-
volumes:
|
|
11
|
-
- .:/home/app
|
|
12
|
-
deploy:
|
|
13
|
-
# replicas: 1
|
|
14
|
-
resources:
|
|
15
|
-
limits:
|
|
16
|
-
memory: 500M
|
|
17
|
-
# restart: unless-stopped
|
|
18
|
-
logging:
|
|
19
|
-
driver: "json-file"
|
|
20
|
-
options:
|
|
21
|
-
max-size: "1M"
|
|
22
|
-
max-file: "10"
|
|
23
|
-
|
|
24
|
-
# healthcheck:
|
|
25
|
-
# test: "curl 'http://localhost:1234/?q=ping'"
|
|
26
|
-
# interval: "30s"
|
|
27
|
-
# timeout: "3s"
|
|
28
|
-
# start_period: "5s"
|
|
29
|
-
# retries: 3
|
|
30
|
-
|
|
31
|
-
proxy:
|
|
32
|
-
depends_on:
|
|
33
|
-
- backend
|
|
34
|
-
build:
|
|
35
|
-
context: ./proxy
|
|
36
|
-
dockerfile: Dockerfile
|
|
37
|
-
restart: always
|
|
38
|
-
volumes:
|
|
39
|
-
- ./proxy/etc/Caddyfile:/etc/caddy/Caddyfile
|
|
40
|
-
ports:
|
|
41
|
-
- "80:80"
|
|
42
|
-
- "443:443"
|
|
43
|
-
- "443:443/udp"
|
|
44
|
-
# env_file:
|
|
45
|
-
# - ./conf/caddy.env
|
|
46
|
-
# - ./conf/caddy_sensitive.env
|
|
47
|
-
logging:
|
|
48
|
-
driver: "json-file"
|
|
49
|
-
options:
|
|
50
|
-
max-size: "1M"
|
|
51
|
-
max-file: "10"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
tls {$TLS_CUSTOM_CERT} {$TLS_CUSTOM_KEY}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
tls internal
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
layout = import('_layout/default')
|
|
2
|
-
|
|
3
|
-
poem = [
|
|
4
|
-
" in ten\xA0", 'M', 'inutes',
|
|
5
|
-
' ', 'C', 'ome back: you will',
|
|
6
|
-
'have taught me chi', 'N', 'ese',
|
|
7
|
-
' (s', 'A', 'tie).',
|
|
8
|
-
' shall I ret', 'U', 'rn the favor?',
|
|
9
|
-
' ', 'G', 'ive you',
|
|
10
|
-
' ot', 'H', 'er lessons',
|
|
11
|
-
' (', 'T', 'ing!)?',
|
|
12
|
-
' ', 'O', 'r would you prefer',
|
|
13
|
-
' sile', 'N', 'ce?',
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
export Papercraft.apply(layout) {
|
|
17
|
-
article(class: 'mesostic') {
|
|
18
|
-
h2 'For William McN. who studied with Ezra Pound'
|
|
19
|
-
|
|
20
|
-
content {
|
|
21
|
-
span(_for: poem) { text it }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
author {
|
|
25
|
-
span "-\xA0"
|
|
26
|
-
a 'John cage', href: 'https://en.wikipedia.org/wiki/John_Cage'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
font-family: sans-serif;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
article.mesostic {
|
|
6
|
-
width: 600px;
|
|
7
|
-
margin: 2em auto;
|
|
8
|
-
font-size: 1.4em;
|
|
9
|
-
|
|
10
|
-
* {
|
|
11
|
-
font-family: monospace;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
h2 {
|
|
15
|
-
text-align: center;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
content {
|
|
19
|
-
display: grid;
|
|
20
|
-
margin: 2em 0;
|
|
21
|
-
grid-template-columns: 1fr auto 1fr;
|
|
22
|
-
|
|
23
|
-
span {
|
|
24
|
-
display: inline-block;
|
|
25
|
-
}
|
|
26
|
-
span:nth-child(3n + 1) {
|
|
27
|
-
text-align: right;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
span:nth-child(3n + 2) {
|
|
31
|
-
text-align: center;
|
|
32
|
-
font-weight: bold;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
author {
|
|
37
|
-
display: block;
|
|
38
|
-
text-align: right;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
layout = import('_layout/default')
|
|
2
|
-
|
|
3
|
-
export Papercraft.apply(layout) {
|
|
4
|
-
h1 'Hello from Syntropy'
|
|
5
|
-
p {
|
|
6
|
-
span "Here's an "
|
|
7
|
-
a 'about', href: 'about'
|
|
8
|
-
span ' page.'
|
|
9
|
-
}
|
|
10
|
-
p {
|
|
11
|
-
span "Here's an "
|
|
12
|
-
a 'article', href: 'articles/cage'
|
|
13
|
-
span ' page.'
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
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,13 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|