syntropy 0.2 → 0.3
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/.rubocop.yml +2 -2
- data/CHANGELOG.md +4 -0
- data/TODO.md +0 -97
- data/bin/syntropy +6 -2
- data/lib/syntropy/app.rb +47 -32
- data/lib/syntropy/version.rb +1 -1
- data/syntropy.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d7686b3b9f5f09c819bebb9e46fdceb45c8c0a66441b1e12b130fa376defc5
|
4
|
+
data.tar.gz: f616e5dcdedc8a08fb23d5a52c1a92296cd348f8555fede1ac31ba0859c1be28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f6d14df3cbbaa74d9ec897cb50fd35caed0f48b6410f2abb13fad79947b50bbf33c32aa6358ab6464ac5b90e861fffacb345805d487cd67f5bd77b36cd7295b
|
7
|
+
data.tar.gz: af07c19a78d94fe37403246b302f95f047aeb12c764e8914e43f5ed1e1b1245cc0678a01e964e895fdc7aef0e775194c6ee9744939113352db07eca166693cc1
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -1,97 +0,0 @@
|
|
1
|
-
## Server tool
|
2
|
-
|
3
|
-
```bash
|
4
|
-
$ bundle exec syntropy --dev ./site
|
5
|
-
$ bundle exec syntropy --workers 4 ./site
|
6
|
-
```
|
7
|
-
|
8
|
-
And also a config file:
|
9
|
-
|
10
|
-
```bash
|
11
|
-
$ bundle exec syntropy site.rb
|
12
|
-
```
|
13
|
-
|
14
|
-
And the config file:
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
# site.rb
|
18
|
-
Syntropy.config do
|
19
|
-
root './site'
|
20
|
-
workers 4
|
21
|
-
log { |req| }
|
22
|
-
end
|
23
|
-
```
|
24
|
-
|
25
|
-
## Lightweight model API on top of Extralite
|
26
|
-
|
27
|
-
- DB connection pool
|
28
|
-
- Lightweight means 90% features with 10% effort:
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
Posts = Syntropy::Relation.new('posts')
|
32
|
-
|
33
|
-
posts = Posts.order_by(:stamp, :desc).all(db)
|
34
|
-
|
35
|
-
post = Posts.where(id: 13).first(db)
|
36
|
-
|
37
|
-
id = Posts.insert(db, title: 'foo', body: 'bar')
|
38
|
-
|
39
|
-
Posts.where(id: id).update(db, body: 'baz')
|
40
|
-
|
41
|
-
Posts.where(id: id).delete(db)
|
42
|
-
```
|
43
|
-
|
44
|
-
The whole `db` argument thing is very limiting. For easier usage we integrate
|
45
|
-
the db connection pool as dependency injection the model:
|
46
|
-
|
47
|
-
```ruby
|
48
|
-
db_pool = E2::ConnectionPool.new(fn)
|
49
|
-
Posts = Syntropy::Dataset.new(db_pool, 'posts')
|
50
|
-
|
51
|
-
Posts[id: 1] #=> { id: 1, title: 'foo', body: 'bar' }
|
52
|
-
Posts.find(id: 1) #=>
|
53
|
-
|
54
|
-
Posts.to_a #=> [...]
|
55
|
-
Posts.order_by(:stamp, :desc).to_a #=> [...]
|
56
|
-
|
57
|
-
id = Posts.insert(title: 'foo', body: 'bar')
|
58
|
-
|
59
|
-
post = Posts.where(id: id)
|
60
|
-
post.values #=> { id: 1, title: 'foo', body: 'bar' }
|
61
|
-
post.update(body: 'baz') #=> 1
|
62
|
-
post.delete
|
63
|
-
```
|
64
|
-
|
65
|
-
So basically it's a bit similar to Sequel datasets, but there's no "object instance as single row". The instance is the entire set of rows in the table, or a subset thereof:
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
Posts.where(...).order_by(...).select(...).from(rowset)
|
69
|
-
```
|
70
|
-
|
71
|
-
How about CTEs?
|
72
|
-
|
73
|
-
```ruby
|
74
|
-
Users = Syntrop::Dataset.new(db_pool, 'users')
|
75
|
-
|
76
|
-
GroupIdRowset = Syntropy::Dataset {
|
77
|
-
with(
|
78
|
-
foo: Users,
|
79
|
-
bar: -> {
|
80
|
-
select user_id, group
|
81
|
-
from foo
|
82
|
-
},
|
83
|
-
baz: -> {
|
84
|
-
select id
|
85
|
-
from bar
|
86
|
-
where user_id == bar.select(:user_id)
|
87
|
-
}
|
88
|
-
)
|
89
|
-
|
90
|
-
select_all
|
91
|
-
from baz
|
92
|
-
where id == :group_id
|
93
|
-
}
|
94
|
-
|
95
|
-
users = GroupIdRowset.bind(group_id: 5).to_a
|
96
|
-
|
97
|
-
```
|
data/bin/syntropy
CHANGED
@@ -56,6 +56,10 @@ if !File.directory?(opts[:location])
|
|
56
56
|
exit
|
57
57
|
end
|
58
58
|
|
59
|
+
|
60
|
+
|
59
61
|
opts[:machine] = UM.new
|
60
|
-
|
61
|
-
|
62
|
+
opts[:logger] = opts[:logger] && TP2::Logger.new(opts[:machine], **opts)
|
63
|
+
|
64
|
+
app = Syntropy::App.new(opts[:machine], opts[:location], '/', opts)
|
65
|
+
TP2.run(opts) { app.call(it) }
|
data/lib/syntropy/app.rb
CHANGED
@@ -12,22 +12,20 @@ module Syntropy
|
|
12
12
|
class App
|
13
13
|
attr_reader :route_cache
|
14
14
|
|
15
|
-
def initialize(machine, src_path, mount_path,
|
15
|
+
def initialize(machine, src_path, mount_path, opts = {})
|
16
16
|
@machine = machine
|
17
|
-
@src_path = src_path
|
17
|
+
@src_path = File.expand_path(src_path)
|
18
18
|
@mount_path = mount_path
|
19
19
|
@route_cache = {}
|
20
|
-
@
|
20
|
+
@opts = opts
|
21
21
|
|
22
22
|
@relative_path_re = calculate_relative_path_re(mount_path)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
p e.backtrace
|
30
|
-
end
|
23
|
+
@machine.spin do
|
24
|
+
# we do startup stuff asynchronously, in order to first let TP2 do its
|
25
|
+
# setup tasks
|
26
|
+
@machine.sleep 0.25
|
27
|
+
@opts[:logger]&.call("Serving from #{File.expand_path(@src_path)}")
|
28
|
+
start_file_watcher if opts[:watch_files]
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -42,15 +40,6 @@ module Syntropy
|
|
42
40
|
entry
|
43
41
|
end
|
44
42
|
|
45
|
-
def invalidate_cache(fn)
|
46
|
-
invalidated_keys = []
|
47
|
-
@route_cache.each do |k, v|
|
48
|
-
invalidated_keys << k if v[:fn] == fn
|
49
|
-
end
|
50
|
-
|
51
|
-
invalidated_keys.each { @route_cache.delete(it) }
|
52
|
-
end
|
53
|
-
|
54
43
|
def call(req)
|
55
44
|
entry = find_route(req.path)
|
56
45
|
render_entry(req, entry)
|
@@ -62,6 +51,32 @@ module Syntropy
|
|
62
51
|
|
63
52
|
private
|
64
53
|
|
54
|
+
def start_file_watcher
|
55
|
+
@opts[:logger]&.call('Watching for module file changes...', nil)
|
56
|
+
wf = @opts[:watch_files]
|
57
|
+
period = wf.is_a?(Numeric) ? wf : 0.1
|
58
|
+
@machine.spin do
|
59
|
+
Syntropy.file_watch(@machine, @src_path, period: period) do
|
60
|
+
@opts[:logger]&.call("Detected changed file: #{it}")
|
61
|
+
invalidate_cache(it)
|
62
|
+
rescue Exception => e
|
63
|
+
p e
|
64
|
+
p e.backtrace
|
65
|
+
exit!
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def invalidate_cache(fn)
|
71
|
+
invalidated_keys = []
|
72
|
+
@route_cache.each do |k, v|
|
73
|
+
@opts[:logger]&.call("Invalidate cache for #{k}", nil)
|
74
|
+
invalidated_keys << k if v[:fn] == fn
|
75
|
+
end
|
76
|
+
|
77
|
+
invalidated_keys.each { @route_cache.delete(it) }
|
78
|
+
end
|
79
|
+
|
65
80
|
def calculate_relative_path_re(mount_path)
|
66
81
|
mount_path = '' if mount_path == '/'
|
67
82
|
/^#{mount_path}(?:\/(.*))?$/
|
@@ -95,7 +110,7 @@ module Syntropy
|
|
95
110
|
end
|
96
111
|
|
97
112
|
def file_entry(fn)
|
98
|
-
{ fn: fn, kind: FILE_KINDS[File.extname(fn)] || :static }
|
113
|
+
{ fn: File.expand_path(fn), kind: FILE_KINDS[File.extname(fn)] || :static }
|
99
114
|
end
|
100
115
|
|
101
116
|
def find_index_entry(dir)
|
@@ -138,19 +153,23 @@ module Syntropy
|
|
138
153
|
when :not_found
|
139
154
|
req.respond('Not found', ':status' => Qeweney::Status::NOT_FOUND)
|
140
155
|
when :static
|
141
|
-
|
142
|
-
req.respond(IO.read(entry[:fn]), 'Content-Type' => entry[:mime_type])
|
156
|
+
respond_static(req, entry)
|
143
157
|
when :markdown
|
144
158
|
body = render_markdown(IO.read(entry[:fn]))
|
145
159
|
req.respond(body, 'Content-Type' => 'text/html')
|
146
160
|
when :module
|
147
|
-
call_module(
|
161
|
+
call_module(req, entry)
|
148
162
|
else
|
149
|
-
raise
|
163
|
+
raise 'Invalid entry kind'
|
150
164
|
end
|
151
165
|
end
|
152
166
|
|
153
|
-
def
|
167
|
+
def respond_static(req, entry)
|
168
|
+
entry[:mime_type] ||= Qeweney::MimeTypes[File.extname(entry[:fn])]
|
169
|
+
req.respond(IO.read(entry[:fn]), 'Content-Type' => entry[:mime_type])
|
170
|
+
end
|
171
|
+
|
172
|
+
def call_module(req, entry)
|
154
173
|
entry[:code] ||= load_module(entry)
|
155
174
|
if entry[:code] == :invalid
|
156
175
|
req.respond(nil, ':status' => Qeweney::Status::INTERNAL_SERVER_ERROR)
|
@@ -165,17 +184,13 @@ module Syntropy
|
|
165
184
|
end
|
166
185
|
|
167
186
|
def load_module(entry)
|
168
|
-
loader = Syntropy::ModuleLoader.new(@src_path, @
|
187
|
+
loader = Syntropy::ModuleLoader.new(@src_path, @opts)
|
169
188
|
ref = entry[:fn].gsub(%r{^#{@src_path}\/}, '').gsub(/\.rb$/, '')
|
170
189
|
o = loader.load(ref)
|
171
190
|
# klass = Class.new
|
172
191
|
# o = klass.instance_eval(body, entry[:fn], 1)
|
173
192
|
|
174
|
-
|
175
|
-
return wrap_template(o)
|
176
|
-
else
|
177
|
-
return o
|
178
|
-
end
|
193
|
+
o.is_a?(Papercraft::HTML) ? wrap_template(o) : o
|
179
194
|
end
|
180
195
|
|
181
196
|
def wrap_template(templ)
|
data/lib/syntropy/version.rb
CHANGED
data/syntropy.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency 'json', '2.12.2'
|
26
26
|
s.add_dependency 'papercraft', '1.4'
|
27
27
|
s.add_dependency 'qeweney', '0.21'
|
28
|
-
s.add_dependency 'tp2', '0.12.
|
28
|
+
s.add_dependency 'tp2', '0.12.3.1'
|
29
29
|
s.add_dependency 'uringmachine', '0.15'
|
30
30
|
|
31
31
|
s.add_dependency 'listen', '3.9.0'
|
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.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -71,14 +71,14 @@ dependencies:
|
|
71
71
|
requirements:
|
72
72
|
- - '='
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.12.
|
74
|
+
version: 0.12.3.1
|
75
75
|
type: :runtime
|
76
76
|
prerelease: false
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - '='
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: 0.12.
|
81
|
+
version: 0.12.3.1
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: uringmachine
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|