syntropy 0.1 → 0.2
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 +196 -0
- data/CHANGELOG.md +6 -0
- data/TODO.md +94 -8
- data/bin/syntropy +61 -0
- data/lib/syntropy/app.rb +32 -7
- data/lib/syntropy/connection_pool.rb +60 -0
- data/lib/syntropy/file_watch.rb +27 -0
- data/lib/syntropy/module.rb +64 -0
- data/lib/syntropy/rpc_api.rb +4 -0
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +23 -1
- data/syntropy.gemspec +23 -18
- data/test/app/_lib/callable.rb +13 -0
- data/test/app/_lib/klass.rb +15 -0
- data/test/app/_lib/missing-export.rb +7 -0
- data/test/app/about/index.rb +1 -1
- data/test/app/api+.rb +4 -3
- data/test/app/bar.rb +1 -1
- data/test/app/tmp.rb +6 -0
- data/test/test_app.rb +20 -1
- data/test/test_connection_pool.rb +81 -0
- data/test/test_file_watch.rb +36 -0
- data/test/test_module.rb +32 -0
- data/test/test_rpc_api.rb +1 -1
- metadata +67 -13
- data/lib/syntropy/context.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9a2e580917d4b05e8470695a75ab399326c6b8f7ee3b576526181c36791ee81
|
4
|
+
data.tar.gz: eb95e089e426bdb618981694cf8240911f30821a90d5ae9ef8f4bf4d79670a44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a85e2502bd313a10b5533ec5b8f124cfa72a3c4494f7ddcd912e0939973e2f72df458e6891543c5cbcf106718254561523c7f561ee1fd23bf348cab701696d4a
|
7
|
+
data.tar.gz: 60391470703441eccb1bdba52edfba754225171bcf65a08d146d01742e1ab8f7b8f6215cfc093ed4aee4b6e99c0f967cb9a6bf1f19274f6f4d34f8ae95a6e2c4
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.2
|
3
|
+
RubyInterpreters:
|
4
|
+
- ruby
|
5
|
+
Exclude:
|
6
|
+
- "**/*.gemspec"
|
7
|
+
- "test/**/*.rb"
|
8
|
+
- "examples/**/*.rb"
|
9
|
+
- "Gemfile*"
|
10
|
+
# Style/LambdaCall:
|
11
|
+
# Enabled: false
|
12
|
+
# Style/ModuleFunction:
|
13
|
+
# Enabled: false
|
14
|
+
# Style/RegexpLiteral:
|
15
|
+
# Enabled: false
|
16
|
+
|
17
|
+
# Naming/MemoizedInstanceVariableName:
|
18
|
+
# Enabled: false
|
19
|
+
|
20
|
+
# Style/Alias:
|
21
|
+
# EnforcedStyle: prefer_alias_method
|
22
|
+
|
23
|
+
# Style/SpecialGlobalVars:
|
24
|
+
# Enabled: false
|
25
|
+
|
26
|
+
# Style/ClassAndModuleChildren:
|
27
|
+
# Enabled: false
|
28
|
+
|
29
|
+
# Metrics/AbcSize:
|
30
|
+
# Enabled: false
|
31
|
+
|
32
|
+
# Style/MixinUsage:
|
33
|
+
# Enabled: false
|
34
|
+
|
35
|
+
# Style/MultilineBlockChain:
|
36
|
+
# Enabled: false
|
37
|
+
|
38
|
+
# Lint/RescueException:
|
39
|
+
# Enabled: false
|
40
|
+
|
41
|
+
# Lint/InheritException:
|
42
|
+
# Enabled: false
|
43
|
+
|
44
|
+
Style/NumericPredicate:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
# Style/TrivialAccessors:
|
48
|
+
# Enabled: false
|
49
|
+
|
50
|
+
# Lint/MissingSuper:
|
51
|
+
# Enabled: false
|
52
|
+
|
53
|
+
# Style/GlobalVars:
|
54
|
+
# Exclude:
|
55
|
+
# - lib/polyphony/auto_run.rb
|
56
|
+
# - lib/polyphony/extensions/core.rb
|
57
|
+
# - examples/**/*.rb
|
58
|
+
|
59
|
+
Layout/HashAlignment:
|
60
|
+
Enabled: false
|
61
|
+
EnforcedColonStyle: table
|
62
|
+
EnforcedHashRocketStyle: table
|
63
|
+
|
64
|
+
# Naming/AccessorMethodName:
|
65
|
+
# Exclude:
|
66
|
+
# - lib/polyphony/extensions/fiber.rb
|
67
|
+
# - examples/**/*.rb
|
68
|
+
|
69
|
+
# Naming/MethodName:
|
70
|
+
# Exclude:
|
71
|
+
# - test/test_signal.rb
|
72
|
+
|
73
|
+
# Lint/SuppressedException:
|
74
|
+
# Exclude:
|
75
|
+
# - examples/**/*.rb
|
76
|
+
|
77
|
+
Metrics/MethodLength:
|
78
|
+
Max: 14
|
79
|
+
# Exclude:
|
80
|
+
# - lib/polyphony/extensions/io.rb
|
81
|
+
# - lib/polyphony/extensions/fiber.rb
|
82
|
+
# - lib/polyphony/extensions/thread.rb
|
83
|
+
# - lib/polyphony/adapters/open3.rb
|
84
|
+
# - test/**/*.rb
|
85
|
+
# - examples/**/*.rb
|
86
|
+
|
87
|
+
# Metrics/ModuleLength:
|
88
|
+
# Exclude:
|
89
|
+
# - lib/polyphony/core/global_api.rb
|
90
|
+
# - examples/**/*.rb
|
91
|
+
|
92
|
+
# Metrics/ClassLength:
|
93
|
+
# Exclude:
|
94
|
+
# - lib/polyphony/extensions/io.rb
|
95
|
+
# - lib/polyphony/extensions/fiber.rb
|
96
|
+
# - lib/polyphony/extensions/object.rb
|
97
|
+
# - lib/polyphony/extensions/thread.rb
|
98
|
+
# - test/**/*.rb
|
99
|
+
# - examples/**/*.rb
|
100
|
+
|
101
|
+
# Metrics/CyclomaticComplexity:
|
102
|
+
# Exclude:
|
103
|
+
# - lib/polyphony/extensions/fiber.rb
|
104
|
+
|
105
|
+
# Metrics/PerceivedComplexity:
|
106
|
+
# Exclude:
|
107
|
+
# - lib/polyphony/extensions/fiber.rb
|
108
|
+
|
109
|
+
# Style/RegexpLiteral:
|
110
|
+
# Enabled: false
|
111
|
+
|
112
|
+
Style/RescueModifier:
|
113
|
+
Enabled: false
|
114
|
+
# Style/Documentation:
|
115
|
+
# Exclude:
|
116
|
+
# - test/**/*.rb
|
117
|
+
# - examples/**/*.rb
|
118
|
+
# - lib/polyphony/adapters/**/*.rb
|
119
|
+
|
120
|
+
# Style/FormatString:
|
121
|
+
# Exclude:
|
122
|
+
# - test/**/*.rb
|
123
|
+
# - examples/**/*.rb
|
124
|
+
|
125
|
+
# Style/FormatStringToken:
|
126
|
+
# Exclude:
|
127
|
+
# - test/**/*.rb
|
128
|
+
# - examples/**/*.rb
|
129
|
+
|
130
|
+
Naming/MethodParameterName:
|
131
|
+
Enabled: false
|
132
|
+
|
133
|
+
# Security/MarshalLoad:
|
134
|
+
# Exclude:
|
135
|
+
# - examples/**/*.rb
|
136
|
+
|
137
|
+
# Lint/ShadowedArgument:
|
138
|
+
# Exclude:
|
139
|
+
# - lib/polyphony/extensions/fiber.rb
|
140
|
+
|
141
|
+
# Style/HashEachMethods:
|
142
|
+
# Enabled: true
|
143
|
+
|
144
|
+
# Style/HashTransformKeys:
|
145
|
+
# Enabled: true
|
146
|
+
|
147
|
+
# Style/HashTransformValues:
|
148
|
+
# Enabled: true
|
149
|
+
|
150
|
+
# Layout/EmptyLinesAroundAttributeAccessor:
|
151
|
+
# Enabled: true
|
152
|
+
|
153
|
+
# Layout/SpaceAroundMethodCallOperator:
|
154
|
+
# Enabled: true
|
155
|
+
|
156
|
+
# Lint/DeprecatedOpenSSLConstant:
|
157
|
+
# Enabled: true
|
158
|
+
|
159
|
+
# Lint/MixedRegexpCaptureTypes:
|
160
|
+
# Enabled: true
|
161
|
+
|
162
|
+
# Lint/RaiseException:
|
163
|
+
# Enabled: true
|
164
|
+
|
165
|
+
# Lint/StructNewOverride:
|
166
|
+
# Enabled: true
|
167
|
+
|
168
|
+
Style/NegatedIf:
|
169
|
+
Enabled: false
|
170
|
+
# Style/NegatedWhile:
|
171
|
+
# Enabled: false
|
172
|
+
|
173
|
+
# Style/CombinableLoops:
|
174
|
+
# Enabled: false
|
175
|
+
|
176
|
+
# Style/InfiniteLoop:
|
177
|
+
# Enabled: false
|
178
|
+
|
179
|
+
# Style/RedundantReturn:
|
180
|
+
# Enabled: false
|
181
|
+
|
182
|
+
# Style/ExponentialNotation:
|
183
|
+
# Enabled: true
|
184
|
+
|
185
|
+
# Style/RedundantRegexpCharacterClass:
|
186
|
+
# Enabled: true
|
187
|
+
|
188
|
+
# Style/RedundantRegexpEscape:
|
189
|
+
# Enabled: true
|
190
|
+
|
191
|
+
# Style/SlicingWithRange:
|
192
|
+
# Enabled: true
|
193
|
+
|
194
|
+
# Style/RaiseArgs:
|
195
|
+
# Exclude:
|
196
|
+
# - lib/polyphony/extensions/fiber.rb
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -1,11 +1,97 @@
|
|
1
|
-
|
1
|
+
## Server tool
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
```bash
|
4
|
+
$ bundle exec syntropy --dev ./site
|
5
|
+
$ bundle exec syntropy --workers 4 ./site
|
6
|
+
```
|
6
7
|
|
7
|
-
|
8
|
+
And also a config file:
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
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
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'syntropy'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
opts = {
|
8
|
+
banner: Syntropy::BANNER,
|
9
|
+
logger: true
|
10
|
+
}
|
11
|
+
|
12
|
+
parser = OptionParser.new do |o|
|
13
|
+
o.banner = 'Usage: syntropy [options] DIR'
|
14
|
+
|
15
|
+
o.on('-b', '--bind BIND', String,
|
16
|
+
'Bind address (default: http://0.0.0.0:1234). You can specify this flag multiple times to bind to multiple addresses.') do
|
17
|
+
opts[:bind] ||= []
|
18
|
+
opts[:bind] << it
|
19
|
+
end
|
20
|
+
|
21
|
+
o.on('-s', '--silent', 'Silent mode') do
|
22
|
+
opts[:banner] = nil
|
23
|
+
opts[:logger] = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
o.on('-w', '--watch', 'Watch for changed files') do
|
27
|
+
opts[:watch_files] = 0.1
|
28
|
+
end
|
29
|
+
|
30
|
+
o.on('-h', '--help', 'Show this help message') do
|
31
|
+
puts o
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on('-v', '--version', 'Show version') do
|
36
|
+
require 'syntropy/version'
|
37
|
+
puts "Syntropy version #{Syntropy::VERSION}"
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
RubyVM::YJIT.enable rescue nil
|
43
|
+
|
44
|
+
begin
|
45
|
+
parser.parse!
|
46
|
+
rescue StandardError => e
|
47
|
+
puts e.message
|
48
|
+
puts e.backtrace.join("\n")
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
opts[:location] = ARGV.shift || '.'
|
53
|
+
|
54
|
+
if !File.directory?(opts[:location])
|
55
|
+
puts "#{File.expand_path(opts[:location])} Not a directory"
|
56
|
+
exit
|
57
|
+
end
|
58
|
+
|
59
|
+
opts[:machine] = UM.new
|
60
|
+
app = Syntropy::App.new(opts[:machine], opts[:location], '/', watch_files: 0.05)
|
61
|
+
TP2.run(opts) { app.(it) }
|
data/lib/syntropy/app.rb
CHANGED
@@ -1,20 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'qeweney'
|
4
|
-
require 'syntropy/errors'
|
5
4
|
require 'json'
|
6
5
|
require 'papercraft'
|
7
6
|
|
7
|
+
require 'syntropy/errors'
|
8
|
+
require 'syntropy/file_watch'
|
9
|
+
require 'syntropy/module'
|
10
|
+
|
8
11
|
module Syntropy
|
9
12
|
class App
|
10
13
|
attr_reader :route_cache
|
11
14
|
|
12
|
-
def initialize(src_path, mount_path)
|
15
|
+
def initialize(machine, src_path, mount_path, env = {})
|
16
|
+
@machine = machine
|
13
17
|
@src_path = src_path
|
14
18
|
@mount_path = mount_path
|
15
19
|
@route_cache = {}
|
20
|
+
@env = env
|
16
21
|
|
17
22
|
@relative_path_re = calculate_relative_path_re(mount_path)
|
23
|
+
if (wf = env[:watch_files])
|
24
|
+
period = wf.is_a?(Numeric) ? wf : 0.1
|
25
|
+
machine.spin do
|
26
|
+
Syntropy.file_watch(@machine, src_path, period: period) { invalidate_cache(it) }
|
27
|
+
rescue Exception => e
|
28
|
+
p e
|
29
|
+
p e.backtrace
|
30
|
+
end
|
31
|
+
end
|
18
32
|
end
|
19
33
|
|
20
34
|
def find_route(path, cache: true)
|
@@ -28,6 +42,15 @@ module Syntropy
|
|
28
42
|
entry
|
29
43
|
end
|
30
44
|
|
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
|
+
|
31
54
|
def call(req)
|
32
55
|
entry = find_route(req.path)
|
33
56
|
render_entry(req, entry)
|
@@ -67,7 +90,7 @@ module Syntropy
|
|
67
90
|
|
68
91
|
entry = find_file_entry_with_extension(fs_path)
|
69
92
|
return entry if entry[:kind] != :not_found
|
70
|
-
|
93
|
+
|
71
94
|
find_up_tree_module(path)
|
72
95
|
end
|
73
96
|
|
@@ -138,13 +161,15 @@ module Syntropy
|
|
138
161
|
rescue StandardError => e
|
139
162
|
p e
|
140
163
|
p e.backtrace
|
141
|
-
req.respond(nil, ':status' => Qeweney::
|
164
|
+
req.respond(nil, ':status' => Qeweney::Status::INTERNAL_SERVER_ERROR)
|
142
165
|
end
|
143
166
|
|
144
167
|
def load_module(entry)
|
145
|
-
|
146
|
-
|
147
|
-
o =
|
168
|
+
loader = Syntropy::ModuleLoader.new(@src_path, @env)
|
169
|
+
ref = entry[:fn].gsub(%r{^#{@src_path}\/}, '').gsub(/\.rb$/, '')
|
170
|
+
o = loader.load(ref)
|
171
|
+
# klass = Class.new
|
172
|
+
# o = klass.instance_eval(body, entry[:fn], 1)
|
148
173
|
|
149
174
|
if o.is_a?(Papercraft::HTML)
|
150
175
|
return wrap_template(o)
|
@@ -0,0 +1,60 @@
|
|
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
|
+
private
|
35
|
+
|
36
|
+
def checkout
|
37
|
+
if @queue.count == 0 && @count < @max_conn
|
38
|
+
return create_db
|
39
|
+
end
|
40
|
+
|
41
|
+
@machine.shift(@queue)
|
42
|
+
end
|
43
|
+
|
44
|
+
def checkin(db)
|
45
|
+
@machine.push(@queue, db)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_db
|
49
|
+
db = Extralite::Database.new(@fn, wal: true)
|
50
|
+
setup_db(db)
|
51
|
+
@count += 1
|
52
|
+
db
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_db(db)
|
56
|
+
# setup WAL, sync
|
57
|
+
# setup concurrency stuff
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Syntropy
|
4
|
+
def self.file_watch(machine, *roots, period: 0.1, &block)
|
5
|
+
raise 'Missing root paths' if roots.empty?
|
6
|
+
|
7
|
+
require 'listen'
|
8
|
+
|
9
|
+
queue = Thread::Queue.new
|
10
|
+
listener = Listen.to(*roots) do |modified, added, removed|
|
11
|
+
fns = (modified + added + removed).uniq
|
12
|
+
fns.each { queue.push(it) }
|
13
|
+
end
|
14
|
+
listener.start
|
15
|
+
|
16
|
+
loop do
|
17
|
+
machine.sleep(period) while queue.empty?
|
18
|
+
fn = queue.shift
|
19
|
+
block.call(fn)
|
20
|
+
end
|
21
|
+
rescue StandardError => e
|
22
|
+
p e
|
23
|
+
p e.backtrace
|
24
|
+
ensure
|
25
|
+
listener.stop
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Syntropy
|
4
|
+
class ModuleLoader
|
5
|
+
def initialize(root, env)
|
6
|
+
@root = root
|
7
|
+
@env = env
|
8
|
+
@loaded = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(ref)
|
12
|
+
@loaded[ref] ||= load_module(ref)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def load_module(ref)
|
18
|
+
fn = File.join(@root, "#{ref}.rb")
|
19
|
+
raise RuntimeError, "File not found #{fn}" if !File.file?(fn)
|
20
|
+
|
21
|
+
mod_body = IO.read(fn)
|
22
|
+
mod_ctx = Class.new(Syntropy::Module)
|
23
|
+
mod_ctx.loader = self
|
24
|
+
# mod_ctx = .new(self, @env)
|
25
|
+
mod_ctx.module_eval(mod_body, fn, 1)
|
26
|
+
|
27
|
+
export_value = mod_ctx.__export_value__
|
28
|
+
|
29
|
+
case export_value
|
30
|
+
when nil
|
31
|
+
raise RuntimeError, 'No export found'
|
32
|
+
when Symbol
|
33
|
+
# TODO: verify export_value denotes a valid method
|
34
|
+
mod_ctx.new(@env)
|
35
|
+
when Proc
|
36
|
+
export_value
|
37
|
+
else
|
38
|
+
export_value.new(@env)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Module
|
44
|
+
def initialize(env)
|
45
|
+
@env = env
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.loader=(loader)
|
49
|
+
@loader = loader
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.import(ref)
|
53
|
+
@loader.load(ref)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.export(ref)
|
57
|
+
@__export_value__ = ref
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.__export_value__
|
61
|
+
@__export_value__
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/syntropy/rpc_api.rb
CHANGED
data/lib/syntropy/version.rb
CHANGED
data/lib/syntropy.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'qeweney'
|
4
|
+
require 'uringmachine'
|
5
|
+
require 'tp2'
|
4
6
|
|
5
7
|
require 'syntropy/errors'
|
6
|
-
|
8
|
+
require 'syntropy/connection_pool'
|
9
|
+
require 'syntropy/module'
|
7
10
|
require 'syntropy/rpc_api'
|
8
11
|
require 'syntropy/app'
|
9
12
|
|
@@ -57,4 +60,23 @@ class Qeweney::Request
|
|
57
60
|
end
|
58
61
|
|
59
62
|
module Syntropy
|
63
|
+
def colorize(color_code)
|
64
|
+
"\e[#{color_code}m#{self}\e[0m"
|
65
|
+
end
|
66
|
+
|
67
|
+
GREEN = "\e[32m"
|
68
|
+
WHITE = "\e[0m"
|
69
|
+
YELLOW = "\e[33m"
|
70
|
+
|
71
|
+
BANNER = (
|
72
|
+
"\n"\
|
73
|
+
" #{GREEN}\n"\
|
74
|
+
" #{GREEN} ooo\n"\
|
75
|
+
" #{GREEN}ooooo\n"\
|
76
|
+
" #{GREEN} ooo vvv #{WHITE}Syntropy - a web framework for Ruby\n"\
|
77
|
+
" #{GREEN} o vvvvv #{WHITE}--------------------------------------\n"\
|
78
|
+
" #{GREEN} #{YELLOW}|#{GREEN} vvv o #{WHITE}https://github.com/noteflakes/syntropy\n"\
|
79
|
+
" #{GREEN} :#{YELLOW}|#{GREEN}:::#{YELLOW}|#{GREEN}::#{YELLOW}|#{GREEN}:\n"\
|
80
|
+
" #{YELLOW}++++++++++++\e[0m\n\n"
|
81
|
+
)
|
60
82
|
end
|
data/syntropy.gemspec
CHANGED
@@ -1,32 +1,37 @@
|
|
1
1
|
require_relative './lib/syntropy/version'
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.
|
5
|
-
s.
|
6
|
-
s.
|
7
|
-
s.
|
8
|
-
s.
|
4
|
+
s.name = 'syntropy'
|
5
|
+
s.summary = 'Syntropic Web Framework'
|
6
|
+
s.version = Syntropy::VERSION
|
7
|
+
s.licenses = ['MIT']
|
8
|
+
s.author = 'Sharon Rosner'
|
9
|
+
s.email = 'sharon@noteflakes.com'
|
10
|
+
s.files = `git ls-files`.split
|
9
11
|
|
10
|
-
s.homepage
|
11
|
-
s.metadata
|
12
|
+
s.homepage = 'https://github.com/noteflakes/syntropy'
|
13
|
+
s.metadata = {
|
12
14
|
'homepage_uri' => 'https://github.com/noteflakes/syntropy',
|
13
15
|
'documentation_uri' => 'https://www.rubydoc.info/gems/syntropy',
|
14
16
|
'changelog_uri' => 'https://github.com/noteflakes/syntropy/blob/master/CHANGELOG.md'
|
15
17
|
}
|
16
|
-
s.rdoc_options
|
18
|
+
s.rdoc_options = ['--title', 'Extralite', '--main', 'README.md']
|
17
19
|
s.extra_rdoc_files = ['README.md']
|
18
20
|
s.require_paths = ['lib']
|
19
|
-
s.required_ruby_version = '>= 3.
|
21
|
+
s.required_ruby_version = '>= 3.4'
|
22
|
+
s.executables = ['syntropy']
|
20
23
|
|
21
|
-
s.add_dependency
|
22
|
-
s.add_dependency
|
23
|
-
s.add_dependency
|
24
|
-
s.add_dependency
|
25
|
-
s.add_dependency
|
24
|
+
s.add_dependency 'extralite', '2.12'
|
25
|
+
s.add_dependency 'json', '2.12.2'
|
26
|
+
s.add_dependency 'papercraft', '1.4'
|
27
|
+
s.add_dependency 'qeweney', '0.21'
|
28
|
+
s.add_dependency 'tp2', '0.12.2'
|
29
|
+
s.add_dependency 'uringmachine', '0.15'
|
26
30
|
|
27
|
-
s.
|
28
|
-
s.
|
31
|
+
s.add_dependency 'listen', '3.9.0'
|
32
|
+
s.add_dependency 'logger', '1.7.0'
|
33
|
+
|
34
|
+
s.add_development_dependency 'minitest', '5.25.5'
|
35
|
+
s.add_development_dependency 'rake', '13.3.0'
|
29
36
|
|
30
|
-
s.name = 'syntropy'
|
31
|
-
s.summary = 'Syntropic Web Framework'
|
32
37
|
end
|
data/test/app/about/index.rb
CHANGED
data/test/app/api+.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
class API < Syntropy::RPCAPI
|
2
|
-
def initialize
|
2
|
+
def initialize(env)
|
3
|
+
super(env)
|
3
4
|
@count = 0
|
4
5
|
end
|
5
6
|
|
@@ -9,11 +10,11 @@ class API < Syntropy::RPCAPI
|
|
9
10
|
|
10
11
|
def incr!(req)
|
11
12
|
if req.path != '/test/api'
|
12
|
-
raise Syntropy::Error.new(Qeweney::Status::TEAPOT, 'Teapot')
|
13
|
+
raise Syntropy::Error.new(Qeweney::Status::TEAPOT, 'Teapot')
|
13
14
|
end
|
14
15
|
|
15
16
|
@count += 1
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
|
-
API
|
20
|
+
export API
|
data/test/app/bar.rb
CHANGED
data/test/app/tmp.rb
ADDED
data/test/test_app.rb
CHANGED
@@ -6,7 +6,12 @@ class AppRoutingTest < Minitest::Test
|
|
6
6
|
APP_ROOT = File.join(__dir__, 'app')
|
7
7
|
|
8
8
|
def setup
|
9
|
-
@
|
9
|
+
@machine = UM.new
|
10
|
+
|
11
|
+
@tmp_path = '/test/tmp'
|
12
|
+
@tmp_fn = File.join(APP_ROOT, "tmp.rb")
|
13
|
+
|
14
|
+
@app = Syntropy::App.new(@machine, APP_ROOT, '/test', watch_files: 0.05)
|
10
15
|
end
|
11
16
|
|
12
17
|
def full_path(fn)
|
@@ -100,7 +105,21 @@ class AppRoutingTest < Minitest::Test
|
|
100
105
|
|
101
106
|
req = make_request(':method' => 'GET', ':path' => '/test/about/foo/bar')
|
102
107
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_app_file_watching
|
111
|
+
@machine.sleep 0.2
|
112
|
+
|
113
|
+
req = make_request(':method' => 'GET', ':path' => @tmp_path)
|
114
|
+
assert_equal 'foo', req.response_body
|
103
115
|
|
116
|
+
orig_body = IO.read(@tmp_fn)
|
117
|
+
IO.write(@tmp_fn, orig_body.gsub('foo', 'bar'))
|
118
|
+
@machine.sleep(0.5)
|
104
119
|
|
120
|
+
req = make_request(':method' => 'GET', ':path' => @tmp_path)
|
121
|
+
assert_equal 'bar', req.response_body
|
122
|
+
ensure
|
123
|
+
IO.write(@tmp_fn, orig_body) if orig_body
|
105
124
|
end
|
106
125
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class ConnectionPoolTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@machine = UM.new
|
8
|
+
@fn = "/tmp/#{rand(100000)}.db"
|
9
|
+
@cp = Syntropy::ConnectionPool.new(@machine, @fn, 4)
|
10
|
+
|
11
|
+
FileUtils.rm(@fn) rescue nil
|
12
|
+
@standalone_db = Extralite::Database.new(@fn)
|
13
|
+
@standalone_db.execute("create table foo (x,y, z)")
|
14
|
+
@standalone_db.execute("insert into foo values (1, 2, 3)")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_with_db
|
18
|
+
assert_equal 0, @cp.count
|
19
|
+
|
20
|
+
@cp.with_db do |db|
|
21
|
+
assert_kind_of Extralite::Database, db
|
22
|
+
|
23
|
+
records = db.query("select * from foo")
|
24
|
+
assert_equal [{x: 1, y: 2, z: 3}], records
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_equal 1, @cp.count
|
28
|
+
@cp.with_db { |db| assert_kind_of Extralite::Database, db }
|
29
|
+
assert_equal 1, @cp.count
|
30
|
+
|
31
|
+
dbs = []
|
32
|
+
ff = (1..2).map { |i|
|
33
|
+
@machine.spin {
|
34
|
+
@cp.with_db { |db|
|
35
|
+
dbs << db
|
36
|
+
@machine.sleep(0.05)
|
37
|
+
db.execute("insert into foo values (?, ?, ?)", i * 10 + 1, i * 10 + 2, i * 10 + 3)
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
@machine.join(*ff)
|
42
|
+
|
43
|
+
assert_equal 2, dbs.size
|
44
|
+
assert_equal 2, dbs.uniq.size
|
45
|
+
assert_equal 2, @cp.count
|
46
|
+
|
47
|
+
records = @standalone_db.query("select * from foo order by x")
|
48
|
+
assert_equal [
|
49
|
+
{x: 1, y: 2, z: 3},
|
50
|
+
{x: 11, y: 12, z: 13},
|
51
|
+
{x: 21, y: 22, z: 23},
|
52
|
+
], records
|
53
|
+
|
54
|
+
|
55
|
+
dbs = []
|
56
|
+
ff = (1..10).map { |i|
|
57
|
+
@machine.spin {
|
58
|
+
@cp.with_db { |db|
|
59
|
+
dbs << db
|
60
|
+
@machine.sleep(0.05 + rand * 0.05)
|
61
|
+
db.execute("insert into foo values (?, ?, ?)", i * 10 + 1, i * 10 + 2, i * 10 + 3)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
@machine.join(*ff)
|
66
|
+
|
67
|
+
assert_equal 10, dbs.size
|
68
|
+
assert_equal 4, dbs.uniq.size
|
69
|
+
assert_equal 4, @cp.count
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_with_db_reentrant
|
73
|
+
dbs = @cp.with_db do |db1|
|
74
|
+
@cp.with_db do |db2|
|
75
|
+
[db1, db2]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
assert_equal 1, dbs.uniq.size
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require_relative 'helper'
|
5
|
+
|
6
|
+
class FileWatchTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@machine = UM.new
|
9
|
+
@root = "/tmp/syntropy/#{rand(1000000).to_s(16)}"
|
10
|
+
FileUtils.mkdir_p(@root)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_file_watch
|
14
|
+
queue = UM::Queue.new
|
15
|
+
|
16
|
+
f = @machine.spin do
|
17
|
+
Syntropy.file_watch(@machine, @root, period: 0.01) { @machine.push(queue, it) }
|
18
|
+
end
|
19
|
+
@machine.sleep(0.05)
|
20
|
+
assert_equal 0, queue.count
|
21
|
+
|
22
|
+
fn = File.join(@root, 'foo.bar')
|
23
|
+
IO.write(fn, 'abc')
|
24
|
+
assert_equal fn, @machine.shift(queue)
|
25
|
+
|
26
|
+
fn = File.join(@root, 'foo.bar')
|
27
|
+
IO.write(fn, 'def')
|
28
|
+
assert_equal fn, @machine.shift(queue)
|
29
|
+
|
30
|
+
FileUtils.rm(fn)
|
31
|
+
assert_equal fn, @machine.shift(queue)
|
32
|
+
ensure
|
33
|
+
@machine.schedule(f, UM::Terminate)
|
34
|
+
# @machine.join(f)
|
35
|
+
end
|
36
|
+
end
|
data/test/test_module.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class ModuleTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@machine = UM.new
|
8
|
+
@root = File.join(__dir__, 'app')
|
9
|
+
@env = { baz: 42 }
|
10
|
+
@loader = Syntropy::ModuleLoader.new(@root, @env)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_module_loading
|
14
|
+
mod = @loader.load('_lib/klass')
|
15
|
+
assert_equal :bar, mod.foo
|
16
|
+
assert_equal 42, mod.bar
|
17
|
+
|
18
|
+
assert_raises(RuntimeError) { @loader.load('_lib/foo') }
|
19
|
+
assert_raises(RuntimeError) { @loader.load('_lib/missing-export') }
|
20
|
+
|
21
|
+
mod = @loader.load('_lib/callable')
|
22
|
+
assert_kind_of Syntropy::Module, mod
|
23
|
+
assert_equal 'barbarbar', mod.call(3)
|
24
|
+
assert_raises(NoMethodError) { mod.foo(2) }
|
25
|
+
assert_equal 42, mod.bar
|
26
|
+
|
27
|
+
mod = @loader.load('_lib/klass')
|
28
|
+
assert_equal :bar, mod.foo
|
29
|
+
@env[:baz] += 1
|
30
|
+
assert_equal 43, mod.bar
|
31
|
+
end
|
32
|
+
end
|
data/test/test_rpc_api.rb
CHANGED
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.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
9
9
|
cert_chain: []
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: extralite
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - '='
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.12'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - '='
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '2.12'
|
12
26
|
- !ruby/object:Gem::Dependency
|
13
27
|
name: json
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -23,6 +37,20 @@ dependencies:
|
|
23
37
|
- - '='
|
24
38
|
- !ruby/object:Gem::Version
|
25
39
|
version: 2.12.2
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: papercraft
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.4'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.4'
|
26
54
|
- !ruby/object:Gem::Dependency
|
27
55
|
name: qeweney
|
28
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,47 +66,61 @@ dependencies:
|
|
38
66
|
- !ruby/object:Gem::Version
|
39
67
|
version: '0.21'
|
40
68
|
- !ruby/object:Gem::Dependency
|
41
|
-
name:
|
69
|
+
name: tp2
|
42
70
|
requirement: !ruby/object:Gem::Requirement
|
43
71
|
requirements:
|
44
72
|
- - '='
|
45
73
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
74
|
+
version: 0.12.2
|
47
75
|
type: :runtime
|
48
76
|
prerelease: false
|
49
77
|
version_requirements: !ruby/object:Gem::Requirement
|
50
78
|
requirements:
|
51
79
|
- - '='
|
52
80
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
81
|
+
version: 0.12.2
|
54
82
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
83
|
+
name: uringmachine
|
56
84
|
requirement: !ruby/object:Gem::Requirement
|
57
85
|
requirements:
|
58
86
|
- - '='
|
59
87
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.
|
88
|
+
version: '0.15'
|
61
89
|
type: :runtime
|
62
90
|
prerelease: false
|
63
91
|
version_requirements: !ruby/object:Gem::Requirement
|
64
92
|
requirements:
|
65
93
|
- - '='
|
66
94
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.
|
95
|
+
version: '0.15'
|
68
96
|
- !ruby/object:Gem::Dependency
|
69
|
-
name:
|
97
|
+
name: listen
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 3.9.0
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 3.9.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: logger
|
70
112
|
requirement: !ruby/object:Gem::Requirement
|
71
113
|
requirements:
|
72
114
|
- - '='
|
73
115
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
116
|
+
version: 1.7.0
|
75
117
|
type: :runtime
|
76
118
|
prerelease: false
|
77
119
|
version_requirements: !ruby/object:Gem::Requirement
|
78
120
|
requirements:
|
79
121
|
- - '='
|
80
122
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
123
|
+
version: 1.7.0
|
82
124
|
- !ruby/object:Gem::Dependency
|
83
125
|
name: minitest
|
84
126
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,36 +150,48 @@ dependencies:
|
|
108
150
|
- !ruby/object:Gem::Version
|
109
151
|
version: 13.3.0
|
110
152
|
email: sharon@noteflakes.com
|
111
|
-
executables:
|
153
|
+
executables:
|
154
|
+
- syntropy
|
112
155
|
extensions: []
|
113
156
|
extra_rdoc_files:
|
114
157
|
- README.md
|
115
158
|
files:
|
116
159
|
- ".github/workflows/test.yml"
|
117
160
|
- ".gitignore"
|
161
|
+
- ".rubocop.yml"
|
118
162
|
- CHANGELOG.md
|
119
163
|
- Gemfile
|
120
164
|
- LICENSE
|
121
165
|
- README.md
|
122
166
|
- Rakefile
|
123
167
|
- TODO.md
|
168
|
+
- bin/syntropy
|
124
169
|
- lib/syntropy.rb
|
125
170
|
- lib/syntropy/app.rb
|
126
|
-
- lib/syntropy/
|
171
|
+
- lib/syntropy/connection_pool.rb
|
127
172
|
- lib/syntropy/errors.rb
|
173
|
+
- lib/syntropy/file_watch.rb
|
174
|
+
- lib/syntropy/module.rb
|
128
175
|
- lib/syntropy/rpc_api.rb
|
129
176
|
- lib/syntropy/version.rb
|
130
177
|
- syntropy.gemspec
|
131
178
|
- test/app/_layout/default.rb
|
179
|
+
- test/app/_lib/callable.rb
|
180
|
+
- test/app/_lib/klass.rb
|
181
|
+
- test/app/_lib/missing-export.rb
|
132
182
|
- test/app/about/foo.md
|
133
183
|
- test/app/about/index.rb
|
134
184
|
- test/app/api+.rb
|
135
185
|
- test/app/assets/style.css
|
136
186
|
- test/app/bar.rb
|
137
187
|
- test/app/index.html
|
188
|
+
- test/app/tmp.rb
|
138
189
|
- test/helper.rb
|
139
190
|
- test/run.rb
|
140
191
|
- test/test_app.rb
|
192
|
+
- test/test_connection_pool.rb
|
193
|
+
- test/test_file_watch.rb
|
194
|
+
- test/test_module.rb
|
141
195
|
- test/test_rpc_api.rb
|
142
196
|
- test/test_validation.rb
|
143
197
|
homepage: https://github.com/noteflakes/syntropy
|
@@ -158,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
158
212
|
requirements:
|
159
213
|
- - ">="
|
160
214
|
- !ruby/object:Gem::Version
|
161
|
-
version: '3.
|
215
|
+
version: '3.4'
|
162
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
217
|
requirements:
|
164
218
|
- - ">="
|
data/lib/syntropy/context.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# # frozen_string_literal: true
|
2
|
-
|
3
|
-
# require 'syntropy/errors'
|
4
|
-
|
5
|
-
# module Syntropy
|
6
|
-
# class Context
|
7
|
-
# attr_reader :request
|
8
|
-
|
9
|
-
# def initialize(request)
|
10
|
-
# @request = request
|
11
|
-
# end
|
12
|
-
|
13
|
-
# def params
|
14
|
-
# @request.query
|
15
|
-
# end
|
16
|
-
|
17
|
-
# def validate_param(name, *clauses)
|
18
|
-
# value = @request.query[name]
|
19
|
-
# clauses.each do |c|
|
20
|
-
# valid = param_is_valid?(value, c)
|
21
|
-
# raise(Syntropy::ValidationError, 'Validation error') if !valid
|
22
|
-
# value = param_convert(value, c)
|
23
|
-
# end
|
24
|
-
# value
|
25
|
-
# end
|
26
|
-
|
27
|
-
# BOOL_REGEXP = /^(t|f|true|false|on|off|1|0|yes|no)$/
|
28
|
-
# BOOL_TRUE_REGEXP = /^(t|true|on|1|yes)$/
|
29
|
-
# INTEGER_REGEXP = /^[\+\-]?[0-9]+$/
|
30
|
-
# FLOAT_REGEXP = /^[\+\-]?[0-9]+(\.[0-9]+)?$/
|
31
|
-
|
32
|
-
# def param_is_valid?(value, cond)
|
33
|
-
# if cond == :bool
|
34
|
-
# return (value && value =~ BOOL_REGEXP)
|
35
|
-
# elsif cond == Integer
|
36
|
-
# return (value && value =~ INTEGER_REGEXP)
|
37
|
-
# elsif cond == Float
|
38
|
-
# return (value && value =~ FLOAT_REGEXP)
|
39
|
-
# elsif cond.is_a?(Array)
|
40
|
-
# return cond.any? { |c| param_is_valid?(value, c) }
|
41
|
-
# end
|
42
|
-
|
43
|
-
# cond === value
|
44
|
-
# end
|
45
|
-
|
46
|
-
# def param_convert(value, klass)
|
47
|
-
# if klass == :bool
|
48
|
-
# value = value =~ BOOL_TRUE_REGEXP ? true : false
|
49
|
-
# elsif klass == Integer
|
50
|
-
# value = value.to_i
|
51
|
-
# elsif klass == Float
|
52
|
-
# value = value.to_f
|
53
|
-
# else
|
54
|
-
# value
|
55
|
-
# end
|
56
|
-
# end
|
57
|
-
# end
|
58
|
-
# end
|