factbase 0.0.49 → 0.0.51
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +18 -25
- data/README.md +52 -35
- data/factbase.gemspec +1 -0
- data/lib/factbase/{tuples.rb → accum.rb} +39 -40
- data/lib/factbase/fact.rb +4 -9
- data/lib/factbase/looged.rb +11 -7
- data/lib/factbase/query.rb +7 -2
- data/lib/factbase/rules.rb +35 -12
- data/lib/factbase/syntax.rb +2 -2
- data/lib/factbase/tee.rb +57 -0
- data/lib/factbase/term.rb +32 -278
- data/lib/factbase/terms/aggregates.rb +102 -0
- data/lib/factbase/terms/aliases.rb +56 -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 +62 -0
- data/test/factbase/terms/test_aliases.rb +76 -0
- data/test/factbase/terms/test_math.rb +99 -0
- data/test/factbase/test_accum.rb +70 -0
- data/test/factbase/test_looged.rb +1 -0
- data/test/factbase/test_query.rb +23 -8
- data/test/factbase/test_rules.rb +14 -1
- data/test/factbase/test_syntax.rb +1 -1
- data/test/factbase/test_tee.rb +43 -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,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.51'
|
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,62 @@
|
|
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
|
+
private
|
58
|
+
|
59
|
+
def fact(map = {})
|
60
|
+
Factbase::Fact.new(Mutex.new, map)
|
61
|
+
end
|
62
|
+
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
|
+
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_*" (gt x 1))' => '(exists foo_x)',
|
59
|
+
'(join "foo_*" (exists bar))' => '(and (eq foo_bar 44) (eq foo_bar 55))',
|
60
|
+
'(join "foo_*" (eq fff 1))' => '(absent foo_bar)'
|
61
|
+
}.each do |q, r|
|
62
|
+
t = Factbase::Syntax.new(q).to_term
|
63
|
+
maps.each do |m|
|
64
|
+
f = Factbase::Accum.new(fact(m), {}, false)
|
65
|
+
next unless t.evaluate(f, maps)
|
66
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(f, []), "#{q} -> #{f}")
|
67
|
+
end
|
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,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
|
@@ -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
|