factbase 0.0.14 → 0.0.16

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: 9b1ded0d5a1d5775620d8515eee9ad93ca71c97b70d68bd8624ca5bd55b112b0
4
- data.tar.gz: fe93a4e058eb22a5e4db9c4c70a24461a8c790794df7f9a787989eb07b48837d
3
+ metadata.gz: a8038d22144d137a5f6681fc6d87305b6266613317109c8303477a0ef5deffa8
4
+ data.tar.gz: d22085de542559b452f7a368418a821e83643658ff940fdfecbe698ffe16aa65
5
5
  SHA512:
6
- metadata.gz: 8849f7c00995c3e202c648f4435821825ad5dc79074d2312885b2aa56ceb9a90bffffc3fb4ca7c7292fbeefb34da75a99baf59d32f3a0e421ea461d745fcc8db
7
- data.tar.gz: 0d0cd7b0234b6de46e2a32d9e6c6c45f579e4bb5a09dbb99407d5844a4f206fa0b92977ae921daa6a691a5a4c7dde25f0f90300f4e99c09e7d4107570eb0e7c6
6
+ metadata.gz: aa35c8dd802f4622842cc2c486cc26f3032dfc3ff525f6d97d8185ec6297b8fb5ad45a7dcf010bd7ce5b12b6aae2eb5721f1352f16666513818c2b30470ade17
7
+ data.tar.gz: f4cfcaa303d1c74485760b56b93112003230f955f0b589921beb43d3a8ff83e7b9cfab07d6e4d42cd514b3d1100393611a40f37c287357b99408696e6caa7b6b
data/factbase.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=2.3'
28
28
  s.name = 'factbase'
29
- s.version = '0.0.14'
29
+ s.version = '0.0.16'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Factbase'
32
32
  s.description = 'Fact base in memory and on disc'
@@ -99,7 +99,7 @@ class Factbase::Syntax
99
99
  list << :open
100
100
  when ')'
101
101
  list << :close
102
- when ' '
102
+ when ' ', "\n", "\t", "\r"
103
103
  # ignore it
104
104
  else
105
105
  acc += c
data/lib/factbase/term.rb CHANGED
@@ -92,36 +92,33 @@ class Factbase::Term
92
92
  def absent(fact)
93
93
  assert_args(1)
94
94
  k = @operands[0].to_s
95
- fact[k].empty?
95
+ fact[k].nil?
96
96
  end
97
97
 
98
98
  def eq(fact)
99
- assert_args(2)
100
- k = @operands[0].to_s
101
- v = fact[k]
102
- return true if v == @operands[1]
103
- return v.include?(@operands[1]) if v.is_a?(Array)
104
- false
99
+ arithmetic(:==, fact)
105
100
  end
106
101
 
107
102
  def lt(fact)
108
- assert_args(2)
109
- k = @operands[0].to_s
110
- v = fact[k]
111
- return false if v.empty?
112
- v[0] < @operands[1]
103
+ arithmetic(:<, fact)
113
104
  end
114
105
 
115
106
  def gt(fact)
107
+ arithmetic(:>, fact)
108
+ end
109
+
110
+ def arithmetic(op, fact)
116
111
  assert_args(2)
117
112
  k = @operands[0].to_s
118
113
  v = fact[k]
119
114
  return false if v.nil?
120
- v[0] > @operands[1]
115
+ v = [v] unless v.is_a?(Array)
116
+ v.any? { |vv| vv.send(op, @operands[1]) }
121
117
  end
122
118
 
123
119
  def assert_args(num)
124
- raise "Too many operands for '#{@op}'" if @operands.size > num
125
- raise "Too few operands for '#{@op}'" if @operands.size < num
120
+ c = @operands.size
121
+ raise "Too many (#{c}) operands for '#{@op}' (#{num} expected)" if c > num
122
+ raise "Too few (#{c}) operands for '#{@op}' (#{num} expected)" if c < num
126
123
  end
127
124
  end
data/lib/factbase.rb CHANGED
@@ -35,6 +35,12 @@ class Factbase
35
35
  @mutex = Mutex.new
36
36
  end
37
37
 
38
+ # Is it empty?
39
+ # @return [Boolean] TRUE if there are no facts inside
40
+ def empty?
41
+ @maps.empty?
42
+ end
43
+
38
44
  # Size.
39
45
  # @return [Integer] How many facts are in there
40
46
  def size
@@ -41,11 +41,32 @@ class TestQuery < Minitest::Test
41
41
  )
42
42
  end
43
43
 
44
+ def test_complex_parsing
45
+ maps = []
46
+ maps << { 'num' => 42 }
47
+ maps << { 'pi' => 3.14, 'num' => [42, 66, 0] }
48
+ maps << { 'time' => Time.now - 100, 'num' => 0 }
49
+ {
50
+ '(eq num 444)' => 0,
51
+ '(eq time 0)' => 0,
52
+ '(gt num 60)' => 1,
53
+ "(and (lt pi 100) \n\n (gt num 1000))" => 0,
54
+ '(exists pi)' => 1,
55
+ '(not (exists hello))' => 3,
56
+ '(absent time)' => 2,
57
+ '(and (absent time) (exists pi))' => 1,
58
+ "(and (exists time) (not (\t\texists pi)))" => 1,
59
+ "(or (eq num 66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1
60
+ }.each do |q, r|
61
+ assert_equal(r, Factbase::Query.new(maps, Mutex.new, q).each.to_a.size, q)
62
+ end
63
+ end
64
+
44
65
  def test_simple_deleting
45
66
  maps = []
46
67
  maps << { 'foo' => [42] }
47
68
  maps << { 'bar' => [4, 5] }
48
- maps << { 'bar' => [5] }
69
+ maps << { 'bar' => 5 }
49
70
  q = Factbase::Query.new(maps, Mutex.new, '(eq bar 5)')
50
71
  assert_equal(2, q.delete!)
51
72
  assert_equal(1, maps.size)
@@ -44,8 +44,8 @@ class TestSyntax < Minitest::Test
44
44
  '()',
45
45
  '(foo)',
46
46
  '(foo (bar) (zz 77) )',
47
- "(eq foo 'Hello, world!')",
48
- "(or ( a 4) (b 5) () (and () (c 5) (r 7 8s 8is 'Foo')))"
47
+ "(eq foo \n\n 'Hello, world!'\n)\n",
48
+ "(or ( a 4) (b 5) () (and () (c 5) \t\t(r 7 8s 8is 'Foo')))"
49
49
  ].each do |q|
50
50
  Factbase::Syntax.new(q).to_term
51
51
  end
@@ -41,18 +41,38 @@ class TestTerm < Minitest::Test
41
41
  assert(t.matches?(fact('foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf'])))
42
42
  assert(!t.matches?(fact('foo' => [100])))
43
43
  assert(!t.matches?(fact('foo' => [])))
44
+ assert(!t.matches?(fact('bar' => [])))
44
45
  end
45
46
 
46
47
  def test_lt_matching
47
48
  t = Factbase::Term.new(:lt, ['foo', 42])
48
49
  assert(t.matches?(fact('foo' => [10])))
49
50
  assert(!t.matches?(fact('foo' => [100])))
51
+ assert(!t.matches?(fact('foo' => 100)))
52
+ assert(!t.matches?(fact('bar' => 100)))
50
53
  end
51
54
 
52
55
  def test_gt_matching
53
56
  t = Factbase::Term.new(:gt, ['foo', 42])
54
57
  assert(t.matches?(fact('foo' => [100])))
58
+ assert(t.matches?(fact('foo' => 100)))
55
59
  assert(!t.matches?(fact('foo' => [10])))
60
+ assert(!t.matches?(fact('foo' => 10)))
61
+ assert(!t.matches?(fact('bar' => 10)))
62
+ end
63
+
64
+ def test_lt_matching_time
65
+ t = Factbase::Term.new(:lt, ['foo', Time.now])
66
+ assert(t.matches?(fact('foo' => [Time.now - 100])))
67
+ assert(!t.matches?(fact('foo' => [Time.now + 100])))
68
+ assert(!t.matches?(fact('bar' => [100])))
69
+ end
70
+
71
+ def test_gt_matching_time
72
+ t = Factbase::Term.new(:gt, ['foo', Time.now])
73
+ assert(t.matches?(fact('foo' => [Time.now + 100])))
74
+ assert(!t.matches?(fact('foo' => [Time.now - 100])))
75
+ assert(!t.matches?(fact('bar' => [100])))
56
76
  end
57
77
 
58
78
  def test_not_matching
@@ -60,12 +80,24 @@ class TestTerm < Minitest::Test
60
80
  assert(!t.matches?(fact('foo' => [100])))
61
81
  end
62
82
 
63
- def test_not_exists_matching
83
+ def test_not_eq_matching
64
84
  t = Factbase::Term.new(:not, [Factbase::Term.new(:eq, ['foo', 100])])
65
85
  assert(t.matches?(fact('foo' => [42, 12, -90])))
66
86
  assert(!t.matches?(fact('foo' => 100)))
67
87
  end
68
88
 
89
+ def test_exists_matching
90
+ t = Factbase::Term.new(:exists, ['foo'])
91
+ assert(t.matches?(fact('foo' => [42, 12, -90])))
92
+ assert(!t.matches?(fact('bar' => 100)))
93
+ end
94
+
95
+ def test_absent_matching
96
+ t = Factbase::Term.new(:absent, ['foo'])
97
+ assert(t.matches?(fact('z' => [42, 12, -90])))
98
+ assert(!t.matches?(fact('foo' => 100)))
99
+ end
100
+
69
101
  def test_or_matching
70
102
  t = Factbase::Term.new(
71
103
  :or,
@@ -57,6 +57,13 @@ class TestFactbase < Minitest::Test
57
57
  assert_equal(1, f2.query('(eq foo 42)').each.to_a.count)
58
58
  end
59
59
 
60
+ def test_empty_or_not
61
+ fb = Factbase.new
62
+ assert(fb.empty?)
63
+ fb.insert
64
+ assert(!fb.empty?)
65
+ end
66
+
60
67
  def test_to_json
61
68
  fb = Factbase.new
62
69
  f = fb.insert
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.14
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko