factbase 0.0.50 → 0.0.52

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2024 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require_relative '../../lib/factbase'
25
+ require_relative '../../lib/factbase/accum'
26
+ require_relative '../../lib/factbase/fact'
27
+
28
+ # Accum test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2024 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestAccum < Minitest::Test
33
+ def test_holds_props
34
+ map = {}
35
+ f = Factbase::Fact.new(Mutex.new, map)
36
+ props = {}
37
+ a = Factbase::Accum.new(f, props, false)
38
+ a.foo = 42
39
+ assert_raises { f.foo }
40
+ assert_equal(42, a.foo)
41
+ assert_equal([42], props['foo'])
42
+ end
43
+
44
+ def test_passes_props
45
+ map = {}
46
+ f = Factbase::Fact.new(Mutex.new, map)
47
+ props = {}
48
+ a = Factbase::Accum.new(f, props, true)
49
+ a.foo = 42
50
+ assert_equal(42, f.foo)
51
+ assert_equal(42, a.foo)
52
+ assert_equal([42], props['foo'])
53
+ end
54
+
55
+ def test_appends_props
56
+ map = {}
57
+ f = Factbase::Fact.new(Mutex.new, map)
58
+ f.foo = 42
59
+ props = {}
60
+ a = Factbase::Accum.new(f, props, false)
61
+ a.foo = 55
62
+ assert_equal(2, a['foo'].size)
63
+ end
64
+
65
+ def test_empties
66
+ f = Factbase::Fact.new(Mutex.new, {})
67
+ a = Factbase::Accum.new(f, {}, false)
68
+ assert(a['foo'].nil?)
69
+ end
70
+ end
@@ -45,6 +45,14 @@ class TestLooged < Minitest::Test
45
45
  assert_equal(2, fb.size)
46
46
  end
47
47
 
48
+ def test_reading_one
49
+ fb = Factbase::Looged.new(Factbase.new, Loog::NULL)
50
+ fb.insert
51
+ fb.insert.bar = 42
52
+ assert_equal(1, fb.query('(agg (exists bar) (count))').one)
53
+ assert_equal([42], fb.query('(agg (exists bar) (first bar))').one)
54
+ end
55
+
48
56
  def test_with_txn
49
57
  log = Loog::Buffer.new
50
58
  fb = Factbase::Looged.new(Factbase.new, log)
@@ -44,9 +44,9 @@ class TestQuery < Minitest::Test
44
44
 
45
45
  def test_complex_parsing
46
46
  maps = []
47
- maps << { 'num' => 42, 'name' => 'Jeff' }
48
- maps << { 'pi' => 3.14, 'num' => [42, 66, 0], 'name' => 'peter' }
49
- maps << { 'time' => Time.now - 100, 'num' => 0, 'hi' => [4], 'nome' => ['Walter'] }
47
+ maps << { 'num' => [42], 'name' => ['Jeff'] }
48
+ maps << { 'pi' => [3.14], 'num' => [42, 66, 0], 'name' => ['peter'] }
49
+ maps << { 'time' => [Time.now - 100], 'num' => [0], 'hi' => [4], 'nome' => ['Walter'] }
50
50
  {
51
51
  '(eq num 444)' => 0,
52
52
  '(eq hi 4)' => 1,
@@ -65,6 +65,7 @@ class TestQuery < Minitest::Test
65
65
  '(unique pi)' => 1,
66
66
  '(many num)' => 1,
67
67
  '(one num)' => 2,
68
+ '(nil (agg (exists hello) (min num)))' => 3,
68
69
  '(gt num (minus 1 (either (at 0 (prev num)) 0)))' => 3,
69
70
  '(and (not (many num)) (eq num (plus 21 +21)))' => 1,
70
71
  '(and (not (many num)) (eq num (minus -100 -142)))' => 1,
@@ -84,7 +85,8 @@ class TestQuery < Minitest::Test
84
85
  '(and (absent time) (exists pi))' => 1,
85
86
  "(and (exists time) (not (\t\texists pi)))" => 1,
86
87
  '(undef something)' => 3,
87
- "(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1
88
+ "(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
89
+ '(eq 3 (agg (eq num $num) (count)))' => 1
88
90
  }.each do |q, r|
89
91
  assert_equal(r, Factbase::Query.new(maps, Mutex.new, q).each.to_a.size, q)
90
92
  end
@@ -93,7 +95,7 @@ class TestQuery < Minitest::Test
93
95
  def test_simple_parsing_with_time
94
96
  maps = []
95
97
  now = Time.now.utc
96
- maps << { 'foo' => now }
98
+ maps << { 'foo' => [now] }
97
99
  q = Factbase::Query.new(maps, Mutex.new, "(eq foo #{now.iso8601})")
98
100
  assert_equal(1, q.each.to_a.size)
99
101
  end
@@ -102,17 +104,32 @@ class TestQuery < Minitest::Test
102
104
  maps = []
103
105
  maps << { 'foo' => [42] }
104
106
  maps << { 'bar' => [4, 5] }
105
- maps << { 'bar' => 5 }
107
+ maps << { 'bar' => [5] }
106
108
  q = Factbase::Query.new(maps, Mutex.new, '(eq bar 5)')
107
109
  assert_equal(2, q.delete!)
108
110
  assert_equal(1, maps.size)
109
111
  end
110
112
 
113
+ def test_reading_one
114
+ maps = []
115
+ maps << { 'foo' => [42] }
116
+ maps << { 'bar' => [4, 5] }
117
+ {
118
+ '(agg (exists foo) (first foo))' => [42],
119
+ '(agg (exists z) (first z))' => nil,
120
+ '(agg (always) (count))' => 2,
121
+ '(agg (eq bar $v) (count))' => 1,
122
+ '(agg (eq z 40) (count))' => 0
123
+ }.each do |q, r|
124
+ assert_equal(r, Factbase::Query.new(maps, Mutex.new, q).one(v: 4), "#{q} -> #{r}")
125
+ end
126
+ end
127
+
111
128
  def test_deleting_nothing
112
129
  maps = []
113
130
  maps << { 'foo' => [42] }
114
131
  maps << { 'bar' => [4, 5] }
115
- maps << { 'bar' => 5 }
132
+ maps << { 'bar' => [5] }
116
133
  q = Factbase::Query.new(maps, Mutex.new, '(never)')
117
134
  assert_equal(0, q.delete!)
118
135
  assert_equal(3, maps.size)
@@ -126,8 +143,34 @@ class TestQuery < Minitest::Test
126
143
 
127
144
  def test_returns_int
128
145
  maps = []
129
- maps << { 'foo' => 1 }
146
+ maps << { 'foo' => [1] }
130
147
  q = Factbase::Query.new(maps, Mutex.new, '(eq foo 1)')
131
148
  assert_equal(1, q.each(&:to_s))
132
149
  end
150
+
151
+ def test_with_aliases
152
+ maps = []
153
+ maps << { 'foo' => [42] }
154
+ assert_equal(45, Factbase::Query.new(maps, Mutex.new, '(as bar (plus foo 3))').each.to_a[0].bar)
155
+ assert_equal(1, maps[0].size)
156
+ end
157
+
158
+ def test_with_params
159
+ maps = []
160
+ maps << { 'foo' => [42] }
161
+ maps << { 'foo' => [17] }
162
+ found = 0
163
+ Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: [42]) do
164
+ found += 1
165
+ end
166
+ assert_equal(1, found)
167
+ assert_equal(1, Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: 42).to_a.size)
168
+ assert_equal(0, Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: 555).to_a.size)
169
+ end
170
+
171
+ def test_with_nil_alias
172
+ maps = []
173
+ maps << { 'foo' => [42] }
174
+ assert(Factbase::Query.new(maps, Mutex.new, '(as bar (plus xxx 3))').each.to_a[0]['bar'].nil?)
175
+ end
133
176
  end
@@ -53,6 +53,13 @@ class TestRules < Minitest::Test
53
53
  assert(f.to_s.length.positive?)
54
54
  end
55
55
 
56
+ def test_query_one
57
+ fb = Factbase::Rules.new(Factbase.new, '(always)')
58
+ f = fb.insert
59
+ f.foo = 42
60
+ assert_equal(1, fb.query('(agg (eq foo $v) (count))').one(v: 42))
61
+ end
62
+
56
63
  def test_check_only_when_txn_is_closed
57
64
  fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
58
65
  ok = false
@@ -94,6 +101,6 @@ class TestRules < Minitest::Test
94
101
  end
95
102
  end
96
103
  assert(ok)
97
- assert_equal(0, fb.query('(eq hello 42)').each.to_a.size)
104
+ assert_equal(0, fb.query('(eq hello $v)').each(v: 42).to_a.size)
98
105
  end
99
106
  end
@@ -43,7 +43,7 @@ class TestSyntax < Minitest::Test
43
43
  [
44
44
  '(foo)',
45
45
  '(foo (bar) (zz 77) ) # hey',
46
- "# hello\n\n\n(foo (bar))",
46
+ "# hello\n\n\n(foo ($bar))",
47
47
  "(eq foo \n\n 'Hello, world!'\n)\n",
48
48
  "(eq x 'Hello, \\' \n) \\' ( world!')",
49
49
  "# this is a comment\n(eq foo # test\n 42)\n\n# another comment\n",
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2024 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require_relative '../../lib/factbase'
25
+ require_relative '../../lib/factbase/tee'
26
+ require_relative '../../lib/factbase/fact'
27
+
28
+ # Tee test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2024 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestTee < Minitest::Test
33
+ def test_two_facts
34
+ map = {}
35
+ prim = Factbase::Fact.new(Mutex.new, map)
36
+ prim.foo = 42
37
+ upper = Factbase::Fact.new(Mutex.new, map)
38
+ upper.bar = 13
39
+ t = Factbase::Tee.new(prim, upper)
40
+ assert_equal(42, t.foo)
41
+ assert_equal([13], t['$bar'])
42
+ end
43
+
44
+ def test_recursively
45
+ map = {}
46
+ prim = Factbase::Fact.new(Mutex.new, map)
47
+ prim.foo = 42
48
+ t = Factbase::Tee.new(nil, { 'bar' => 7 })
49
+ assert_equal(7, t['$bar'])
50
+ t = Factbase::Tee.new(prim, t)
51
+ assert_equal(7, t['$bar'])
52
+ end
53
+ end
@@ -22,67 +22,12 @@
22
22
 
23
23
  require 'minitest/autorun'
24
24
  require_relative '../../lib/factbase/term'
25
- require_relative '../../lib/factbase/syntax'
26
25
 
27
26
  # Term test.
28
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
28
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
30
29
  # License:: MIT
31
30
  class TestTerm < Minitest::Test
32
- def test_simple_matching
33
- t = Factbase::Term.new(:eq, [:foo, 42])
34
- assert(t.evaluate(fact('foo' => [42]), []))
35
- assert(!t.evaluate(fact('foo' => 'Hello!'), []))
36
- assert(!t.evaluate(fact('bar' => ['Hello!']), []))
37
- end
38
-
39
- def test_eq_matching
40
- t = Factbase::Term.new(:eq, [:foo, 42])
41
- assert(t.evaluate(fact('foo' => 42), []))
42
- assert(t.evaluate(fact('foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf']), []))
43
- assert(!t.evaluate(fact('foo' => [100]), []))
44
- assert(!t.evaluate(fact('foo' => []), []))
45
- assert(!t.evaluate(fact('bar' => []), []))
46
- end
47
-
48
- def test_eq_matching_time
49
- now = Time.now
50
- t = Factbase::Term.new(:eq, [:foo, Time.parse(now.iso8601)])
51
- assert(t.evaluate(fact('foo' => now), []))
52
- assert(t.evaluate(fact('foo' => [now, Time.now]), []))
53
- end
54
-
55
- def test_lt_matching
56
- t = Factbase::Term.new(:lt, [:foo, 42])
57
- assert(t.evaluate(fact('foo' => [10]), []))
58
- assert(!t.evaluate(fact('foo' => [100]), []))
59
- assert(!t.evaluate(fact('foo' => 100), []))
60
- assert(!t.evaluate(fact('bar' => 100), []))
61
- end
62
-
63
- def test_gt_matching
64
- t = Factbase::Term.new(:gt, [:foo, 42])
65
- assert(t.evaluate(fact('foo' => [100]), []))
66
- assert(t.evaluate(fact('foo' => 100), []))
67
- assert(!t.evaluate(fact('foo' => [10]), []))
68
- assert(!t.evaluate(fact('foo' => 10), []))
69
- assert(!t.evaluate(fact('bar' => 10), []))
70
- end
71
-
72
- def test_lt_matching_time
73
- t = Factbase::Term.new(:lt, [:foo, Time.now])
74
- assert(t.evaluate(fact('foo' => [Time.now - 100]), []))
75
- assert(!t.evaluate(fact('foo' => [Time.now + 100]), []))
76
- assert(!t.evaluate(fact('bar' => [100]), []))
77
- end
78
-
79
- def test_gt_matching_time
80
- t = Factbase::Term.new(:gt, [:foo, Time.now])
81
- assert(t.evaluate(fact('foo' => [Time.now + 100]), []))
82
- assert(!t.evaluate(fact('foo' => [Time.now - 100]), []))
83
- assert(!t.evaluate(fact('bar' => [100]), []))
84
- end
85
-
86
31
  def test_false_matching
87
32
  t = Factbase::Term.new(:never, [])
88
33
  assert(!t.evaluate(fact('foo' => [100]), []))
@@ -125,6 +70,7 @@ class TestTerm < Minitest::Test
125
70
  assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), []))
126
71
  assert_equal('Float', t.evaluate(fact('foo' => 3.14), []))
127
72
  assert_equal('Time', t.evaluate(fact('foo' => Time.now), []))
73
+ assert_equal('Integer', t.evaluate(fact('foo' => 1_000_000_000_000_000), []))
128
74
  assert_equal('nil', t.evaluate(fact, []))
129
75
  end
130
76
 
@@ -213,6 +159,12 @@ class TestTerm < Minitest::Test
213
159
  assert_equal([42], t.evaluate(fact('foo' => 4), []))
214
160
  end
215
161
 
162
+ def test_plus
163
+ t = Factbase::Term.new(:plus, [:foo, 42])
164
+ assert_equal(46, t.evaluate(fact('foo' => 4), []))
165
+ assert(t.evaluate(fact, []).nil?)
166
+ end
167
+
216
168
  def test_report_missing_term
217
169
  t = Factbase::Term.new(:something, [])
218
170
  msg = assert_raises do
@@ -229,27 +181,6 @@ class TestTerm < Minitest::Test
229
181
  assert(msg.include?('at (at)'), msg)
230
182
  end
231
183
 
232
- def test_aggregation
233
- maps = [
234
- { 'x' => 1, 'y' => 0, 'z' => 4 },
235
- { 'x' => 2, 'y' => 42, 'z' => 3 },
236
- { 'x' => 3, 'y' => 42, 'z' => 5 },
237
- { 'x' => 4, 'y' => 42, 'z' => 2 },
238
- { 'x' => 5, 'y' => 42, 'z' => 1 },
239
- { 'x' => 8, 'y' => 0, 'z' => 6 }
240
- ]
241
- {
242
- '(eq x (agg (eq y 42) (min x)))' => '(eq x 2)',
243
- '(eq z (agg (eq y 0) (max z)))' => '(eq x 8)',
244
- '(eq x (agg (and (eq y 42) (gt z 1)) (max x)))' => '(eq x 4)',
245
- '(and (eq x (agg (eq y 42) (min x))) (eq z 3))' => '(eq x 2)'
246
- }.each do |q, r|
247
- t = Factbase::Syntax.new(q).to_term
248
- f = maps.find { |m| t.evaluate(fact(m), maps) }
249
- assert(Factbase::Syntax.new(r).to_term.evaluate(fact(f), []))
250
- end
251
- end
252
-
253
184
  private
254
185
 
255
186
  def fact(map = {})
@@ -73,6 +73,27 @@ class TestToXML < Minitest::Test
73
73
  assert(!xml.xpath('/fb/f/class').empty?)
74
74
  end
75
75
 
76
+ def test_show_types_as_attributes
77
+ fb = Factbase.new
78
+ f = fb.insert
79
+ f.a = 42
80
+ f.b = 3.14
81
+ f.c = 'Hello'
82
+ f.d = Time.now
83
+ f.e = 'e'
84
+ f.e = 4
85
+ out = Factbase::ToXML.new(fb).xml
86
+ xml = Nokogiri::XML.parse(out)
87
+ [
88
+ '/fb/f/a[@t="I"]',
89
+ '/fb/f/b[@t="F"]',
90
+ '/fb/f/c[@t="S"]',
91
+ '/fb/f/d[@t="T"]',
92
+ '/fb/f/e/v[@t="S"]',
93
+ '/fb/f/e/v[@t="I"]'
94
+ ].each { |x| assert(!xml.xpath(x).empty?, out) }
95
+ end
96
+
76
97
  def test_sorts_keys
77
98
  fb = Factbase.new
78
99
  f = fb.insert
@@ -80,7 +101,10 @@ class TestToXML < Minitest::Test
80
101
  f.t = 40
81
102
  f.a = 10
82
103
  f.c = 1
83
- xml = Factbase::ToXML.new(fb).xml
84
- assert(xml.gsub(/\s*/, '').include?('<f><a>10</a><c>1</c><t>40</t><x>20</x></f>'), xml)
104
+ to = Factbase::ToXML.new(fb)
105
+ xml = Nokogiri::XML.parse(to.xml)
106
+ %w[a c t x].each_with_index do |e, i|
107
+ assert(!xml.xpath("/fb/f/#{e}[count(preceding-sibling::*) = #{i}]").empty?, e)
108
+ end
85
109
  end
86
110
  end
@@ -68,15 +68,15 @@ class TestFactbase < Minitest::Test
68
68
  fb.insert.bar = 1
69
69
  fb.query('(exists bar)').each do |f|
70
70
  f.bar = 42
71
- assert_equal([1, 42], f['bar'])
71
+ assert_equal(2, f['bar'].size)
72
72
  end
73
73
  found = 0
74
74
  fb.query('(always)').each do |f|
75
- assert_equal([1, 42], f['bar'])
75
+ assert_equal(2, f['bar'].size)
76
76
  found += 1
77
77
  end
78
78
  assert_equal(1, found)
79
- assert_equal([1, 42], fb.query('(always)').each.to_a[0]['bar'])
79
+ assert_equal(2, fb.query('(always)').each.to_a[0]['bar'].size)
80
80
  end
81
81
 
82
82
  def test_serialize_and_deserialize
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.50
4
+ version: 0.0.52
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-13 00:00:00.000000000 Z
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backtrace
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: json
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -115,6 +129,7 @@ files:
115
129
  - Rakefile
116
130
  - factbase.gemspec
117
131
  - lib/factbase.rb
132
+ - lib/factbase/accum.rb
118
133
  - lib/factbase/fact.rb
119
134
  - lib/factbase/flatten.rb
120
135
  - lib/factbase/inv.rb
@@ -123,12 +138,25 @@ files:
123
138
  - lib/factbase/query.rb
124
139
  - lib/factbase/rules.rb
125
140
  - lib/factbase/syntax.rb
141
+ - lib/factbase/tee.rb
126
142
  - lib/factbase/term.rb
143
+ - lib/factbase/terms/aggregates.rb
144
+ - lib/factbase/terms/aliases.rb
145
+ - lib/factbase/terms/debug.rb
146
+ - lib/factbase/terms/defn.rb
147
+ - lib/factbase/terms/logical.rb
148
+ - lib/factbase/terms/math.rb
149
+ - lib/factbase/terms/meta.rb
150
+ - lib/factbase/terms/ordering.rb
151
+ - lib/factbase/terms/strings.rb
127
152
  - lib/factbase/to_json.rb
128
153
  - lib/factbase/to_xml.rb
129
154
  - lib/factbase/to_yaml.rb
130
- - lib/factbase/tuples.rb
131
155
  - renovate.json
156
+ - test/factbase/terms/test_aggregates.rb
157
+ - test/factbase/terms/test_aliases.rb
158
+ - test/factbase/terms/test_math.rb
159
+ - test/factbase/test_accum.rb
132
160
  - test/factbase/test_fact.rb
133
161
  - test/factbase/test_flatten.rb
134
162
  - test/factbase/test_inv.rb
@@ -137,11 +165,11 @@ files:
137
165
  - test/factbase/test_query.rb
138
166
  - test/factbase/test_rules.rb
139
167
  - test/factbase/test_syntax.rb
168
+ - test/factbase/test_tee.rb
140
169
  - test/factbase/test_term.rb
141
170
  - test/factbase/test_to_json.rb
142
171
  - test/factbase/test_to_xml.rb
143
172
  - test/factbase/test_to_yaml.rb
144
- - test/factbase/test_tuples.rb
145
173
  - test/test__helper.rb
146
174
  - test/test_factbase.rb
147
175
  homepage: http://github.com/yegor256/factbase.rb
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'minitest/autorun'
24
- require_relative '../../lib/factbase'
25
- require_relative '../../lib/factbase/tuples'
26
-
27
- # Test.
28
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
- # Copyright:: Copyright (c) 2024 Yegor Bugayenko
30
- # License:: MIT
31
- class TestTuples < Minitest::Test
32
- def test_passes_facts
33
- fb = Factbase.new
34
- f1 = fb.insert
35
- f1.foo = 42
36
- f2 = fb.insert
37
- f2.bar = 55
38
- Factbase::Tuples.new(fb, ['(exists foo)', '(exists bar)']).each do |a, b|
39
- assert_equal(42, a.foo)
40
- assert_equal(55, b.bar)
41
- end
42
- end
43
-
44
- def test_with_empty_list_of_queries
45
- fb = Factbase.new
46
- f1 = fb.insert
47
- f1.foo = 42
48
- tuples = Factbase::Tuples.new(fb, [])
49
- assert(tuples.each.to_a.empty?)
50
- end
51
-
52
- def test_is_reusable
53
- fb = Factbase.new
54
- f1 = fb.insert
55
- f1.foo = 42
56
- tuples = Factbase::Tuples.new(fb, ['(exists foo)'])
57
- assert_equal(1, tuples.each.to_a.size)
58
- assert_equal(1, tuples.each.to_a.size)
59
- end
60
-
61
- def test_with_modifications
62
- fb = Factbase.new
63
- f1 = fb.insert
64
- f1.foo = 42
65
- Factbase::Tuples.new(fb, ['(exists foo)']).each do |fs|
66
- fs[0].bar = 1
67
- end
68
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
69
- end
70
-
71
- def test_with_txn
72
- fb = Factbase.new
73
- f1 = fb.insert
74
- f1.foo = 42
75
- Factbase::Tuples.new(fb, ['(exists foo)']).each do |fs|
76
- fb.txn do |fbt|
77
- f = fbt.insert
78
- f.bar = 1
79
- end
80
- fs[0].xyz = 'hey'
81
- end
82
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
83
- assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
84
- end
85
-
86
- def test_with_chaining
87
- fb = Factbase.new
88
- f1 = fb.insert
89
- f1.name = 'Jeff'
90
- f1.friend = 'Walter'
91
- f2 = fb.insert
92
- f2.name = 'Walter'
93
- f2.group = 1
94
- f3 = fb.insert
95
- f3.name = 'Donny'
96
- f3.group = 1
97
- tuples = Factbase::Tuples.new(
98
- fb, ['(eq name "Jeff")', '(eq name "{f0.friend}")', '(eq group {f1.group})']
99
- )
100
- tuples.each do |fs|
101
- assert_equal('Walter', fs[1].name)
102
- assert(%w[Walter Donny].include?(fs[2].name))
103
- end
104
- assert_equal(2, tuples.each.to_a.size)
105
- end
106
- end