factbase 0.0.50 → 0.0.51

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.
@@ -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,43 @@
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
+ 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.51
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-18 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