factbase 0.0.50 → 0.0.51

Sign up to get free protection for your applications and to get access to all the features.
@@ -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