factbase 0.0.39 → 0.0.40
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/README.md +1 -0
- data/lib/factbase/fact.rb +7 -4
- data/lib/factbase/looged.rb +25 -12
- data/lib/factbase/term.rb +22 -0
- data/lib/factbase.rb +1 -1
- data/test/factbase/test_looged.rb +1 -1
- data/test/factbase/test_query.rb +3 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 129d17fba6d19bc5131f853d6b90c2e963187e84626270be4f7766e926d4c2c9
|
4
|
+
data.tar.gz: 4196611d541b81bdc1a73bf31f4b1fe15077ad702d8d1ec558f0f61d5e530396
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d87ddb11c2252043c963c6e086a617f216bc15a79441cfa121a0e3de3157f31705cfd1bfea7b6b89996488c76805ee27152f4be00627c7d3f3e1d506636c303
|
7
|
+
data.tar.gz: 5e913f0d675f19fc03cc83c80301af5fd390de8cdaf730a0ea2612768ae0056286be7f5f42686616ee0b1fc69cf22adc0009e9df5315251971e9c948da5ee739
|
data/README.md
CHANGED
@@ -92,6 +92,7 @@ One term is for meta-programming:
|
|
92
92
|
There are terms that are history of search aware:
|
93
93
|
|
94
94
|
* `(prev a)` returns the value of `a` in the previously seen fact
|
95
|
+
* `(unique k)` returns true if the value of `k` property hasn't been seen yet
|
95
96
|
|
96
97
|
There are also terms that match the entire factbase
|
97
98
|
and must be used inside the `(agg ..)` term:
|
data/lib/factbase/fact.rb
CHANGED
@@ -24,17 +24,20 @@ require 'json'
|
|
24
24
|
require 'time'
|
25
25
|
require_relative '../factbase'
|
26
26
|
|
27
|
-
#
|
27
|
+
# A single fact in a factbase.
|
28
28
|
#
|
29
|
-
# This is an internal class, it is not supposed to be instantiated directly
|
30
|
-
#
|
31
|
-
#
|
29
|
+
# This is an internal class, it is not supposed to be instantiated directly,
|
30
|
+
# by the +Factbase+ class.
|
31
|
+
# However, it is possible to use it for testing directly, for example to make a
|
32
32
|
# fact with a single key/value pair inside:
|
33
33
|
#
|
34
34
|
# require 'factbase/fact'
|
35
35
|
# f = Factbase::Fact.new(Mutex.new, { 'foo' => [42, 256, 'Hello, world!'] })
|
36
36
|
# assert_equal(42, f.foo)
|
37
37
|
#
|
38
|
+
# A fact is basically a key/value hash map, where values are non-empty
|
39
|
+
# sets of values.
|
40
|
+
#
|
38
41
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
39
42
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
40
43
|
# License:: MIT
|
data/lib/factbase/looged.rb
CHANGED
@@ -20,6 +20,7 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
|
+
require 'time'
|
23
24
|
require 'loog'
|
24
25
|
|
25
26
|
# A decorator of a Factbase, that logs all operations.
|
@@ -114,39 +115,51 @@ class Factbase::Looged
|
|
114
115
|
def each(&)
|
115
116
|
q = Factbase::Syntax.new(@expr).to_term.to_s
|
116
117
|
if block_given?
|
117
|
-
r =
|
118
|
+
r = nil
|
119
|
+
tail = Factbase::Looged.elapsed do
|
120
|
+
r = @query.each(&)
|
121
|
+
end
|
118
122
|
raise ".each of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
|
119
123
|
if r.zero?
|
120
|
-
@loog.debug("Nothing found by '#{q}'")
|
124
|
+
@loog.debug("Nothing found by '#{q}' #{tail}")
|
121
125
|
else
|
122
|
-
@loog.debug("Found #{r} fact(s) by '#{q}'")
|
126
|
+
@loog.debug("Found #{r} fact(s) by '#{q}' #{tail}")
|
123
127
|
end
|
124
128
|
r
|
125
129
|
else
|
126
130
|
array = []
|
127
|
-
|
128
|
-
|
129
|
-
|
131
|
+
tail = Factbase::Looged.elapsed do
|
132
|
+
@query.each do |f|
|
133
|
+
array << f
|
134
|
+
end
|
130
135
|
end
|
131
|
-
# rubocop:enable Style/MapIntoArray
|
132
136
|
if array.empty?
|
133
|
-
@loog.debug("Nothing found by '#{q}'")
|
137
|
+
@loog.debug("Nothing found by '#{q}' #{tail}")
|
134
138
|
else
|
135
|
-
@loog.debug("Found #{array.size} fact(s) by '#{q}'")
|
139
|
+
@loog.debug("Found #{array.size} fact(s) by '#{q}' #{tail}")
|
136
140
|
end
|
137
141
|
array
|
138
142
|
end
|
139
143
|
end
|
140
144
|
|
141
145
|
def delete!
|
142
|
-
r =
|
146
|
+
r = nil
|
147
|
+
tail = Factbase::Looged.elapsed do
|
148
|
+
r = @query.delete!
|
149
|
+
end
|
143
150
|
raise ".delete! of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
|
144
151
|
if r.zero?
|
145
|
-
@loog.debug("Nothing deleted by '#{@expr}'")
|
152
|
+
@loog.debug("Nothing deleted by '#{@expr}' #{tail}")
|
146
153
|
else
|
147
|
-
@loog.debug("Deleted #{r} fact(s) by '#{@expr}'")
|
154
|
+
@loog.debug("Deleted #{r} fact(s) by '#{@expr}' #{tail}")
|
148
155
|
end
|
149
156
|
r
|
150
157
|
end
|
151
158
|
end
|
159
|
+
|
160
|
+
def self.elapsed
|
161
|
+
start = Time.now
|
162
|
+
yield
|
163
|
+
"in #{format('%.2f', (Time.now - start) * 1000)}ms"
|
164
|
+
end
|
152
165
|
end
|
data/lib/factbase/term.rb
CHANGED
@@ -36,6 +36,15 @@ require_relative 'fact'
|
|
36
36
|
# t = Factbase::Term.new(:lt, [:foo, 50])
|
37
37
|
# assert(t.evaluate(f))
|
38
38
|
#
|
39
|
+
# The design of this class may look ugly, since it has a large number of
|
40
|
+
# methods, each of which corresponds to a different type of a +Term+. A much
|
41
|
+
# better design would definitely involve many classes, one per each type
|
42
|
+
# of a term. It's not done this way because of an experimental nature of
|
43
|
+
# the project. Most probably we should keep current design intact, since it
|
44
|
+
# works well and is rather simple to extend (by adding new term types).
|
45
|
+
# Moreover, it looks like the number of possible term types is rather limited
|
46
|
+
# and currently we implement most of them.
|
47
|
+
#
|
39
48
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
40
49
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
41
50
|
# License:: MIT
|
@@ -184,6 +193,19 @@ class Factbase::Term
|
|
184
193
|
before
|
185
194
|
end
|
186
195
|
|
196
|
+
def unique(fact, _maps)
|
197
|
+
@uniques = [] if @uniques.nil?
|
198
|
+
assert_args(1)
|
199
|
+
vv = by_symbol(0, fact)
|
200
|
+
return false if vv.nil?
|
201
|
+
vv = [vv] unless vv.is_a?(Array)
|
202
|
+
vv.each do |v|
|
203
|
+
return false if @uniques.include?(v)
|
204
|
+
@uniques << v
|
205
|
+
end
|
206
|
+
true
|
207
|
+
end
|
208
|
+
|
187
209
|
def many(fact, maps)
|
188
210
|
assert_args(1)
|
189
211
|
v = the_values(0, fact, maps)
|
data/lib/factbase.rb
CHANGED
@@ -79,7 +79,7 @@ require 'yaml'
|
|
79
79
|
# License:: MIT
|
80
80
|
class Factbase
|
81
81
|
# Current version of the gem (changed by .rultor.yml on every release)
|
82
|
-
VERSION = '0.0.
|
82
|
+
VERSION = '0.0.40'
|
83
83
|
|
84
84
|
# An exception that may be thrown in a transaction, to roll it back.
|
85
85
|
class Rollback < StandardError; end
|
data/test/factbase/test_query.rb
CHANGED
@@ -57,6 +57,9 @@ class TestQuery < Minitest::Test
|
|
57
57
|
'(not (exists hello))' => 3,
|
58
58
|
'(eq "Integer" (type num))' => 2,
|
59
59
|
'(when (eq num 0) (exists time))' => 2,
|
60
|
+
'(unique num)' => 2,
|
61
|
+
'(unique name)' => 2,
|
62
|
+
'(unique pi)' => 1,
|
60
63
|
'(many num)' => 1,
|
61
64
|
'(one num)' => 2,
|
62
65
|
'(gt num (minus 1 (either (at 0 (prev num)) 0)))' => 3,
|