factbase 0.0.14 → 0.0.16

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: 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