factbase 0.9.6 → 0.9.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab2bcf895fa6934620163134f67815a20126515fcc163bdf7a232752a474bfcd
4
- data.tar.gz: 2b96185e57e1ffa3176d34839940cff0a025b4cef8c7cd49b99bf9bdc79ab05c
3
+ metadata.gz: 1b9679d9fad6ba549ccccd428809c330ba6f2c3eefb3a8c32cd6b2ea9668f8e1
4
+ data.tar.gz: 5103850e97643459fda4640e5564fe8073bc0c949b699a325a83360bb32e7dfc
5
5
  SHA512:
6
- metadata.gz: ac68811b7e3fd879a0a19079c537d5718095e0f8786de51b9fa949a1541f518dbd0f93ea9aedd749b41e90c965a9f81ec1fdd75b24e1959c0adc818d899f8017
7
- data.tar.gz: dd39f0a82dc183b2c324660f1a9bb3ba6bf95cb2fa37c528d2684197aa96167dc62d6ee4797efd20c705a8c530c6e8ae09f332954023b1791c4dcb806f7b9a54
6
+ metadata.gz: cb9d62637fde56598cb1c2c01d492b6f2e0e9f144ee7eba1cbca88779be1214afc1f7ec43687baec3a9bc232ccb127856a9aad4b5732965667c2f69c91341229
7
+ data.tar.gz: 10c1b8ddeeb23a0b1ed8de099aad0bf55c2e19370fba0d6686384a24769a57f3483cb10de5313588b0607e8dee9b4484050dde929b8e7fe2a9b053a96f242b20
data/Rakefile CHANGED
@@ -33,7 +33,7 @@ end
33
33
  desc 'Run them via Ruby, one by one'
34
34
  task :picks do
35
35
  next if OS.windows?
36
- %w[text lib].each do |d|
36
+ %w[test lib].each do |d|
37
37
  Dir["#{d}/**/*.rb"].each do |f|
38
38
  qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout)
39
39
  end
@@ -36,9 +36,12 @@ 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.
@@ -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.each do |f|
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.
@@ -54,8 +54,7 @@ module Factbase::IndexedTerm
54
54
  end
55
55
  vv =
56
56
  if @operands[1].is_a?(Symbol)
57
- sym = @operands[1].to_s.gsub(/^\$/, '')
58
- params[sym] || []
57
+ params[@operands[1].to_s] || []
59
58
  else
60
59
  [@operands[1]]
61
60
  end
@@ -84,8 +83,7 @@ module Factbase::IndexedTerm
84
83
  tuples = _as_tuples(
85
84
  @operands.sort_by { |o| o.operands.first }.map do |o|
86
85
  if o.operands[1].is_a?(Symbol)
87
- sym = o.operands[1].to_s.gsub(/^\$/, '')
88
- params[sym] || []
86
+ params[o.operands[1].to_s] || []
89
87
  else
90
88
  [o.operands[1]]
91
89
  end
@@ -138,13 +138,14 @@ class Factbase::Logged
138
138
  def each(fb = @fb, params = {}, &)
139
139
  return to_enum(__method__, fb, params) unless block_given?
140
140
  start = Time.now
141
- q = Factbase::Syntax.new(@term).to_term.to_s
142
141
  r = nil
142
+ qry = @fb.query(@term, @maps)
143
143
  tail =
144
144
  Factbase::Logged.elapsed do
145
- r = @fb.query(@term, @maps).each(fb, params, &)
145
+ r = qry.each(fb, params, &)
146
146
  end
147
- raise ".each of #{@term.class} returned #{r.class}" unless r.is_a?(Integer)
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
148
149
  if r.zero?
149
150
  @tube.say(start, "Zero/#{@fb.size} facts found by '#{q}' #{tail}")
150
151
  else
@@ -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
@@ -61,7 +61,6 @@ class Factbase::Rules
61
61
  # Fact decorator.
62
62
  #
63
63
  # This is an internal class, it is not supposed to be instantiated directly.
64
- #
65
64
  class Fact
66
65
  def initialize(fact, check, fb)
67
66
  @fact = fact
@@ -130,9 +129,10 @@ class Factbase::Rules
130
129
  end
131
130
 
132
131
  def it(fact, _fb)
132
+ return if @uid.nil?
133
133
  a = fact[@uid]
134
134
  return if a.nil?
135
- @facts << a[0] unless @uid.nil?
135
+ @facts << a[0]
136
136
  end
137
137
 
138
138
  def include?(fact)
data/lib/factbase/tee.rb CHANGED
@@ -31,10 +31,13 @@ class Factbase::Tee
31
31
  end
32
32
 
33
33
  others do |*args|
34
- if args[0].to_s == '[]' && args[1].to_s.start_with?('$')
34
+ if args[0].to_s == '[]' && args[1].start_with?('$')
35
35
  n = args[1].to_s
36
36
  n = n[1..] unless @upper.is_a?(Factbase::Tee)
37
- @upper[n]
37
+ r = @upper[n]
38
+ r = @fact[n] if r.nil?
39
+ r = [r] unless r.respond_to?(:each) || r.nil?
40
+ r
38
41
  else
39
42
  @fact.method_missing(*args)
40
43
  end
data/lib/factbase/term.rb CHANGED
@@ -218,6 +218,10 @@ class Factbase::Term
218
218
  [v]
219
219
  end
220
220
  end
221
+ raise 'Why not array?' unless v.is_a?(Array)
222
+ unless v.all? { |i| [Float, Integer, String, Time, TrueClass, FalseClass].any? { |t| i.is_a?(t) } }
223
+ raise 'Wrong type inside'
224
+ end
221
225
  v
222
226
  end
223
227
  end
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.6' unless const_defined?(:VERSION)
85
+ VERSION = '0.9.8' 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
@@ -19,7 +19,7 @@ class TestIndexedTerm < Factbase::Test
19
19
  idx = {}
20
20
  term.redress!(Factbase::IndexedTerm, idx:)
21
21
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
22
- n = term.predict(maps, { a: 1 })
22
+ n = term.predict(maps, {})
23
23
  assert_equal(2, n.size)
24
24
  assert_kind_of(Factbase::Taped, n)
25
25
  end
@@ -29,7 +29,7 @@ class TestIndexedTerm < Factbase::Test
29
29
  idx = {}
30
30
  term.redress!(Factbase::IndexedTerm, idx:)
31
31
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
32
- n = term.predict(maps, { a: 1 })
32
+ n = term.predict(maps, {})
33
33
  assert_equal(3, n.size)
34
34
  assert_kind_of(Factbase::Taped, n)
35
35
  end
@@ -39,7 +39,7 @@ class TestIndexedTerm < Factbase::Test
39
39
  idx = {}
40
40
  term.redress!(Factbase::IndexedTerm, idx:)
41
41
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
42
- n = term.predict(maps, { a: 1 })
42
+ n = term.predict(maps, {})
43
43
  assert_equal(1, n.size)
44
44
  assert_kind_of(Factbase::Taped, n)
45
45
  end
@@ -49,7 +49,7 @@ class TestIndexedTerm < Factbase::Test
49
49
  idx = {}
50
50
  term.redress!(Factbase::IndexedTerm, idx:)
51
51
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22] }])
52
- n = term.predict(maps, { a: 1 })
52
+ n = term.predict(maps, {})
53
53
  assert_equal(1, n.size)
54
54
  assert_kind_of(Factbase::Taped, n)
55
55
  end
@@ -59,13 +59,13 @@ class TestIndexedTerm < Factbase::Test
59
59
  :and,
60
60
  [
61
61
  Factbase::Term.new(:eq, [:foo, 42]),
62
- Factbase::Term.new(:eq, %i[bar $a])
62
+ Factbase::Term.new(:eq, %i[bar $jeff])
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' => [7] })
68
+ n = term.predict(maps, Factbase::Tee.new({}, { 'jeff' => [7] }))
69
69
  assert_equal(1, n.size)
70
70
  assert_kind_of(Factbase::Taped, n)
71
71
  end
@@ -90,7 +90,7 @@ class TestIndexedTerm < Factbase::Test
90
90
  idx = {}
91
91
  term.redress!(Factbase::IndexedTerm, idx:)
92
92
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
93
- n = term.predict(maps, { a: 1 })
93
+ n = term.predict(maps, {})
94
94
  assert_equal(3, n.size)
95
95
  assert_kind_of(Factbase::Taped, n)
96
96
  end
@@ -100,7 +100,7 @@ class TestIndexedTerm < Factbase::Test
100
100
  idx = {}
101
101
  term.redress!(Factbase::IndexedTerm, idx:)
102
102
  maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'alpha' => [] }, {}])
103
- n = term.predict(maps, { a: 1 })
103
+ n = term.predict(maps, {})
104
104
  assert_nil(n)
105
105
  end
106
106
  end
@@ -57,7 +57,7 @@ class TestAggregates < Factbase::Test
57
57
  { 'a' => [4], 'b' => [55] }
58
58
  ]
59
59
  t = Factbase::Syntax.new('(empty (eq b $x))').to_term
60
- assert(t.evaluate(Factbase::Fact.new({ 'x' => 42 }), maps, Factbase.new))
61
- refute(t.evaluate(Factbase::Fact.new({ 'x' => 44 }), maps, Factbase.new))
60
+ assert(t.evaluate(Factbase::Fact.new({ 'x' => [42] }), maps, Factbase.new))
61
+ refute(t.evaluate(Factbase::Fact.new({ 'x' => [44] }), maps, Factbase.new))
62
62
  end
63
63
  end
@@ -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)
@@ -156,18 +156,22 @@ class TestQuery < Factbase::Test
156
156
 
157
157
  def test_reading_one
158
158
  maps = [
159
- { 'foo' => [42] },
159
+ { 'foo' => [42], 'hello' => [4] },
160
160
  { 'bar' => [4, 5] }
161
161
  ]
162
162
  with_factbases(maps) do |badge, fb|
163
163
  {
164
+ '(agg (and (eq foo 42) (eq hello $v)) (min foo))' => 42,
165
+ '(agg (or (eq foo 42) (eq bar 4)) (min foo))' => 42,
164
166
  '(agg (exists foo) (first foo))' => [42],
165
167
  '(agg (exists z) (first z))' => nil,
166
168
  '(agg (always) (count))' => 2,
167
169
  '(agg (eq bar $v) (count))' => 1,
170
+ '(agg (eq foo 42) (min foo))' => 42,
171
+ '(agg (and (eq foo 42)) (min foo))' => 42,
168
172
  '(agg (eq z 40) (count))' => 0
169
173
  }.each do |q, expected|
170
- result = fb.query(q).one(fb, v: 4)
174
+ result = fb.query(q).one(fb, 'v' => 4)
171
175
  if expected.nil?
172
176
  assert_nil(result, "#{q} -> nil in #{badge}")
173
177
  else
@@ -190,6 +194,16 @@ class TestQuery < Factbase::Test
190
194
  end
191
195
  end
192
196
 
197
+ def test_finds_with_subsitution
198
+ maps = [{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [666] }]
199
+ with_factbases(maps) do |badge, fb|
200
+ assert_equal(1, fb.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge}")
201
+ fb.txn do |fbt|
202
+ assert_equal(1, fbt.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge} (txn)")
203
+ end
204
+ end
205
+ end
206
+
193
207
  def test_scans_and_inserts
194
208
  with_factbases do |_, fb|
195
209
  fb.insert.foo = 42
@@ -277,8 +291,8 @@ class TestQuery < Factbase::Test
277
291
  found += 1
278
292
  end
279
293
  assert_equal(1, found)
280
- assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: 42).to_a.size)
281
- assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: 555).to_a.size)
294
+ assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [42]).to_a.size)
295
+ assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [555]).to_a.size)
282
296
  end
283
297
 
284
298
  def test_with_nil_alias
@@ -37,10 +37,10 @@ class TestTee < Factbase::Test
37
37
  map = {}
38
38
  prim = Factbase::Fact.new(map)
39
39
  prim.foo = 42
40
- t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => 7 })
41
- assert_equal(7, t['$bar'])
40
+ t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => [7] })
41
+ assert_equal([7], t['$bar'])
42
42
  t = Factbase::Tee.new(prim, t)
43
- assert_equal(7, t['$bar'])
43
+ assert_equal([7], t['$bar'])
44
44
  end
45
45
 
46
46
  def test_prints_to_string
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.9.6
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko