factbase 0.9.5 → 0.9.7
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 +4 -2
- data/.rultor.yml +1 -0
- data/Gemfile +9 -9
- data/Gemfile.lock +31 -127
- data/README.md +25 -24
- data/Rakefile +7 -14
- data/factbase.gemspec +6 -5
- data/lib/factbase/cached/cached_query.rb +4 -1
- data/lib/factbase/fact.rb +0 -5
- data/lib/factbase/indexed/indexed_query.rb +3 -1
- data/lib/factbase/indexed/indexed_term.rb +71 -10
- data/lib/factbase/logged.rb +20 -31
- data/lib/factbase/query.rb +1 -1
- data/lib/factbase/rules.rb +1 -1
- data/lib/factbase/taped.rb +4 -1
- data/lib/factbase/term.rb +1 -0
- data/lib/factbase.rb +1 -1
- data/test/factbase/cached/test_cached_query.rb +21 -0
- data/test/factbase/indexed/test_indexed_term.rb +10 -2
- data/test/factbase/test_logged.rb +19 -0
- data/test/factbase/test_query.rb +81 -6
- data/test/factbase/test_taped.rb +12 -0
- data/test/factbase/test_term.rb +2 -0
- metadata +36 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7d1b649fb808d571609f3231f90dbd57ba57683993d52ee2eaddd674e2aeb65
|
4
|
+
data.tar.gz: 717ea095ae2e1092d71509b39f1581cfc4b65d47ca9f39cb704d694eabbd91d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f6955bdf61ad153a2cf956935310fbd1d59782a34e479ae94e48c70ab8a1002dfdf61f2384e968bbdedb0be58d19ea556841d7b7300aa110927f78f1fdabaf9
|
7
|
+
data.tar.gz: 2364a4421fcf35c42b6e316e33f11afaf4abc69b33502b475fa08fc28e2e45b8dbe138cf72d26b8938212d2807dfd8c3b50aa40b166e481e15f363d2cf5629c8
|
data/.rubocop.yml
CHANGED
@@ -20,6 +20,8 @@ Gemspec/RequiredRubyVersion:
|
|
20
20
|
Enabled: false
|
21
21
|
Metrics/MethodLength:
|
22
22
|
Enabled: false
|
23
|
+
Metrics/ModuleLength:
|
24
|
+
Enabled: false
|
23
25
|
Style/ClassAndModuleChildren:
|
24
26
|
Enabled: false
|
25
27
|
Layout/MultilineMethodCallIndentation:
|
@@ -29,9 +31,9 @@ Metrics/AbcSize:
|
|
29
31
|
Metrics/BlockLength:
|
30
32
|
Max: 50
|
31
33
|
Metrics/CyclomaticComplexity:
|
32
|
-
Max:
|
34
|
+
Max: 100
|
33
35
|
Metrics/PerceivedComplexity:
|
34
|
-
Max:
|
36
|
+
Max: 100
|
35
37
|
Metrics/ClassLength:
|
36
38
|
Enabled: false
|
37
39
|
Layout/EmptyLineAfterGuardClause:
|
data/.rultor.yml
CHANGED
data/Gemfile
CHANGED
@@ -6,18 +6,18 @@
|
|
6
6
|
source 'https://rubygems.org'
|
7
7
|
gemspec
|
8
8
|
|
9
|
-
gem 'minitest', '5.25
|
10
|
-
gem 'minitest-reporters', '1.7
|
9
|
+
gem 'minitest', '~>5.25', require: false
|
10
|
+
gem 'minitest-reporters', '~>1.7', require: false
|
11
11
|
gem 'os', '>0', require: false
|
12
12
|
gem 'qbash', '>0', require: false
|
13
|
-
gem 'rake', '13.2
|
14
|
-
gem '
|
15
|
-
gem 'rubocop', '1.74
|
13
|
+
gem 'rake', '~>13.2', require: false
|
14
|
+
gem 'rdoc', '~>6.13', require: false
|
15
|
+
gem 'rubocop', '~>1.74', require: false
|
16
16
|
gem 'rubocop-minitest', '>0', require: false
|
17
17
|
gem 'rubocop-performance', '>0', require: false
|
18
18
|
gem 'rubocop-rake', '>0', require: false
|
19
19
|
gem 'rubocop-rspec', '>0', require: false
|
20
|
-
gem 'simplecov', '0.22
|
21
|
-
gem 'simplecov-cobertura', '2.1
|
22
|
-
gem 'threads', '0.4
|
23
|
-
gem 'yard', '0.9
|
20
|
+
gem 'simplecov', '~>0.22', require: false
|
21
|
+
gem 'simplecov-cobertura', '~>2.1', require: false
|
22
|
+
gem 'threads', '~>0.4', require: false
|
23
|
+
gem 'yard', '~>0.9', require: false
|
data/Gemfile.lock
CHANGED
@@ -2,80 +2,34 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
factbase (0.0.0)
|
5
|
-
backtrace (
|
6
|
-
decoor (
|
5
|
+
backtrace (~> 0.4)
|
6
|
+
decoor (~> 0.0)
|
7
7
|
json (~> 2.7)
|
8
|
-
|
8
|
+
logger (~> 1.0)
|
9
|
+
loog (~> 0.6)
|
9
10
|
nokogiri (~> 1.10)
|
10
|
-
others (
|
11
|
-
tago (
|
11
|
+
others (~> 0.0)
|
12
|
+
tago (~> 0.0)
|
12
13
|
yaml (~> 0.3)
|
13
14
|
|
14
15
|
GEM
|
15
16
|
remote: https://rubygems.org/
|
16
17
|
specs:
|
17
|
-
actionpack (8.0.2)
|
18
|
-
actionview (= 8.0.2)
|
19
|
-
activesupport (= 8.0.2)
|
20
|
-
nokogiri (>= 1.8.5)
|
21
|
-
rack (>= 2.2.4)
|
22
|
-
rack-session (>= 1.0.1)
|
23
|
-
rack-test (>= 0.6.3)
|
24
|
-
rails-dom-testing (~> 2.2)
|
25
|
-
rails-html-sanitizer (~> 1.6)
|
26
|
-
useragent (~> 0.16)
|
27
|
-
actionview (8.0.2)
|
28
|
-
activesupport (= 8.0.2)
|
29
|
-
builder (~> 3.1)
|
30
|
-
erubi (~> 1.11)
|
31
|
-
rails-dom-testing (~> 2.2)
|
32
|
-
rails-html-sanitizer (~> 1.6)
|
33
|
-
activesupport (8.0.2)
|
34
|
-
base64
|
35
|
-
benchmark (>= 0.3)
|
36
|
-
bigdecimal
|
37
|
-
concurrent-ruby (~> 1.0, >= 1.3.1)
|
38
|
-
connection_pool (>= 2.2.5)
|
39
|
-
drb
|
40
|
-
i18n (>= 1.6, < 2)
|
41
|
-
logger (>= 1.4.2)
|
42
|
-
minitest (>= 5.1)
|
43
|
-
securerandom (>= 0.3)
|
44
|
-
tzinfo (~> 2.0, >= 2.0.5)
|
45
|
-
uri (>= 0.13.1)
|
46
18
|
ansi (1.5.0)
|
47
|
-
ast (2.4.
|
19
|
+
ast (2.4.3)
|
48
20
|
backtrace (0.4.0)
|
49
|
-
base64 (0.2.0)
|
50
|
-
benchmark (0.4.0)
|
51
|
-
bigdecimal (3.1.9)
|
52
21
|
builder (3.3.0)
|
53
22
|
concurrent-ruby (1.3.5)
|
54
|
-
connection_pool (2.5.0)
|
55
|
-
crass (1.0.6)
|
56
23
|
date (3.4.1)
|
57
24
|
decoor (0.0.1)
|
58
|
-
diff-lcs (1.6.0)
|
59
25
|
docile (1.4.1)
|
60
|
-
drb (2.2.1)
|
61
26
|
elapsed (0.0.1)
|
62
27
|
loog (> 0)
|
63
28
|
tago (> 0)
|
64
|
-
erubi (1.13.1)
|
65
|
-
i18n (1.14.7)
|
66
|
-
concurrent-ruby (~> 1.0)
|
67
|
-
io-console (0.8.0)
|
68
|
-
irb (1.15.1)
|
69
|
-
pp (>= 0.6.0)
|
70
|
-
rdoc (>= 4.0.0)
|
71
|
-
reline (>= 0.4.2)
|
72
29
|
json (2.10.2)
|
73
30
|
language_server-protocol (3.17.0.4)
|
74
31
|
lint_roller (1.1.0)
|
75
|
-
logger (1.
|
76
|
-
loofah (2.24.0)
|
77
|
-
crass (~> 1.0.2)
|
78
|
-
nokogiri (>= 1.12.0)
|
32
|
+
logger (1.7.0)
|
79
33
|
loog (0.6.0)
|
80
34
|
minitest (5.25.5)
|
81
35
|
minitest-reporters (1.7.1)
|
@@ -83,23 +37,21 @@ GEM
|
|
83
37
|
builder
|
84
38
|
minitest (>= 5.0)
|
85
39
|
ruby-progressbar
|
86
|
-
nokogiri (1.18.
|
40
|
+
nokogiri (1.18.6-arm64-darwin)
|
87
41
|
racc (~> 1.4)
|
88
|
-
nokogiri (1.18.
|
42
|
+
nokogiri (1.18.6-x64-mingw-ucrt)
|
89
43
|
racc (~> 1.4)
|
90
|
-
nokogiri (1.18.
|
44
|
+
nokogiri (1.18.6-x86_64-darwin)
|
91
45
|
racc (~> 1.4)
|
92
|
-
nokogiri (1.18.
|
46
|
+
nokogiri (1.18.6-x86_64-linux-gnu)
|
93
47
|
racc (~> 1.4)
|
94
48
|
os (1.1.4)
|
95
49
|
others (0.0.3)
|
96
50
|
parallel (1.26.3)
|
97
|
-
parser (3.3.7.
|
51
|
+
parser (3.3.7.3)
|
98
52
|
ast (~> 2.4.1)
|
99
53
|
racc
|
100
|
-
|
101
|
-
prettyprint
|
102
|
-
prettyprint (0.2.0)
|
54
|
+
prism (1.4.0)
|
103
55
|
psych (5.2.3)
|
104
56
|
date
|
105
57
|
stringio
|
@@ -109,55 +61,13 @@ GEM
|
|
109
61
|
loog (> 0)
|
110
62
|
tago (> 0)
|
111
63
|
racc (1.8.1)
|
112
|
-
rack (3.1.12)
|
113
|
-
rack-session (2.1.0)
|
114
|
-
base64 (>= 0.1.0)
|
115
|
-
rack (>= 3.0.0)
|
116
|
-
rack-test (2.2.0)
|
117
|
-
rack (>= 1.3)
|
118
|
-
rackup (2.2.1)
|
119
|
-
rack (>= 3)
|
120
|
-
rails-dom-testing (2.2.0)
|
121
|
-
activesupport (>= 5.0.0)
|
122
|
-
minitest
|
123
|
-
nokogiri (>= 1.6)
|
124
|
-
rails-html-sanitizer (1.6.2)
|
125
|
-
loofah (~> 2.21)
|
126
|
-
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
127
|
-
railties (8.0.2)
|
128
|
-
actionpack (= 8.0.2)
|
129
|
-
activesupport (= 8.0.2)
|
130
|
-
irb (~> 1.13)
|
131
|
-
rackup (>= 1.0.0)
|
132
|
-
rake (>= 12.2)
|
133
|
-
thor (~> 1.0, >= 1.2.2)
|
134
|
-
zeitwerk (~> 2.6)
|
135
64
|
rainbow (3.1.1)
|
136
65
|
rake (13.2.1)
|
137
|
-
rdoc (6.
|
66
|
+
rdoc (6.13.1)
|
138
67
|
psych (>= 4.0.0)
|
139
68
|
regexp_parser (2.10.0)
|
140
|
-
reline (0.6.0)
|
141
|
-
io-console (~> 0.5)
|
142
69
|
rexml (3.4.1)
|
143
|
-
|
144
|
-
rspec-support (~> 3.13.0)
|
145
|
-
rspec-expectations (3.13.3)
|
146
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
147
|
-
rspec-support (~> 3.13.0)
|
148
|
-
rspec-mocks (3.13.2)
|
149
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
150
|
-
rspec-support (~> 3.13.0)
|
151
|
-
rspec-rails (7.1.1)
|
152
|
-
actionpack (>= 7.0)
|
153
|
-
activesupport (>= 7.0)
|
154
|
-
railties (>= 7.0)
|
155
|
-
rspec-core (~> 3.13)
|
156
|
-
rspec-expectations (~> 3.13)
|
157
|
-
rspec-mocks (~> 3.13)
|
158
|
-
rspec-support (~> 3.13)
|
159
|
-
rspec-support (3.13.2)
|
160
|
-
rubocop (1.74.0)
|
70
|
+
rubocop (1.75.1)
|
161
71
|
json (~> 2.3)
|
162
72
|
language_server-protocol (~> 3.17.0.2)
|
163
73
|
lint_roller (~> 1.1.0)
|
@@ -165,11 +75,12 @@ GEM
|
|
165
75
|
parser (>= 3.3.0.2)
|
166
76
|
rainbow (>= 2.2.2, < 4.0)
|
167
77
|
regexp_parser (>= 2.9.3, < 3.0)
|
168
|
-
rubocop-ast (>= 1.
|
78
|
+
rubocop-ast (>= 1.43.0, < 2.0)
|
169
79
|
ruby-progressbar (~> 1.7)
|
170
80
|
unicode-display_width (>= 2.4.0, < 4.0)
|
171
|
-
rubocop-ast (1.
|
172
|
-
parser (>= 3.3.
|
81
|
+
rubocop-ast (1.43.0)
|
82
|
+
parser (>= 3.3.7.2)
|
83
|
+
prism (~> 1.4)
|
173
84
|
rubocop-minitest (0.37.1)
|
174
85
|
lint_roller (~> 1.1)
|
175
86
|
rubocop (>= 1.72.1, < 2.0)
|
@@ -185,7 +96,6 @@ GEM
|
|
185
96
|
lint_roller (~> 1.1)
|
186
97
|
rubocop (~> 1.72, >= 1.72.1)
|
187
98
|
ruby-progressbar (1.13.0)
|
188
|
-
securerandom (0.4.1)
|
189
99
|
simplecov (0.22.0)
|
190
100
|
docile (~> 1.1)
|
191
101
|
simplecov-html (~> 0.11)
|
@@ -195,22 +105,16 @@ GEM
|
|
195
105
|
simplecov (~> 0.19)
|
196
106
|
simplecov-html (0.13.1)
|
197
107
|
simplecov_json_formatter (0.1.4)
|
198
|
-
stringio (3.1.
|
199
|
-
tago (0.0
|
200
|
-
thor (1.3.2)
|
108
|
+
stringio (3.1.6)
|
109
|
+
tago (0.1.0)
|
201
110
|
threads (0.4.1)
|
202
111
|
backtrace (~> 0)
|
203
112
|
concurrent-ruby (~> 1.0)
|
204
|
-
tzinfo (2.0.6)
|
205
|
-
concurrent-ruby (~> 1.0)
|
206
113
|
unicode-display_width (3.1.4)
|
207
114
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
208
115
|
unicode-emoji (4.0.4)
|
209
|
-
uri (1.0.3)
|
210
|
-
useragent (0.16.11)
|
211
116
|
yaml (0.4.0)
|
212
117
|
yard (0.9.37)
|
213
|
-
zeitwerk (2.7.2)
|
214
118
|
|
215
119
|
PLATFORMS
|
216
120
|
arm64-darwin-22
|
@@ -223,21 +127,21 @@ PLATFORMS
|
|
223
127
|
|
224
128
|
DEPENDENCIES
|
225
129
|
factbase!
|
226
|
-
minitest (
|
227
|
-
minitest-reporters (
|
130
|
+
minitest (~> 5.25)
|
131
|
+
minitest-reporters (~> 1.7)
|
228
132
|
os (> 0)
|
229
133
|
qbash (> 0)
|
230
|
-
rake (
|
231
|
-
|
232
|
-
rubocop (
|
134
|
+
rake (~> 13.2)
|
135
|
+
rdoc (~> 6.13)
|
136
|
+
rubocop (~> 1.74)
|
233
137
|
rubocop-minitest (> 0)
|
234
138
|
rubocop-performance (> 0)
|
235
139
|
rubocop-rake (> 0)
|
236
140
|
rubocop-rspec (> 0)
|
237
|
-
simplecov (
|
238
|
-
simplecov-cobertura (
|
239
|
-
threads (
|
240
|
-
yard (
|
141
|
+
simplecov (~> 0.22)
|
142
|
+
simplecov-cobertura (~> 2.1)
|
143
|
+
threads (~> 0.4)
|
144
|
+
yard (~> 0.9)
|
241
145
|
|
242
146
|
BUNDLED WITH
|
243
147
|
2.5.16
|
data/README.md
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
[](http://rubydoc.info/github/yegor256/factbase/master/frames)
|
11
11
|
[](https://hitsofcode.com/view/github/yegor256/factbase)
|
12
12
|
[](https://github.com/yegor256/factbase/blob/master/LICENSE.txt)
|
13
|
+
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fyegor256%2Ffactbase?ref=badge_shield&issueType=license)
|
13
14
|
|
14
15
|
This Ruby gem manages an in-memory database of facts.
|
15
16
|
A fact is simply a map of properties and values.
|
@@ -209,33 +210,33 @@ This is the result of the benchmark:
|
|
209
210
|
<!-- benchmark_begin -->
|
210
211
|
```text
|
211
212
|
user system total real
|
212
|
-
insert 20000 facts 0.
|
213
|
-
export 20000 facts 0.
|
214
|
-
import
|
215
|
-
insert 10 facts 0.
|
216
|
-
query 10 times w/txn 1.
|
217
|
-
query 10 times w/o txn 0.
|
218
|
-
modify 10 attrs w/txn 1.
|
219
|
-
delete 10 facts w/txn 0.
|
220
|
-
(and (eq what 'issue-was-closed') (exists... -> 200
|
221
|
-
(and (eq what 'issue-was-closed') (exists... -> 200/txn
|
222
|
-
(and (eq what 'issue-was-closed') (exists... -> zero
|
223
|
-
(and (eq what 'issue-was-closed') (exists... -> zero/txn
|
224
|
-
(gt time '2024-03-23T03:21:43Z') 0.
|
225
|
-
(gt cost 50) 0.
|
226
|
-
(eq title 'Object Thinking 5000') 0.
|
227
|
-
(and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.
|
228
|
-
(eq id (agg (always) (max id))) 0.
|
229
|
-
(join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.
|
230
|
-
delete! 0.
|
231
|
-
Taped.append() x50000 0.
|
232
|
-
Taped.each() x125 1.
|
233
|
-
Taped.delete_if() x375 0.
|
213
|
+
insert 20000 facts 0.597725 0.004012 0.601737 ( 0.601785)
|
214
|
+
export 20000 facts 0.020481 0.003039 0.023520 ( 0.023523)
|
215
|
+
import 410961 bytes (20000 facts) 0.021204 0.002017 0.023221 ( 0.023223)
|
216
|
+
insert 10 facts 0.042456 0.002961 0.045417 ( 0.045418)
|
217
|
+
query 10 times w/txn 1.594704 0.026991 1.621695 ( 1.621807)
|
218
|
+
query 10 times w/o txn 0.057308 0.000013 0.057321 ( 0.057322)
|
219
|
+
modify 10 attrs w/txn 1.225101 0.013972 1.239073 ( 1.239349)
|
220
|
+
delete 10 facts w/txn 0.735944 0.001018 0.736962 ( 0.737102)
|
221
|
+
(and (eq what 'issue-was-closed') (exists... -> 200 2.068974 0.008005 2.076979 ( 2.077134)
|
222
|
+
(and (eq what 'issue-was-closed') (exists... -> 200/txn 1.094799 0.000000 1.094799 ( 1.094849)
|
223
|
+
(and (eq what 'issue-was-closed') (exists... -> zero 2.384214 0.001004 2.385218 ( 2.385610)
|
224
|
+
(and (eq what 'issue-was-closed') (exists... -> zero/txn 1.255267 0.001916 1.257183 ( 1.257310)
|
225
|
+
(gt time '2024-03-23T03:21:43Z') 0.110972 0.002000 0.112972 ( 0.112986)
|
226
|
+
(gt cost 50) 0.087402 0.000000 0.087402 ( 0.087411)
|
227
|
+
(eq title 'Object Thinking 5000') 0.002488 0.000000 0.002488 ( 0.002488)
|
228
|
+
(and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.022121 0.000001 0.022122 ( 0.022123)
|
229
|
+
(eq id (agg (always) (max id))) 0.237595 0.000000 0.237595 ( 0.237605)
|
230
|
+
(join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.635953 0.003996 0.639949 ( 0.640016)
|
231
|
+
delete! 0.060744 0.000997 0.061741 ( 0.061741)
|
232
|
+
Taped.append() x50000 0.037044 0.002000 0.039044 ( 0.039048)
|
233
|
+
Taped.each() x125 1.259629 0.002997 1.262626 ( 1.262661)
|
234
|
+
Taped.delete_if() x375 0.810420 0.000005 0.810425 ( 0.810483)
|
234
235
|
```
|
235
236
|
|
236
237
|
The results were calculated in [this GHA job][benchmark-gha]
|
237
|
-
on 2025-03-
|
238
|
+
on 2025-03-30 at 05:03,
|
238
239
|
on Linux with 4 CPUs.
|
239
240
|
<!-- benchmark_end -->
|
240
241
|
|
241
|
-
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/
|
242
|
+
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/14152813171
|
data/Rakefile
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'os'
|
6
7
|
require 'qbash'
|
7
|
-
require 'rubygems'
|
8
8
|
require 'rake'
|
9
9
|
require 'rake/clean'
|
10
|
+
require 'rubygems'
|
10
11
|
require 'shellwords'
|
11
|
-
require 'os'
|
12
12
|
|
13
13
|
def name
|
14
14
|
@name ||= File.basename(Dir['*.gemspec'].first, '.*')
|
@@ -18,7 +18,7 @@ def version
|
|
18
18
|
Gem::Specification.load(Dir['*.gemspec'].first).version
|
19
19
|
end
|
20
20
|
|
21
|
-
task default: %i[clean test picks
|
21
|
+
task default: %i[clean test picks rubocop yard]
|
22
22
|
|
23
23
|
require 'rake/testtask'
|
24
24
|
desc 'Run all unit tests'
|
@@ -33,16 +33,10 @@ end
|
|
33
33
|
desc 'Run them via Ruby, one by one'
|
34
34
|
task :picks do
|
35
35
|
next if OS.windows?
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
desc 'Require them via Ruby, one by one'
|
42
|
-
task :reqs do
|
43
|
-
next if OS.windows?
|
44
|
-
Dir['lib/**/*.rb'].each do |f|
|
45
|
-
qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout)
|
36
|
+
%w[test lib].each do |d|
|
37
|
+
Dir["#{d}/**/*.rb"].each do |f|
|
38
|
+
qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout)
|
39
|
+
end
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
@@ -56,7 +50,6 @@ require 'rubocop/rake_task'
|
|
56
50
|
desc 'Run RuboCop on all directories'
|
57
51
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
58
52
|
task.fail_on_error = true
|
59
|
-
task.requires << 'rubocop-rspec'
|
60
53
|
end
|
61
54
|
|
62
55
|
desc 'Benchmark them all'
|
data/factbase.gemspec
CHANGED
@@ -25,13 +25,14 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.files = `git ls-files`.split($RS)
|
26
26
|
s.rdoc_options = ['--charset=UTF-8']
|
27
27
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
28
|
-
s.add_dependency 'backtrace', '
|
29
|
-
s.add_dependency 'decoor', '
|
28
|
+
s.add_dependency 'backtrace', '~>0.4'
|
29
|
+
s.add_dependency 'decoor', '~>0.0'
|
30
30
|
s.add_dependency 'json', '~>2.7'
|
31
|
-
s.add_dependency '
|
31
|
+
s.add_dependency 'logger', '~>1.0'
|
32
|
+
s.add_dependency 'loog', '~>0.6'
|
32
33
|
s.add_dependency 'nokogiri', '~>1.10'
|
33
|
-
s.add_dependency 'others', '
|
34
|
-
s.add_dependency 'tago', '
|
34
|
+
s.add_dependency 'others', '~>0.0'
|
35
|
+
s.add_dependency 'tago', '~>0.0'
|
35
36
|
s.add_dependency 'yaml', '~>0.3'
|
36
37
|
s.metadata['rubygems_mfa_required'] = 'true'
|
37
38
|
end
|
@@ -36,14 +36,17 @@ class Factbase::CachedQuery
|
|
36
36
|
key = "each #{@origin}" # params are ignored!
|
37
37
|
before = @cache[key]
|
38
38
|
@cache[key] = @origin.each(fb, params).to_a if before.nil?
|
39
|
+
c = 0
|
39
40
|
@cache[key].each do |f|
|
41
|
+
c += 1
|
40
42
|
yield Factbase::CachedFact.new(f, @cache)
|
41
43
|
end
|
44
|
+
c
|
42
45
|
end
|
43
46
|
|
44
47
|
# Read a single value.
|
45
48
|
# @param [Hash] fb The factbase
|
46
|
-
# @param [Hash]
|
49
|
+
# @param [Hash] params Optional params accessible in the query via the "$" symbol (unused)
|
47
50
|
# @return The value evaluated
|
48
51
|
def one(fb = @fb, params = {})
|
49
52
|
key = "one: #{@origin} #{params}"
|
data/lib/factbase/fact.rb
CHANGED
@@ -46,11 +46,6 @@ class Factbase::Fact
|
|
46
46
|
@map.keys
|
47
47
|
end
|
48
48
|
|
49
|
-
# When a method is missing, this method is called.
|
50
|
-
# Method missing handler for dynamic property access and setting
|
51
|
-
# @param [Symbol] method The method name being called
|
52
|
-
# @param [Array] args Method arguments
|
53
|
-
# @return [Object] The value retrieved or nil if setting a value
|
54
49
|
others do |*args|
|
55
50
|
k = args[0].to_s
|
56
51
|
if k.end_with?('=')
|
@@ -33,9 +33,11 @@ class Factbase::IndexedQuery
|
|
33
33
|
# @return [Integer] Total number of facts yielded
|
34
34
|
def each(fb = @fb, params = {})
|
35
35
|
return to_enum(__method__, fb, params) unless block_given?
|
36
|
-
@origin.each(fb, params).to_a
|
36
|
+
a = @origin.each(fb, params).to_a
|
37
|
+
a.each do |f|
|
37
38
|
yield Factbase::IndexedFact.new(f, @idx)
|
38
39
|
end
|
40
|
+
a.size
|
39
41
|
end
|
40
42
|
|
41
43
|
# Read a single value.
|
@@ -68,18 +68,45 @@ module Factbase::IndexedTerm
|
|
68
68
|
end
|
69
69
|
when :and
|
70
70
|
r = nil
|
71
|
-
@operands.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
if @operands.all? { |o| o.op == :eq } && @operands.size > 1 \
|
72
|
+
&& @operands.all? { |o| o.operands.first.is_a?(Symbol) && _scalar?(o.operands[1]) }
|
73
|
+
key = [maps.object_id, @operands.map { |o| o.operands.first }, :multi_eq]
|
74
|
+
props = @operands.map { |o| o.operands.first }.sort
|
75
|
+
if @idx[key].nil?
|
76
|
+
@idx[key] = {}
|
77
|
+
maps.to_a.each do |m|
|
78
|
+
_all_tuples(m, props).each do |t|
|
79
|
+
@idx[key][t] = [] if @idx[key][t].nil?
|
80
|
+
@idx[key][t].append(m)
|
81
|
+
end
|
82
|
+
end
|
76
83
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
84
|
+
tuples = _as_tuples(
|
85
|
+
@operands.sort_by { |o| o.operands.first }.map do |o|
|
86
|
+
if o.operands[1].is_a?(Symbol)
|
87
|
+
sym = o.operands[1].to_s.gsub(/^\$/, '')
|
88
|
+
params[sym] || []
|
89
|
+
else
|
90
|
+
[o.operands[1]]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
)
|
94
|
+
j = tuples.map { |t| @idx[key][t] || [] }.reduce(&:|)
|
95
|
+
r = (maps & []) | j
|
96
|
+
else
|
97
|
+
@operands.each do |o|
|
98
|
+
n = o.predict(maps, params)
|
99
|
+
if n.nil?
|
100
|
+
r = nil
|
101
|
+
break
|
102
|
+
end
|
103
|
+
if r.nil?
|
104
|
+
r = n
|
105
|
+
else
|
106
|
+
r &= n.to_a
|
107
|
+
end
|
108
|
+
break if r.empty?
|
81
109
|
end
|
82
|
-
break if r.empty?
|
83
110
|
end
|
84
111
|
r
|
85
112
|
when :or
|
@@ -106,6 +133,40 @@ module Factbase::IndexedTerm
|
|
106
133
|
|
107
134
|
private
|
108
135
|
|
136
|
+
# The input looks like this: [[6, 55], [3], [4, 3, 5]].
|
137
|
+
# The outputh should contain all possible combinations: [[6, 3, 4], [6, 3, 3], [55, 3, 5], ...]
|
138
|
+
def _as_tuples(values)
|
139
|
+
tuples = [values.first]
|
140
|
+
if values.size > 1
|
141
|
+
tails = _as_tuples(values[1..])
|
142
|
+
ext = []
|
143
|
+
tuples.each do |t|
|
144
|
+
tails.each do |tail|
|
145
|
+
ext << (t + tail)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
tuples = ext
|
149
|
+
end
|
150
|
+
tuples
|
151
|
+
end
|
152
|
+
|
153
|
+
def _all_tuples(fact, props)
|
154
|
+
prop = props.first.to_s
|
155
|
+
tuples = []
|
156
|
+
tuples += (fact[prop] || []).zip
|
157
|
+
if props.size > 1
|
158
|
+
tails = _all_tuples(fact, props[1..])
|
159
|
+
ext = []
|
160
|
+
tuples.each do |t|
|
161
|
+
tails.each do |tail|
|
162
|
+
ext << (t + tail)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
tuples = ext
|
166
|
+
end
|
167
|
+
tuples
|
168
|
+
end
|
169
|
+
|
109
170
|
def _scalar?(item)
|
110
171
|
item.is_a?(String) || item.is_a?(Time) || item.is_a?(Integer) || item.is_a?(Float) || item.is_a?(Symbol)
|
111
172
|
end
|
data/lib/factbase/logged.rb
CHANGED
@@ -131,47 +131,36 @@ class Factbase::Logged
|
|
131
131
|
@fb = fb
|
132
132
|
end
|
133
133
|
|
134
|
-
def
|
134
|
+
def to_s
|
135
|
+
@term.to_s
|
136
|
+
end
|
137
|
+
|
138
|
+
def each(fb = @fb, params = {}, &)
|
135
139
|
return to_enum(__method__, fb, params) unless block_given?
|
136
140
|
start = Time.now
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
r = @fb.query(@term, @maps).each(@fb, params, &)
|
143
|
-
end
|
144
|
-
raise ".each of #{@term.class} returned #{r.class}" unless r.is_a?(Integer)
|
145
|
-
if r.zero?
|
146
|
-
@tube.say(start, "Zero/#{@fb.size} facts found by '#{q}' #{tail}")
|
147
|
-
else
|
148
|
-
@tube.say(start, "Found #{r}/#{@fb.size} fact(s) by '#{q}' #{tail}")
|
141
|
+
r = nil
|
142
|
+
qry = @fb.query(@term, @maps)
|
143
|
+
tail =
|
144
|
+
Factbase::Logged.elapsed do
|
145
|
+
r = qry.each(fb, params, &)
|
149
146
|
end
|
150
|
-
|
147
|
+
raise ".query(#{@term.to_s.inspect}).each() of #{qry.class} returned #{r.class}" unless r.is_a?(Integer)
|
148
|
+
q = Factbase::Syntax.new(@term).to_term.to_s
|
149
|
+
if r.zero?
|
150
|
+
@tube.say(start, "Zero/#{@fb.size} facts found by '#{q}' #{tail}")
|
151
151
|
else
|
152
|
-
|
153
|
-
tail =
|
154
|
-
Factbase::Logged.elapsed do
|
155
|
-
@fb.query(@term, @maps).each(@fb, params) do |f|
|
156
|
-
array << f
|
157
|
-
end
|
158
|
-
end
|
159
|
-
if array.empty?
|
160
|
-
@tube.say(start, "Zero/#{@fb.size} found by '#{q}' #{tail}")
|
161
|
-
else
|
162
|
-
@tube.say(start, "Found #{array.size}/#{@fb.size} fact(s) by '#{q}' #{tail}")
|
163
|
-
end
|
164
|
-
array
|
152
|
+
@tube.say(start, "Found #{r}/#{@fb.size} fact(s) by '#{q}' #{tail}")
|
165
153
|
end
|
154
|
+
r
|
166
155
|
end
|
167
156
|
|
168
|
-
def one(
|
157
|
+
def one(fb = @fb, params = {})
|
169
158
|
start = Time.now
|
170
159
|
q = Factbase::Syntax.new(@term).to_term.to_s
|
171
160
|
r = nil
|
172
161
|
tail =
|
173
162
|
Factbase::Logged.elapsed do
|
174
|
-
r = @fb.query(@term, @maps).one(
|
163
|
+
r = @fb.query(@term, @maps).one(fb, params)
|
175
164
|
end
|
176
165
|
if r.nil?
|
177
166
|
@tube.say(start, "Nothing found by '#{q}' #{tail}")
|
@@ -181,13 +170,13 @@ class Factbase::Logged
|
|
181
170
|
r
|
182
171
|
end
|
183
172
|
|
184
|
-
def delete!(
|
173
|
+
def delete!(fb = @fb)
|
185
174
|
r = nil
|
186
175
|
start = Time.now
|
187
176
|
before = @fb.size
|
188
177
|
tail =
|
189
178
|
Factbase::Logged.elapsed do
|
190
|
-
r = @fb.query(@term).delete!(
|
179
|
+
r = @fb.query(@term, @maps).delete!(fb)
|
191
180
|
end
|
192
181
|
raise ".delete! of #{@term.class} returned #{r.class}" unless r.is_a?(Integer)
|
193
182
|
if before.zero?
|
data/lib/factbase/query.rb
CHANGED
@@ -39,7 +39,7 @@ class Factbase::Query
|
|
39
39
|
# @param [Factbase] fb The factbase
|
40
40
|
# @param [Hash] params Optional params accessible in the query via the "$" symbol
|
41
41
|
# @yield [Fact] Facts one-by-one
|
42
|
-
# @return [Integer] Total number of facts yielded
|
42
|
+
# @return [Integer] Total number of facts yielded (if block given), otherwise enumerator
|
43
43
|
def each(fb = @fb, params = {})
|
44
44
|
return to_enum(__method__, fb, params) unless block_given?
|
45
45
|
yielded = 0
|
data/lib/factbase/rules.rb
CHANGED
data/lib/factbase/taped.rb
CHANGED
@@ -68,12 +68,15 @@ class Factbase::Taped
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def &(other)
|
71
|
-
|
71
|
+
if other == [] || @origin.empty?
|
72
|
+
return Factbase::Taped.new([], inserted: @inserted, deleted: @deleted, added: @added)
|
73
|
+
end
|
72
74
|
join(other, &:&)
|
73
75
|
end
|
74
76
|
|
75
77
|
def |(other)
|
76
78
|
return Factbase::Taped.new(to_a, inserted: @inserted, deleted: @deleted, added: @added) if other == []
|
79
|
+
return Factbase::Taped.new(other, inserted: @inserted, deleted: @deleted, added: @added) if @origin.empty?
|
77
80
|
join(other, &:|)
|
78
81
|
end
|
79
82
|
|
data/lib/factbase/term.rb
CHANGED
@@ -104,6 +104,7 @@ class Factbase::Term
|
|
104
104
|
# should be evaluated. If no prediction can be made,
|
105
105
|
# the same list is returned.
|
106
106
|
# @param [Array<Hash>] maps Records to iterate, maybe
|
107
|
+
# @param [Hash] _params Params to use (keys must be strings, not symbols, with values as arrays)
|
107
108
|
# @return [Array<Hash>] Records to iterate
|
108
109
|
def predict(maps, _params)
|
109
110
|
maps
|
data/lib/factbase.rb
CHANGED
@@ -82,7 +82,7 @@ require 'yaml'
|
|
82
82
|
# License:: MIT
|
83
83
|
class Factbase
|
84
84
|
# Current version of the gem (changed by .rultor.yml on every release)
|
85
|
-
VERSION = '0.9.
|
85
|
+
VERSION = '0.9.7' unless const_defined?(:VERSION)
|
86
86
|
|
87
87
|
# An exception that may be thrown in a transaction, to roll it back.
|
88
88
|
class Rollback < StandardError; end
|
@@ -3,8 +3,10 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'loog'
|
6
7
|
require_relative '../../test__helper'
|
7
8
|
require_relative '../../../lib/factbase'
|
9
|
+
require_relative '../../../lib/factbase/logged'
|
8
10
|
require_relative '../../../lib/factbase/cached/cached_factbase'
|
9
11
|
require_relative '../../../lib/factbase/indexed/indexed_factbase'
|
10
12
|
require_relative '../../../lib/factbase/sync/sync_factbase'
|
@@ -58,6 +60,25 @@ class TestCachedQuery < Factbase::Test
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
63
|
+
def test_works_with_logging
|
64
|
+
fb = Factbase::CachedFactbase.new(Factbase::Logged.new(Factbase.new, Loog::NULL))
|
65
|
+
total = 10
|
66
|
+
total.times do |i|
|
67
|
+
f = fb.insert
|
68
|
+
f.foo = i
|
69
|
+
f.hello = 1
|
70
|
+
end
|
71
|
+
3.times do
|
72
|
+
[
|
73
|
+
'(exists foo)',
|
74
|
+
'(and (gt foo -99) (exists hello))',
|
75
|
+
'(and (lt hello 1000.44) (exists foo) (not (exists bar)))'
|
76
|
+
].each do |q|
|
77
|
+
assert_equal(total, fb.query(q).each.to_a.size)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
61
82
|
def test_caches_while_being_decorated
|
62
83
|
fb = Factbase::SyncFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
|
63
84
|
10_000.times do |i|
|
@@ -59,17 +59,25 @@ class TestIndexedTerm < Factbase::Test
|
|
59
59
|
:and,
|
60
60
|
[
|
61
61
|
Factbase::Term.new(:eq, [:foo, 42]),
|
62
|
-
Factbase::Term.new(:eq, [
|
62
|
+
Factbase::Term.new(:eq, %i[bar $a])
|
63
63
|
]
|
64
64
|
)
|
65
65
|
idx = {}
|
66
66
|
term.redress!(Factbase::IndexedTerm, idx:)
|
67
67
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
|
68
|
-
n = term.predict(maps, { a
|
68
|
+
n = term.predict(maps, { 'a' => [7] })
|
69
69
|
assert_equal(1, n.size)
|
70
70
|
assert_kind_of(Factbase::Taped, n)
|
71
71
|
end
|
72
72
|
|
73
|
+
def test_predicts_on_single_and
|
74
|
+
term = Factbase::Term.new(:and, [Factbase::Term.new(:eq, [:foo, 42])])
|
75
|
+
idx = {}
|
76
|
+
term.redress!(Factbase::IndexedTerm, idx:)
|
77
|
+
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [4] }])
|
78
|
+
assert_equal(1, term.predict(maps, {}).size)
|
79
|
+
end
|
80
|
+
|
73
81
|
def test_predicts_on_or
|
74
82
|
term = Factbase::Term.new(
|
75
83
|
:or,
|
@@ -7,6 +7,7 @@ require_relative '../test__helper'
|
|
7
7
|
require 'loog'
|
8
8
|
require_relative '../../lib/factbase'
|
9
9
|
require_relative '../../lib/factbase/logged'
|
10
|
+
require_relative '../../lib/factbase/cached/cached_factbase'
|
10
11
|
|
11
12
|
# Test.
|
12
13
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -36,6 +37,18 @@ class TestLogged < Factbase::Test
|
|
36
37
|
assert_equal([42], fb.query('(agg (exists bar) (first bar))').one)
|
37
38
|
end
|
38
39
|
|
40
|
+
def test_avoid_inner_logging
|
41
|
+
buf = Loog::Buffer.new
|
42
|
+
fb = Factbase.new
|
43
|
+
fb.insert
|
44
|
+
fb.insert.bar = 42
|
45
|
+
fb = Factbase::Logged.new(Factbase::CachedFactbase.new(fb), buf)
|
46
|
+
fb.query('(agg (exists bar) (count))').one
|
47
|
+
fb.query('(join "foo<=bar" (exists bar))').each.to_a
|
48
|
+
refute_includes(buf.to_s, '\'(count)\'')
|
49
|
+
refute_includes(buf.to_s, '\'(exists bar)\'')
|
50
|
+
end
|
51
|
+
|
39
52
|
def test_with_txn
|
40
53
|
log = Loog::Buffer.new
|
41
54
|
fb = Factbase::Logged.new(Factbase.new, log)
|
@@ -92,6 +105,12 @@ class TestLogged < Factbase::Test
|
|
92
105
|
assert_equal(0, Factbase::Logged.new(fb, Loog::NULL).query('(always)').each(&:to_s))
|
93
106
|
end
|
94
107
|
|
108
|
+
def test_returns_to_s_correctly
|
109
|
+
fb = Factbase.new
|
110
|
+
q = '(always)'
|
111
|
+
assert_equal(q, fb.query(q).to_s)
|
112
|
+
end
|
113
|
+
|
95
114
|
def test_logs_when_enumerator
|
96
115
|
fb = Factbase::Logged.new(Factbase.new, Loog::NULL)
|
97
116
|
assert_equal(0, fb.query('(always)').each.to_a.size)
|
data/test/factbase/test_query.rb
CHANGED
@@ -123,11 +123,13 @@ class TestQuery < Factbase::Test
|
|
123
123
|
{ 'num' => [42, 66, 0], 'pi' => [3.14], 'name' => ['peter'] },
|
124
124
|
{ 'num' => [0], 'time' => [Time.now - 100], 'hi' => [4], 'nome' => ['Walter'] }
|
125
125
|
]
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
126
|
+
3.times do |cycle|
|
127
|
+
with_factbases(maps) do |badge, fb|
|
128
|
+
queries.each do |q, r|
|
129
|
+
assert_equal(r, fb.query(q).each.to_a.size, "#{q} in #{badge} (cycle ##{cycle})")
|
130
|
+
fb.txn do |fbt|
|
131
|
+
assert_equal(r, fbt.query(q).each.to_a.size, "#{q} in #{badge} (txn, cycle ##{cycle})")
|
132
|
+
end
|
131
133
|
end
|
132
134
|
end
|
133
135
|
end
|
@@ -301,12 +303,85 @@ class TestQuery < Factbase::Test
|
|
301
303
|
'sync+plain' => Factbase::SyncFactbase.new(Factbase.new(maps)),
|
302
304
|
'tallied+plain' => Factbase::Tallied.new(Factbase.new(maps)),
|
303
305
|
'indexed+plain' => Factbase::IndexedFactbase.new(Factbase.new(maps)),
|
306
|
+
'indexed+logged+plain' => Factbase::IndexedFactbase.new(
|
307
|
+
Factbase::Logged.new(
|
308
|
+
Factbase.new(maps),
|
309
|
+
Loog::NULL
|
310
|
+
)
|
311
|
+
),
|
304
312
|
'cached+plain' => Factbase::CachedFactbase.new(Factbase.new(maps)),
|
313
|
+
'cached+logged+plain' => Factbase::CachedFactbase.new(
|
314
|
+
Factbase::Logged.new(
|
315
|
+
Factbase.new(maps),
|
316
|
+
Loog::NULL
|
317
|
+
)
|
318
|
+
),
|
305
319
|
'logged+plain' => Factbase::Logged.new(Factbase.new(maps), Loog::NULL),
|
306
320
|
'indexed+cached+plain' => Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new(maps))),
|
307
321
|
'cached+indexed+plain' => Factbase::CachedFactbase.new(Factbase::IndexedFactbase.new(Factbase.new(maps))),
|
322
|
+
'indexed+indexed+plain' => Factbase::IndexedFactbase.new(
|
323
|
+
Factbase::IndexedFactbase.new(Factbase.new(maps))
|
324
|
+
),
|
325
|
+
'cached+cached+cached+plain' => Factbase::CachedFactbase.new(
|
326
|
+
Factbase::CachedFactbase.new(
|
327
|
+
Factbase::CachedFactbase.new(
|
328
|
+
Factbase.new(maps)
|
329
|
+
)
|
330
|
+
)
|
331
|
+
),
|
332
|
+
'tallied+pre+rules+inv+plain' => Factbase::Tallied.new(
|
333
|
+
Factbase::Pre.new(
|
334
|
+
Factbase::Rules.new(
|
335
|
+
Factbase::Inv.new(
|
336
|
+
Factbase.new(maps)
|
337
|
+
) { nil },
|
338
|
+
'(always)'
|
339
|
+
)
|
340
|
+
) { nil }
|
341
|
+
),
|
308
342
|
'sync+cached+indexed+plain' => Factbase::SyncFactbase.new(
|
309
|
-
Factbase::CachedFactbase.new(
|
343
|
+
Factbase::CachedFactbase.new(
|
344
|
+
Factbase::IndexedFactbase.new(
|
345
|
+
Factbase.new(maps)
|
346
|
+
)
|
347
|
+
)
|
348
|
+
),
|
349
|
+
'sync+logged+plain' => Factbase::SyncFactbase.new(
|
350
|
+
Factbase::Logged.new(
|
351
|
+
Factbase.new(maps),
|
352
|
+
Loog::NULL
|
353
|
+
)
|
354
|
+
),
|
355
|
+
'sync+cached+indexed+logged+plain' => Factbase::SyncFactbase.new(
|
356
|
+
Factbase::CachedFactbase.new(
|
357
|
+
Factbase::IndexedFactbase.new(
|
358
|
+
Factbase::Logged.new(
|
359
|
+
Factbase.new(maps),
|
360
|
+
Loog::NULL
|
361
|
+
)
|
362
|
+
)
|
363
|
+
)
|
364
|
+
),
|
365
|
+
'sync+sync+sync+plain' => Factbase::SyncFactbase.new(
|
366
|
+
Factbase::SyncFactbase.new(
|
367
|
+
Factbase::SyncFactbase.new(
|
368
|
+
Factbase::SyncFactbase.new(
|
369
|
+
Factbase.new(maps)
|
370
|
+
)
|
371
|
+
)
|
372
|
+
)
|
373
|
+
),
|
374
|
+
'logged+logged+logged+plain' => Factbase::SyncFactbase.new(
|
375
|
+
Factbase::Logged.new(
|
376
|
+
Factbase::Logged.new(
|
377
|
+
Factbase::Logged.new(
|
378
|
+
Factbase.new(maps),
|
379
|
+
Loog::NULL
|
380
|
+
),
|
381
|
+
Loog::NULL
|
382
|
+
),
|
383
|
+
Loog::NULL
|
384
|
+
)
|
310
385
|
),
|
311
386
|
'all+plain' => Factbase::Tallied.new(
|
312
387
|
Factbase::Pre.new(
|
data/test/factbase/test_taped.rb
CHANGED
@@ -18,6 +18,18 @@ class TestTaped < Factbase::Test
|
|
18
18
|
assert_equal(1, t.inserted.size)
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_joins_with_empty
|
22
|
+
t = Factbase::Taped.new([{ foo: 'yes' }])
|
23
|
+
t &= []
|
24
|
+
assert_equal(0, t.size)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_disjoins_with_empty
|
28
|
+
t = Factbase::Taped.new([{ bar: 'oops' }])
|
29
|
+
t |= []
|
30
|
+
assert_equal(1, t.size)
|
31
|
+
end
|
32
|
+
|
21
33
|
def test_tracks_deletion
|
22
34
|
t = Factbase::Taped.new([{ x: 1 }, { x: 2 }])
|
23
35
|
t.delete_if { |m| m[:x] == 1 }
|
data/test/factbase/test_term.rb
CHANGED
@@ -81,5 +81,7 @@ class TestTerm < Factbase::Test
|
|
81
81
|
t.redress!(Factbase::IndexedTerm)
|
82
82
|
require_relative '../../lib/factbase/cached/cached_term'
|
83
83
|
t.redress!(Factbase::CachedTerm)
|
84
|
+
assert_kind_of(Factbase::CachedTerm, t)
|
85
|
+
refute_kind_of(Factbase::CachedTerm, Factbase::Term.new(:something, []))
|
84
86
|
end
|
85
87
|
end
|
metadata
CHANGED
@@ -1,42 +1,42 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-30 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: backtrace
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - "
|
16
|
+
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.4
|
18
|
+
version: '0.4'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
|
-
- - "
|
23
|
+
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 0.4
|
25
|
+
version: '0.4'
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: decoor
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- - "
|
30
|
+
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.0
|
32
|
+
version: '0.0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - "
|
37
|
+
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.0
|
39
|
+
version: '0.0'
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: json
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,20 +51,34 @@ dependencies:
|
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '2.7'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: logger
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.0'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.0'
|
54
68
|
- !ruby/object:Gem::Dependency
|
55
69
|
name: loog
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
57
71
|
requirements:
|
58
|
-
- - "
|
72
|
+
- - "~>"
|
59
73
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.6
|
74
|
+
version: '0.6'
|
61
75
|
type: :runtime
|
62
76
|
prerelease: false
|
63
77
|
version_requirements: !ruby/object:Gem::Requirement
|
64
78
|
requirements:
|
65
|
-
- - "
|
79
|
+
- - "~>"
|
66
80
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.6
|
81
|
+
version: '0.6'
|
68
82
|
- !ruby/object:Gem::Dependency
|
69
83
|
name: nokogiri
|
70
84
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,30 +97,30 @@ dependencies:
|
|
83
97
|
name: others
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
85
99
|
requirements:
|
86
|
-
- - "
|
100
|
+
- - "~>"
|
87
101
|
- !ruby/object:Gem::Version
|
88
|
-
version: 0.0
|
102
|
+
version: '0.0'
|
89
103
|
type: :runtime
|
90
104
|
prerelease: false
|
91
105
|
version_requirements: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
|
-
- - "
|
107
|
+
- - "~>"
|
94
108
|
- !ruby/object:Gem::Version
|
95
|
-
version: 0.0
|
109
|
+
version: '0.0'
|
96
110
|
- !ruby/object:Gem::Dependency
|
97
111
|
name: tago
|
98
112
|
requirement: !ruby/object:Gem::Requirement
|
99
113
|
requirements:
|
100
|
-
- - "
|
114
|
+
- - "~>"
|
101
115
|
- !ruby/object:Gem::Version
|
102
|
-
version: 0.0
|
116
|
+
version: '0.0'
|
103
117
|
type: :runtime
|
104
118
|
prerelease: false
|
105
119
|
version_requirements: !ruby/object:Gem::Requirement
|
106
120
|
requirements:
|
107
|
-
- - "
|
121
|
+
- - "~>"
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.0
|
123
|
+
version: '0.0'
|
110
124
|
- !ruby/object:Gem::Dependency
|
111
125
|
name: yaml
|
112
126
|
requirement: !ruby/object:Gem::Requirement
|