factbase 0.0.50 → 0.0.52
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/Gemfile.lock +19 -26
- data/README.md +57 -35
- data/factbase.gemspec +1 -0
- data/lib/factbase/{tuples.rb → accum.rb} +40 -40
- data/lib/factbase/fact.rb +4 -9
- data/lib/factbase/looged.rb +18 -5
- data/lib/factbase/query.rb +27 -5
- data/lib/factbase/rules.rb +6 -2
- data/lib/factbase/syntax.rb +2 -2
- data/lib/factbase/tee.rb +59 -0
- data/lib/factbase/term.rb +32 -278
- data/lib/factbase/terms/aggregates.rb +109 -0
- data/lib/factbase/terms/aliases.rb +60 -0
- data/lib/factbase/terms/debug.rb +39 -0
- data/lib/factbase/terms/defn.rb +54 -0
- data/lib/factbase/terms/logical.rb +95 -0
- data/lib/factbase/terms/math.rb +91 -0
- data/lib/factbase/terms/meta.rb +73 -0
- data/lib/factbase/terms/ordering.rb +51 -0
- data/lib/factbase/terms/strings.rb +41 -0
- data/lib/factbase/to_xml.rb +6 -2
- data/lib/factbase.rb +3 -1
- data/test/factbase/terms/test_aggregates.rb +76 -0
- data/test/factbase/terms/test_aliases.rb +79 -0
- data/test/factbase/terms/test_math.rb +99 -0
- data/test/factbase/test_accum.rb +70 -0
- data/test/factbase/test_looged.rb +8 -0
- data/test/factbase/test_query.rb +51 -8
- data/test/factbase/test_rules.rb +8 -1
- data/test/factbase/test_syntax.rb +1 -1
- data/test/factbase/test_tee.rb +53 -0
- data/test/factbase/test_term.rb +7 -76
- data/test/factbase/test_to_xml.rb +26 -2
- data/test/test_factbase.rb +3 -3
- metadata +32 -4
- data/test/factbase/test_tuples.rb +0 -106
@@ -0,0 +1,95 @@
|
|
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_relative '../../factbase'
|
24
|
+
|
25
|
+
# Logical terms.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Factbase::Term::Logical
|
31
|
+
def always(_fact, _maps)
|
32
|
+
assert_args(0)
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def never(_fact, _maps)
|
37
|
+
assert_args(0)
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def not(fact, maps)
|
42
|
+
assert_args(1)
|
43
|
+
!_only_bool(the_values(0, fact, maps), 0)
|
44
|
+
end
|
45
|
+
|
46
|
+
def or(fact, maps)
|
47
|
+
(0..@operands.size - 1).each do |i|
|
48
|
+
return true if _only_bool(the_values(i, fact, maps), i)
|
49
|
+
end
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def and(fact, maps)
|
54
|
+
(0..@operands.size - 1).each do |i|
|
55
|
+
return false unless _only_bool(the_values(i, fact, maps), i)
|
56
|
+
end
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def and_or_simplify
|
61
|
+
strs = []
|
62
|
+
ops = []
|
63
|
+
@operands.each do |o|
|
64
|
+
o = o.simplify
|
65
|
+
s = o.to_s
|
66
|
+
next if strs.include?(s)
|
67
|
+
strs << s
|
68
|
+
ops << o
|
69
|
+
end
|
70
|
+
return ops[0] if ops.size == 1
|
71
|
+
Factbase::Term.new(@op, ops)
|
72
|
+
end
|
73
|
+
|
74
|
+
def and_simplify
|
75
|
+
and_or_simplify
|
76
|
+
end
|
77
|
+
|
78
|
+
def or_simplify
|
79
|
+
and_or_simplify
|
80
|
+
end
|
81
|
+
|
82
|
+
def when(fact, maps)
|
83
|
+
assert_args(2)
|
84
|
+
a = @operands[0]
|
85
|
+
b = @operands[1]
|
86
|
+
!a.evaluate(fact, maps) || (a.evaluate(fact, maps) && b.evaluate(fact, maps))
|
87
|
+
end
|
88
|
+
|
89
|
+
def _only_bool(val, pos)
|
90
|
+
val = val[0] if val.is_a?(Array)
|
91
|
+
return false if val.nil?
|
92
|
+
return val if val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
93
|
+
raise "Boolean expected, while #{val.class} received from #{@operands[pos]}"
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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_relative '../../factbase'
|
24
|
+
|
25
|
+
# Math terms.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Factbase::Term::Math
|
31
|
+
def plus(fact, maps)
|
32
|
+
arithmetic(:+, fact, maps)
|
33
|
+
end
|
34
|
+
|
35
|
+
def minus(fact, maps)
|
36
|
+
arithmetic(:-, fact, maps)
|
37
|
+
end
|
38
|
+
|
39
|
+
def times(fact, maps)
|
40
|
+
arithmetic(:*, fact, maps)
|
41
|
+
end
|
42
|
+
|
43
|
+
def div(fact, maps)
|
44
|
+
arithmetic(:/, fact, maps)
|
45
|
+
end
|
46
|
+
|
47
|
+
def zero(fact, maps)
|
48
|
+
assert_args(1)
|
49
|
+
vv = the_values(0, fact, maps)
|
50
|
+
return false if vv.nil?
|
51
|
+
vv.any? { |v| (v.is_a?(Integer) || v.is_a?(Float)) && v.zero? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def eq(fact, maps)
|
55
|
+
cmp(:==, fact, maps)
|
56
|
+
end
|
57
|
+
|
58
|
+
def lt(fact, maps)
|
59
|
+
cmp(:<, fact, maps)
|
60
|
+
end
|
61
|
+
|
62
|
+
def gt(fact, maps)
|
63
|
+
cmp(:>, fact, maps)
|
64
|
+
end
|
65
|
+
|
66
|
+
def cmp(op, fact, maps)
|
67
|
+
assert_args(2)
|
68
|
+
lefts = the_values(0, fact, maps)
|
69
|
+
return false if lefts.nil?
|
70
|
+
rights = the_values(1, fact, maps)
|
71
|
+
return false if rights.nil?
|
72
|
+
lefts.any? do |l|
|
73
|
+
l = l.floor if l.is_a?(Time) && op == :==
|
74
|
+
rights.any? do |r|
|
75
|
+
r = r.floor if r.is_a?(Time) && op == :==
|
76
|
+
l.send(op, r)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def arithmetic(op, fact, maps)
|
82
|
+
assert_args(2)
|
83
|
+
lefts = the_values(0, fact, maps)
|
84
|
+
return nil if lefts.nil?
|
85
|
+
raise 'Too many values at first position, one expected' unless lefts.size == 1
|
86
|
+
rights = the_values(1, fact, maps)
|
87
|
+
return nil if rights.nil?
|
88
|
+
raise 'Too many values at second position, one expected' unless rights.size == 1
|
89
|
+
lefts[0].send(op, rights[0])
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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_relative '../../factbase'
|
24
|
+
|
25
|
+
# Meta terms.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Factbase::Term::Meta
|
31
|
+
def exists(fact, _maps)
|
32
|
+
assert_args(1)
|
33
|
+
!by_symbol(0, fact).nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def absent(fact, _maps)
|
37
|
+
assert_args(1)
|
38
|
+
by_symbol(0, fact).nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def size(fact, _maps)
|
42
|
+
assert_args(1)
|
43
|
+
v = by_symbol(0, fact)
|
44
|
+
return 0 if v.nil?
|
45
|
+
return 1 unless v.is_a?(Array)
|
46
|
+
v.size
|
47
|
+
end
|
48
|
+
|
49
|
+
def type(fact, _maps)
|
50
|
+
assert_args(1)
|
51
|
+
v = by_symbol(0, fact)
|
52
|
+
return 'nil' if v.nil?
|
53
|
+
v = v[0] if v.is_a?(Array) && v.size == 1
|
54
|
+
v.class.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
def nil(fact, maps)
|
58
|
+
assert_args(1)
|
59
|
+
the_values(0, fact, maps).nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
def many(fact, maps)
|
63
|
+
assert_args(1)
|
64
|
+
v = the_values(0, fact, maps)
|
65
|
+
!v.nil? && v.size > 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def one(fact, maps)
|
69
|
+
assert_args(1)
|
70
|
+
v = the_values(0, fact, maps)
|
71
|
+
!v.nil? && v.size == 1
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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_relative '../../factbase'
|
24
|
+
|
25
|
+
# Ordering terms.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Factbase::Term::Ordering
|
31
|
+
def prev(fact, maps)
|
32
|
+
assert_args(1)
|
33
|
+
before = @prev
|
34
|
+
v = the_values(0, fact, maps)
|
35
|
+
@prev = v
|
36
|
+
before
|
37
|
+
end
|
38
|
+
|
39
|
+
def unique(fact, _maps)
|
40
|
+
@uniques = [] if @uniques.nil?
|
41
|
+
assert_args(1)
|
42
|
+
vv = by_symbol(0, fact)
|
43
|
+
return false if vv.nil?
|
44
|
+
vv = [vv] unless vv.is_a?(Array)
|
45
|
+
vv.each do |v|
|
46
|
+
return false if @uniques.include?(v)
|
47
|
+
@uniques << v
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
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_relative '../../factbase'
|
24
|
+
|
25
|
+
# String terms.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Factbase::Term::Strings
|
31
|
+
def matches(fact, maps)
|
32
|
+
assert_args(2)
|
33
|
+
str = the_values(0, fact, maps)
|
34
|
+
return false if str.nil?
|
35
|
+
raise 'Exactly one string expected' unless str.size == 1
|
36
|
+
re = the_values(1, fact, maps)
|
37
|
+
raise 'Regexp is nil' if re.nil?
|
38
|
+
raise 'Exactly one regexp expected' unless re.size == 1
|
39
|
+
str[0].to_s.match?(re[0])
|
40
|
+
end
|
41
|
+
end
|
data/lib/factbase/to_xml.rb
CHANGED
@@ -59,11 +59,11 @@ class Factbase::ToXML
|
|
59
59
|
if vv.is_a?(Array)
|
60
60
|
xml.send(:"#{k}_") do
|
61
61
|
vv.each do |v|
|
62
|
-
xml.send(:v, to_str(v))
|
62
|
+
xml.send(:v, to_str(v), t: type_of(v))
|
63
63
|
end
|
64
64
|
end
|
65
65
|
else
|
66
|
-
xml.send(:"#{k}_", to_str(vv))
|
66
|
+
xml.send(:"#{k}_", to_str(vv), t: type_of(vv))
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -81,4 +81,8 @@ class Factbase::ToXML
|
|
81
81
|
val.to_s
|
82
82
|
end
|
83
83
|
end
|
84
|
+
|
85
|
+
def type_of(val)
|
86
|
+
val.class.to_s[0]
|
87
|
+
end
|
84
88
|
end
|
data/lib/factbase.rb
CHANGED
@@ -74,12 +74,14 @@ require 'yaml'
|
|
74
74
|
# It's important to use +binwrite+ and +binread+, because the content is
|
75
75
|
# a chain of bytes, not a text.
|
76
76
|
#
|
77
|
+
# It is NOT thread-safe!
|
78
|
+
#
|
77
79
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
78
80
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
79
81
|
# License:: MIT
|
80
82
|
class Factbase
|
81
83
|
# Current version of the gem (changed by .rultor.yml on every release)
|
82
|
-
VERSION = '0.0.
|
84
|
+
VERSION = '0.0.52'
|
83
85
|
|
84
86
|
# An exception that may be thrown in a transaction, to roll it back.
|
85
87
|
class Rollback < StandardError; end
|
@@ -0,0 +1,76 @@
|
|
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/term'
|
25
|
+
require_relative '../../../lib/factbase/syntax'
|
26
|
+
|
27
|
+
# Aggregates test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestAggregates < Minitest::Test
|
32
|
+
def test_aggregation
|
33
|
+
maps = [
|
34
|
+
{ 'x' => [1], 'y' => [0], 'z' => [4] },
|
35
|
+
{ 'x' => [2], 'y' => [42], 'z' => [3] },
|
36
|
+
{ 'x' => [3], 'y' => [42], 'z' => [5] },
|
37
|
+
{ 'x' => [4], 'y' => [42], 'z' => [2] },
|
38
|
+
{ 'x' => [5], 'y' => [42], 'z' => [1] },
|
39
|
+
{ 'x' => [8], 'y' => [0], 'z' => [6] }
|
40
|
+
]
|
41
|
+
{
|
42
|
+
'(eq x (agg (eq y 42) (min x)))' => '(eq x 2)',
|
43
|
+
'(eq z (agg (eq y 0) (max z)))' => '(eq x 8)',
|
44
|
+
'(eq x (agg (and (eq y 42) (gt z 1)) (max x)))' => '(eq x 4)',
|
45
|
+
'(and (eq x (agg (eq y 42) (min x))) (eq z 3))' => '(eq x 2)',
|
46
|
+
'(eq x (agg (eq y 0) (nth 0 x)))' => '(eq x 1)',
|
47
|
+
'(eq x (agg (eq y 0) (first x)))' => '(eq x 1)',
|
48
|
+
'(agg (eq foo 42) (always))' => '(eq x 1)'
|
49
|
+
}.each do |q, r|
|
50
|
+
t = Factbase::Syntax.new(q).to_term
|
51
|
+
f = maps.find { |m| t.evaluate(fact(m), maps) }
|
52
|
+
assert(!f.nil?, "nothing found by: #{q}")
|
53
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(fact(f), []))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_empty
|
58
|
+
maps = [
|
59
|
+
{ 'x' => [1], 'y' => [0], 'z' => [4] },
|
60
|
+
{ 'x' => [8], 'y' => [0] }
|
61
|
+
]
|
62
|
+
{
|
63
|
+
'(empty (eq y 42))' => true,
|
64
|
+
'(empty (eq x 1))' => false
|
65
|
+
}.each do |q, r|
|
66
|
+
t = Factbase::Syntax.new(q).to_term
|
67
|
+
assert_equal(r, t.evaluate(nil, maps), q)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def fact(map = {})
|
74
|
+
Factbase::Fact.new(Mutex.new, map)
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,79 @@
|
|
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/term'
|
25
|
+
require_relative '../../../lib/factbase/syntax'
|
26
|
+
require_relative '../../../lib/factbase/accum'
|
27
|
+
|
28
|
+
# Aliases test.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
class TestAliases < Minitest::Test
|
33
|
+
def test_aliases
|
34
|
+
maps = [
|
35
|
+
{ 'x' => [1], 'y' => [0] },
|
36
|
+
{ 'x' => [2], 'y' => [42] }
|
37
|
+
]
|
38
|
+
{
|
39
|
+
'(as foo (plus x 1))' => '(exists foo)',
|
40
|
+
'(as foo (plus x y))' => '(gt foo 0)',
|
41
|
+
'(as foo (plus bar 1))' => '(absent foo)'
|
42
|
+
}.each do |q, r|
|
43
|
+
t = Factbase::Syntax.new(q).to_term
|
44
|
+
maps.each do |m|
|
45
|
+
f = Factbase::Accum.new(fact(m), {}, false)
|
46
|
+
next unless t.evaluate(f, maps)
|
47
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(f, []), "#{q} -> #{f}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_join
|
53
|
+
maps = [
|
54
|
+
{ 'x' => 1, 'y' => 0, 'z' => 4 },
|
55
|
+
{ 'x' => [2], 'bar' => [44, 55, 66] }
|
56
|
+
]
|
57
|
+
{
|
58
|
+
'(join "foo_x<=x" (gt x 1))' => '(exists foo_x)',
|
59
|
+
'(join "foo <=bar " (exists bar))' => '(and (eq foo 44) (eq foo 55))',
|
60
|
+
'(join "uuu" (eq x 1))' => '(absent uuu)',
|
61
|
+
'(join "uuu <= fff" (eq fff 1))' => '(absent uuu)'
|
62
|
+
}.each do |q, r|
|
63
|
+
t = Factbase::Syntax.new(q).to_term
|
64
|
+
maps.each do |m|
|
65
|
+
f = Factbase::Accum.new(fact(m), {}, false)
|
66
|
+
require_relative '../../../lib/factbase/looged'
|
67
|
+
f = Factbase::Looged::Fact.new(f, Loog::NULL)
|
68
|
+
next unless t.evaluate(f, maps)
|
69
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(f, []), "#{q} -> #{f} doesn't match #{r}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def fact(map = {})
|
77
|
+
Factbase::Fact.new(Mutex.new, map)
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,99 @@
|
|
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/term'
|
25
|
+
|
26
|
+
# Aggregates test.
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
class TestMath < Minitest::Test
|
31
|
+
def test_simple
|
32
|
+
t = Factbase::Term.new(:eq, [:foo, 42])
|
33
|
+
assert(t.evaluate(fact('foo' => [42]), []))
|
34
|
+
assert(!t.evaluate(fact('foo' => 'Hello!'), []))
|
35
|
+
assert(!t.evaluate(fact('bar' => ['Hello!']), []))
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_zero
|
39
|
+
t = Factbase::Term.new(:zero, [:foo])
|
40
|
+
assert(t.evaluate(fact('foo' => [0]), []))
|
41
|
+
assert(t.evaluate(fact('foo' => [10, 5, 6, -8, 'hey', 0, 9, 'fdsf']), []))
|
42
|
+
assert(!t.evaluate(fact('foo' => [100]), []))
|
43
|
+
assert(!t.evaluate(fact('foo' => []), []))
|
44
|
+
assert(!t.evaluate(fact('bar' => []), []))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_eq
|
48
|
+
t = Factbase::Term.new(:eq, [:foo, 42])
|
49
|
+
assert(t.evaluate(fact('foo' => 42), []))
|
50
|
+
assert(t.evaluate(fact('foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf']), []))
|
51
|
+
assert(!t.evaluate(fact('foo' => [100]), []))
|
52
|
+
assert(!t.evaluate(fact('foo' => []), []))
|
53
|
+
assert(!t.evaluate(fact('bar' => []), []))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_eq_time
|
57
|
+
now = Time.now
|
58
|
+
t = Factbase::Term.new(:eq, [:foo, Time.parse(now.iso8601)])
|
59
|
+
assert(t.evaluate(fact('foo' => now), []))
|
60
|
+
assert(t.evaluate(fact('foo' => [now, Time.now]), []))
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_lt
|
64
|
+
t = Factbase::Term.new(:lt, [:foo, 42])
|
65
|
+
assert(t.evaluate(fact('foo' => [10]), []))
|
66
|
+
assert(!t.evaluate(fact('foo' => [100]), []))
|
67
|
+
assert(!t.evaluate(fact('foo' => 100), []))
|
68
|
+
assert(!t.evaluate(fact('bar' => 100), []))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_gt
|
72
|
+
t = Factbase::Term.new(:gt, [:foo, 42])
|
73
|
+
assert(t.evaluate(fact('foo' => [100]), []))
|
74
|
+
assert(t.evaluate(fact('foo' => 100), []))
|
75
|
+
assert(!t.evaluate(fact('foo' => [10]), []))
|
76
|
+
assert(!t.evaluate(fact('foo' => 10), []))
|
77
|
+
assert(!t.evaluate(fact('bar' => 10), []))
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_lt_time
|
81
|
+
t = Factbase::Term.new(:lt, [:foo, Time.now])
|
82
|
+
assert(t.evaluate(fact('foo' => [Time.now - 100]), []))
|
83
|
+
assert(!t.evaluate(fact('foo' => [Time.now + 100]), []))
|
84
|
+
assert(!t.evaluate(fact('bar' => [100]), []))
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_gt_time
|
88
|
+
t = Factbase::Term.new(:gt, [:foo, Time.now])
|
89
|
+
assert(t.evaluate(fact('foo' => [Time.now + 100]), []))
|
90
|
+
assert(!t.evaluate(fact('foo' => [Time.now - 100]), []))
|
91
|
+
assert(!t.evaluate(fact('bar' => [100]), []))
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def fact(map = {})
|
97
|
+
Factbase::Fact.new(Mutex.new, map)
|
98
|
+
end
|
99
|
+
end
|