factbase 0.0.50 → 0.0.52

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.
@@ -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