factbase 0.0.39 → 0.0.40

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ff1db55d5a25e5036d3a98423caedc960f8323681e2227c82e0a397727067c0
4
- data.tar.gz: b3000b708bd2eb69005998a722011a296384d5cea66641b975471e611b93e4d0
3
+ metadata.gz: 129d17fba6d19bc5131f853d6b90c2e963187e84626270be4f7766e926d4c2c9
4
+ data.tar.gz: 4196611d541b81bdc1a73bf31f4b1fe15077ad702d8d1ec558f0f61d5e530396
5
5
  SHA512:
6
- metadata.gz: a377a359a877b1f50c83f13c451e095036b4087cf88e39c04a0e5d64e86337bfef458883646009daff4b2b90446abbdbd563a4921b3ed275b88b7408b69ef0de
7
- data.tar.gz: 26a5ca088df353e0c526080213aa4d87b23805dd522617d52d2d738b1881c40ae4c659fa886db4fbe19a30a131ff6b5a7e19aadf5dbafcbd0f6b81954386bd65
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
- # Fact.
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
- # It is possible to use for testing directly, for example to make a
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
@@ -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 = @query.each(&)
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
- # rubocop:disable Style/MapIntoArray
128
- @query.each do |f|
129
- array << f
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 = @query.delete!
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.39'
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
@@ -94,7 +94,7 @@ class TestLooged < Minitest::Test
94
94
  'Found 1 fact(s) by \'(exists bar)\'',
95
95
  'Deleted 3 fact(s) by \'(not (exists bar))\''
96
96
  ].each do |s|
97
- assert(log.to_s.include?("#{s}\n"), "#{log}\n")
97
+ assert(log.to_s.include?(s), "#{log}\n")
98
98
  end
99
99
  end
100
100
  end
@@ -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,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.39
4
+ version: 0.0.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko