factbase 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/actionlint.yml +1 -1
- data/.github/workflows/codecov.yml +2 -2
- data/.github/workflows/copyrights.yml +5 -1
- data/.github/workflows/markdown-lint.yml +1 -1
- data/.github/workflows/pdd.yml +1 -1
- data/.github/workflows/rake.yml +2 -2
- data/.github/workflows/xcop.yml +5 -1
- data/.github/workflows/yamllint.yml +1 -1
- data/.rubocop.yml +2 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +14 -13
- data/lib/factbase/fact.rb +3 -3
- data/lib/factbase/looged.rb +25 -20
- data/lib/factbase/term.rb +9 -8
- data/lib/factbase/terms/math.rb +13 -5
- data/lib/factbase/terms/system.rb +1 -1
- data/lib/factbase.rb +1 -1
- data/test/factbase/terms/test_math.rb +20 -0
- data/test/factbase/terms/test_system.rb +12 -0
- data/test/factbase/test_inv.rb +12 -9
- data/test/factbase/test_rules.rb +4 -3
- data/test/test_factbase.rb +5 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da15ba272d70a23c1f7138efd317a27e19f37846c7305b005e75fb23d9222004
|
4
|
+
data.tar.gz: 37588b7eb0b03659b5e6373a4f42bda9e89cd652cc954bc6a7988faf705d35ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba914de891e44ee3580e42be96710c3a2deecd75c2ba7fae07d78bb84920af2ffbf602b587e0aa81c1b138b9603f0c58903c21a933177e04e3fdcf1124d367b6
|
7
|
+
data.tar.gz: 3c681187d0df5285eb0922f7ae718c12009c26adb84c9a9ba7ad2676c095e5dcd68e01dce538a87c52f02e3475d62e4833349995c6d69cd444f3a9730fd4ba52
|
@@ -25,12 +25,12 @@ name: codecov
|
|
25
25
|
- master
|
26
26
|
jobs:
|
27
27
|
codecov:
|
28
|
-
runs-on: ubuntu-
|
28
|
+
runs-on: ubuntu-24.04
|
29
29
|
steps:
|
30
30
|
- uses: actions/checkout@v4
|
31
31
|
- uses: ruby/setup-ruby@v1
|
32
32
|
with:
|
33
|
-
ruby-version: 3.
|
33
|
+
ruby-version: 3.3
|
34
34
|
bundler-cache: true
|
35
35
|
- run: bundle install
|
36
36
|
- run: bundle exec rake
|
@@ -21,10 +21,14 @@
|
|
21
21
|
name: copyrights
|
22
22
|
'on':
|
23
23
|
push:
|
24
|
+
branches:
|
25
|
+
- master
|
24
26
|
pull_request:
|
27
|
+
branches:
|
28
|
+
- master
|
25
29
|
jobs:
|
26
30
|
copyrights:
|
27
|
-
runs-on: ubuntu-
|
31
|
+
runs-on: ubuntu-24.04
|
28
32
|
steps:
|
29
33
|
- uses: actions/checkout@v4
|
30
34
|
- uses: yegor256/copyrights-action@0.0.5
|
data/.github/workflows/pdd.yml
CHANGED
data/.github/workflows/rake.yml
CHANGED
data/.github/workflows/xcop.yml
CHANGED
@@ -21,10 +21,14 @@
|
|
21
21
|
name: xcop
|
22
22
|
'on':
|
23
23
|
push:
|
24
|
+
branches:
|
25
|
+
- master
|
24
26
|
pull_request:
|
27
|
+
branches:
|
28
|
+
- master
|
25
29
|
jobs:
|
26
30
|
xcop:
|
27
|
-
runs-on: ubuntu-
|
31
|
+
runs-on: ubuntu-24.04
|
28
32
|
steps:
|
29
33
|
- uses: actions/checkout@v4
|
30
34
|
- uses: g4s8/xcop-action@master
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -27,9 +27,9 @@ gem 'minitest', '5.24.1', require: false
|
|
27
27
|
gem 'minitest-reporters', '1.7.1', require: false
|
28
28
|
gem 'rake', '13.2.1', require: false
|
29
29
|
gem 'rspec-rails', '6.1.3', require: false
|
30
|
-
gem 'rubocop', '1.65.
|
30
|
+
gem 'rubocop', '1.65.1', require: false
|
31
31
|
gem 'rubocop-performance', '1.21.1', require: false
|
32
|
-
gem 'rubocop-rspec', '3.0.
|
32
|
+
gem 'rubocop-rspec', '3.0.4', require: false
|
33
33
|
gem 'simplecov', '0.22.0', require: false
|
34
34
|
gem 'simplecov-cobertura', '2.1.0', require: false
|
35
35
|
gem 'yard', '0.9.36', require: false
|
data/Gemfile.lock
CHANGED
@@ -51,7 +51,7 @@ GEM
|
|
51
51
|
crass (1.0.6)
|
52
52
|
decoor (0.0.1)
|
53
53
|
diff-lcs (1.5.1)
|
54
|
-
docile (1.4.
|
54
|
+
docile (1.4.1)
|
55
55
|
drb (2.2.1)
|
56
56
|
erubi (1.13.0)
|
57
57
|
i18n (1.14.5)
|
@@ -65,7 +65,7 @@ GEM
|
|
65
65
|
loofah (2.22.0)
|
66
66
|
crass (~> 1.0.2)
|
67
67
|
nokogiri (>= 1.12.0)
|
68
|
-
loog (0.5.
|
68
|
+
loog (0.5.3)
|
69
69
|
minitest (5.24.1)
|
70
70
|
minitest-reporters (1.7.1)
|
71
71
|
ansi
|
@@ -73,13 +73,13 @@ GEM
|
|
73
73
|
minitest (>= 5.0)
|
74
74
|
ruby-progressbar
|
75
75
|
mutex_m (0.2.0)
|
76
|
-
nokogiri (1.16.
|
76
|
+
nokogiri (1.16.7-arm64-darwin)
|
77
77
|
racc (~> 1.4)
|
78
|
-
nokogiri (1.16.
|
78
|
+
nokogiri (1.16.7-x64-mingw-ucrt)
|
79
79
|
racc (~> 1.4)
|
80
|
-
nokogiri (1.16.
|
80
|
+
nokogiri (1.16.7-x86_64-darwin)
|
81
81
|
racc (~> 1.4)
|
82
|
-
nokogiri (1.16.
|
82
|
+
nokogiri (1.16.7-x86_64-linux)
|
83
83
|
racc (~> 1.4)
|
84
84
|
others (0.0.3)
|
85
85
|
parallel (1.25.1)
|
@@ -88,7 +88,7 @@ GEM
|
|
88
88
|
racc
|
89
89
|
psych (5.1.2)
|
90
90
|
stringio
|
91
|
-
racc (1.8.
|
91
|
+
racc (1.8.1)
|
92
92
|
rack (3.1.7)
|
93
93
|
rack-session (2.0.0)
|
94
94
|
rack (>= 3.0.0)
|
@@ -119,7 +119,7 @@ GEM
|
|
119
119
|
regexp_parser (2.9.2)
|
120
120
|
reline (0.5.9)
|
121
121
|
io-console (~> 0.5)
|
122
|
-
rexml (3.3.
|
122
|
+
rexml (3.3.4)
|
123
123
|
strscan
|
124
124
|
rspec-core (3.13.0)
|
125
125
|
rspec-support (~> 3.13.0)
|
@@ -138,7 +138,7 @@ GEM
|
|
138
138
|
rspec-mocks (~> 3.13)
|
139
139
|
rspec-support (~> 3.13)
|
140
140
|
rspec-support (3.13.1)
|
141
|
-
rubocop (1.65.
|
141
|
+
rubocop (1.65.1)
|
142
142
|
json (~> 2.3)
|
143
143
|
language_server-protocol (>= 3.17.0)
|
144
144
|
parallel (~> 1.10)
|
@@ -154,7 +154,7 @@ GEM
|
|
154
154
|
rubocop-performance (1.21.1)
|
155
155
|
rubocop (>= 1.48.1, < 2.0)
|
156
156
|
rubocop-ast (>= 1.31.1, < 2.0)
|
157
|
-
rubocop-rspec (3.0.
|
157
|
+
rubocop-rspec (3.0.4)
|
158
158
|
rubocop (~> 1.61)
|
159
159
|
ruby-progressbar (1.13.0)
|
160
160
|
simplecov (0.22.0)
|
@@ -176,12 +176,13 @@ GEM
|
|
176
176
|
webrick (1.8.1)
|
177
177
|
yaml (0.3.0)
|
178
178
|
yard (0.9.36)
|
179
|
-
zeitwerk (2.6.
|
179
|
+
zeitwerk (2.6.17)
|
180
180
|
|
181
181
|
PLATFORMS
|
182
182
|
arm64-darwin-22
|
183
183
|
x64-mingw-ucrt
|
184
184
|
x86_64-darwin-20
|
185
|
+
x86_64-darwin-21
|
185
186
|
x86_64-linux
|
186
187
|
|
187
188
|
DEPENDENCIES
|
@@ -190,9 +191,9 @@ DEPENDENCIES
|
|
190
191
|
minitest-reporters (= 1.7.1)
|
191
192
|
rake (= 13.2.1)
|
192
193
|
rspec-rails (= 6.1.3)
|
193
|
-
rubocop (= 1.65.
|
194
|
+
rubocop (= 1.65.1)
|
194
195
|
rubocop-performance (= 1.21.1)
|
195
|
-
rubocop-rspec (= 3.0.
|
196
|
+
rubocop-rspec (= 3.0.4)
|
196
197
|
simplecov (= 0.22.0)
|
197
198
|
simplecov-cobertura (= 2.1.0)
|
198
199
|
yard (= 0.9.36)
|
data/lib/factbase/fact.rb
CHANGED
@@ -71,9 +71,9 @@ class Factbase::Fact
|
|
71
71
|
raise "Invalid prop name '#{kk}'" unless kk.match?(/^[a-z_][_a-zA-Z0-9]*$/)
|
72
72
|
raise "Prohibited prop name '#{kk}'" if methods.include?(kk.to_sym)
|
73
73
|
v = args[1]
|
74
|
-
raise "
|
75
|
-
raise "
|
76
|
-
raise "
|
74
|
+
raise "The value of '#{kk}' can't be nil" if v.nil?
|
75
|
+
raise "The value of '#{kk}' can't be empty" if v == ''
|
76
|
+
raise "The type '#{v.class}' of '#{kk}' is not allowed" unless [String, Integer, Float, Time].include?(v.class)
|
77
77
|
v = v.utc if v.is_a?(Time)
|
78
78
|
@mutex.synchronize do
|
79
79
|
@map[kk] = [] if @map[kk].nil?
|
data/lib/factbase/looged.rb
CHANGED
@@ -59,13 +59,14 @@ class Factbase::Looged
|
|
59
59
|
start = Time.now
|
60
60
|
id = nil
|
61
61
|
rollback = false
|
62
|
-
r =
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
62
|
+
r =
|
63
|
+
@fb.txn(this) do |fbt|
|
64
|
+
id = fbt.object_id
|
65
|
+
yield fbt
|
66
|
+
rescue Factbase::Rollback => e
|
67
|
+
rollback = true
|
68
|
+
raise e
|
69
|
+
end
|
69
70
|
if rollback
|
70
71
|
@loog.debug("Txn ##{id} rolled back in #{start.ago}")
|
71
72
|
else
|
@@ -120,9 +121,10 @@ class Factbase::Looged
|
|
120
121
|
def one(params = {})
|
121
122
|
q = Factbase::Syntax.new(@expr).to_term.to_s
|
122
123
|
r = nil
|
123
|
-
tail =
|
124
|
-
|
125
|
-
|
124
|
+
tail =
|
125
|
+
Factbase::Looged.elapsed do
|
126
|
+
r = @fb.query(@expr).one(params)
|
127
|
+
end
|
126
128
|
if r.nil?
|
127
129
|
@loog.debug("Nothing found by '#{q}' #{tail}")
|
128
130
|
else
|
@@ -135,9 +137,10 @@ class Factbase::Looged
|
|
135
137
|
q = Factbase::Syntax.new(@expr).to_term.to_s
|
136
138
|
if block_given?
|
137
139
|
r = nil
|
138
|
-
tail =
|
139
|
-
|
140
|
-
|
140
|
+
tail =
|
141
|
+
Factbase::Looged.elapsed do
|
142
|
+
r = @fb.query(@expr).each(params, &)
|
143
|
+
end
|
141
144
|
raise ".each of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
|
142
145
|
if r.zero?
|
143
146
|
@loog.debug("Nothing found by '#{q}' #{tail}")
|
@@ -147,11 +150,12 @@ class Factbase::Looged
|
|
147
150
|
r
|
148
151
|
else
|
149
152
|
array = []
|
150
|
-
tail =
|
151
|
-
|
152
|
-
|
153
|
+
tail =
|
154
|
+
Factbase::Looged.elapsed do
|
155
|
+
@fb.query(@expr).each(params) do |f|
|
156
|
+
array << f
|
157
|
+
end
|
153
158
|
end
|
154
|
-
end
|
155
159
|
if array.empty?
|
156
160
|
@loog.debug("Nothing found by '#{q}' #{tail}")
|
157
161
|
else
|
@@ -164,9 +168,10 @@ class Factbase::Looged
|
|
164
168
|
def delete!
|
165
169
|
r = nil
|
166
170
|
before = @fb.size
|
167
|
-
tail =
|
168
|
-
|
169
|
-
|
171
|
+
tail =
|
172
|
+
Factbase::Looged.elapsed do
|
173
|
+
r = @fb.query(@expr).delete!
|
174
|
+
end
|
170
175
|
raise ".delete! of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
|
171
176
|
if before.zero?
|
172
177
|
@loog.debug("There were no facts, nothing deleted by '#{@expr}' #{tail}")
|
data/lib/factbase/term.rb
CHANGED
@@ -122,15 +122,16 @@ class Factbase::Term
|
|
122
122
|
def to_s
|
123
123
|
items = []
|
124
124
|
items << @op
|
125
|
-
items +=
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
o.
|
130
|
-
|
131
|
-
|
125
|
+
items +=
|
126
|
+
@operands.map do |o|
|
127
|
+
if o.is_a?(String)
|
128
|
+
"'#{o.gsub("'", "\\\\'").gsub('"', '\\\\"')}'"
|
129
|
+
elsif o.is_a?(Time)
|
130
|
+
o.utc.iso8601
|
131
|
+
else
|
132
|
+
o.to_s
|
133
|
+
end
|
132
134
|
end
|
133
|
-
end
|
134
135
|
"(#{items.join(' ')})"
|
135
136
|
end
|
136
137
|
|
data/lib/factbase/terms/math.rb
CHANGED
@@ -63,6 +63,14 @@ module Factbase::Term::Math
|
|
63
63
|
cmp(:>, fact, maps)
|
64
64
|
end
|
65
65
|
|
66
|
+
def lte(fact, maps)
|
67
|
+
cmp(:<=, fact, maps)
|
68
|
+
end
|
69
|
+
|
70
|
+
def gte(fact, maps)
|
71
|
+
cmp(:>=, fact, maps)
|
72
|
+
end
|
73
|
+
|
66
74
|
def cmp(op, fact, maps)
|
67
75
|
assert_args(2)
|
68
76
|
lefts = the_values(0, fact, maps)
|
@@ -93,15 +101,15 @@ module Factbase::Term::Math
|
|
93
101
|
num = num.to_i
|
94
102
|
r =
|
95
103
|
case units
|
96
|
-
when 'seconds'
|
104
|
+
when 'seconds', 'second'
|
97
105
|
num
|
98
|
-
when 'minutes'
|
106
|
+
when 'minutes', 'minute'
|
99
107
|
num * 60
|
100
|
-
when 'hours'
|
108
|
+
when 'hours', 'hour'
|
101
109
|
num * 60 * 60
|
102
|
-
when 'days'
|
110
|
+
when 'days', 'day'
|
103
111
|
num * 60 * 60 * 24
|
104
|
-
when 'weeks'
|
112
|
+
when 'weeks', 'week'
|
105
113
|
num * 60 * 60 * 24 * 7
|
106
114
|
else
|
107
115
|
raise "Unknown time unit '#{units}' in '#{r}"
|
data/lib/factbase.rb
CHANGED
@@ -81,7 +81,7 @@ require 'yaml'
|
|
81
81
|
# License:: MIT
|
82
82
|
class Factbase
|
83
83
|
# Current version of the gem (changed by .rultor.yml on every release)
|
84
|
-
VERSION = '0.
|
84
|
+
VERSION = '0.3.0'
|
85
85
|
|
86
86
|
# An exception that may be thrown in a transaction, to roll it back.
|
87
87
|
class Rollback < StandardError; end
|
@@ -69,6 +69,20 @@ class TestMath < Minitest::Test
|
|
69
69
|
assert(!t.evaluate(fact('bar' => 100), []))
|
70
70
|
end
|
71
71
|
|
72
|
+
def test_gte
|
73
|
+
t = Factbase::Term.new(:gte, [:foo, 42])
|
74
|
+
assert(t.evaluate(fact('foo' => 100), []))
|
75
|
+
assert(t.evaluate(fact('foo' => 42), []))
|
76
|
+
assert(!t.evaluate(fact('foo' => 41), []))
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_lte
|
80
|
+
t = Factbase::Term.new(:lte, [:foo, 42])
|
81
|
+
assert(t.evaluate(fact('foo' => 41), []))
|
82
|
+
assert(t.evaluate(fact('foo' => 42), []))
|
83
|
+
assert(!t.evaluate(fact('foo' => 100), []))
|
84
|
+
end
|
85
|
+
|
72
86
|
def test_gt
|
73
87
|
t = Factbase::Term.new(:gt, [:foo, 42])
|
74
88
|
assert(t.evaluate(fact('foo' => [100]), []))
|
@@ -115,4 +129,10 @@ class TestMath < Minitest::Test
|
|
115
129
|
assert_equal(Time.parse('2024-01-01T06:04'), t.evaluate(fact('foo' => Time.parse('2024-01-01T10:04')), []))
|
116
130
|
assert(t.evaluate(fact, []).nil?)
|
117
131
|
end
|
132
|
+
|
133
|
+
def test_minus_time_singular
|
134
|
+
t = Factbase::Term.new(:minus, [:foo, '1 hour'])
|
135
|
+
assert_equal(Time.parse('2024-01-01T09:04'), t.evaluate(fact('foo' => Time.parse('2024-01-01T10:04')), []))
|
136
|
+
assert(t.evaluate(fact, []).nil?)
|
137
|
+
end
|
118
138
|
end
|
@@ -34,4 +34,16 @@ class TestSystem < Minitest::Test
|
|
34
34
|
t = Factbase::Term.new(:env, ['FOO', ''])
|
35
35
|
assert_equal('bar', t.evaluate(fact, []))
|
36
36
|
end
|
37
|
+
|
38
|
+
def test_default
|
39
|
+
ENV.delete('FOO')
|
40
|
+
t = Factbase::Term.new(:env, ['FOO', 'мой друг'])
|
41
|
+
assert_equal('мой друг', t.evaluate(fact, []))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_when_default_is_absent
|
45
|
+
ENV.delete('FOO')
|
46
|
+
t = Factbase::Term.new(:env, ['FOO'])
|
47
|
+
assert_raises { t.evaluate(fact, []) }
|
48
|
+
end
|
37
49
|
end
|
data/test/factbase/test_inv.rb
CHANGED
@@ -32,9 +32,10 @@ require_relative '../../lib/factbase/pre'
|
|
32
32
|
# License:: MIT
|
33
33
|
class TestInv < Minitest::Test
|
34
34
|
def test_simple_checking
|
35
|
-
fb =
|
36
|
-
|
37
|
-
|
35
|
+
fb =
|
36
|
+
Factbase::Inv.new(Factbase.new) do |p, v|
|
37
|
+
raise 'oops' if v.is_a?(String) && p == 'b'
|
38
|
+
end
|
38
39
|
f = fb.insert
|
39
40
|
f.a = 42
|
40
41
|
assert_raises do
|
@@ -46,12 +47,14 @@ class TestInv < Minitest::Test
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def test_pre_and_inv
|
49
|
-
fb =
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
fb =
|
51
|
+
Factbase::Inv.new(Factbase.new) do |p, v|
|
52
|
+
raise 'oops' if v.is_a?(String) && p == 'b'
|
53
|
+
end
|
54
|
+
fb =
|
55
|
+
Factbase::Pre.new(fb) do |f|
|
56
|
+
f.id = 42
|
57
|
+
end
|
55
58
|
f = fb.insert
|
56
59
|
assert_equal(42, f.id)
|
57
60
|
end
|
data/test/factbase/test_rules.rb
CHANGED
@@ -96,9 +96,10 @@ class TestRules < Minitest::Test
|
|
96
96
|
|
97
97
|
def test_in_combination_with_pre
|
98
98
|
fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
|
99
|
-
fb =
|
100
|
-
|
101
|
-
|
99
|
+
fb =
|
100
|
+
Factbase::Pre.new(fb) do |f|
|
101
|
+
f.hello = 42
|
102
|
+
end
|
102
103
|
ok = false
|
103
104
|
assert_raises do
|
104
105
|
fb.txn do |fbt|
|
data/test/test_factbase.rb
CHANGED
@@ -211,10 +211,11 @@ class TestFactbase < Minitest::Test
|
|
211
211
|
|
212
212
|
def test_txn_with_rollback
|
213
213
|
fb = Factbase.new
|
214
|
-
modified =
|
215
|
-
|
216
|
-
|
217
|
-
|
214
|
+
modified =
|
215
|
+
fb.txn do |fbt|
|
216
|
+
fbt.insert.bar = 33
|
217
|
+
raise Factbase::Rollback
|
218
|
+
end
|
218
219
|
assert(!modified)
|
219
220
|
assert_equal(0, fb.query('(always)').each.to_a.size)
|
220
221
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backtrace
|