factbase 0.8.0 → 0.9.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -13
- data/README.md +24 -24
- data/REUSE.toml +7 -2
- data/Rakefile +8 -1
- data/benchmark/bench_factbase.rb +1 -1
- data/fixtures/stories/agg.yml +17 -0
- data/fixtures/stories/always.yml +16 -0
- data/fixtures/stories/as.yml +16 -0
- data/fixtures/stories/count.yml +18 -0
- data/fixtures/stories/eq.yml +30 -0
- data/fixtures/stories/gt.yml +18 -0
- data/fixtures/stories/join.yml +19 -0
- data/fixtures/stories/max.yml +14 -0
- data/fixtures/stories/min.yml +14 -0
- data/fixtures/stories/nth.yml +14 -0
- data/fixtures/stories/or.yml +18 -0
- data/fixtures/stories/sprintf.yml +12 -0
- data/fixtures/stories/sum.yml +14 -0
- data/lib/factbase/cached/cached_fact.rb +28 -0
- data/lib/factbase/cached/cached_factbase.rb +64 -0
- data/lib/factbase/cached/cached_query.rb +61 -0
- data/lib/factbase/cached/cached_term.rb +25 -0
- data/lib/factbase/fact.rb +13 -13
- data/lib/factbase/indexed/indexed_fact.rb +28 -0
- data/lib/factbase/indexed/indexed_factbase.rb +64 -0
- data/lib/factbase/indexed/indexed_query.rb +56 -0
- data/lib/factbase/indexed/indexed_term.rb +60 -0
- data/lib/factbase/inv.rb +18 -6
- data/lib/factbase/light.rb +7 -6
- data/lib/factbase/logged.rb +87 -62
- data/lib/factbase/query.rb +29 -34
- data/lib/factbase/rules.rb +16 -15
- data/lib/factbase/sync/sync_factbase.rb +57 -0
- data/lib/factbase/sync/sync_query.rb +61 -0
- data/lib/factbase/syntax.rb +12 -25
- data/lib/factbase/tallied.rb +11 -10
- data/lib/factbase/taped.rb +8 -0
- data/lib/factbase/tee.rb +2 -0
- data/lib/factbase/term.rb +45 -17
- data/lib/factbase/terms/aggregates.rb +17 -15
- data/lib/factbase/terms/aliases.rb +4 -4
- data/lib/factbase/terms/casting.rb +8 -8
- data/lib/factbase/terms/debug.rb +2 -2
- data/lib/factbase/terms/defn.rb +3 -3
- data/lib/factbase/terms/logical.rb +53 -14
- data/lib/factbase/terms/math.rb +26 -26
- data/lib/factbase/terms/meta.rb +14 -14
- data/lib/factbase/terms/ordering.rb +4 -4
- data/lib/factbase/terms/strings.rb +8 -8
- data/lib/factbase/terms/system.rb +3 -3
- data/lib/factbase.rb +67 -55
- data/test/factbase/cached/test_cached_factbase.rb +22 -0
- data/test/factbase/cached/test_cached_query.rb +79 -0
- data/test/factbase/indexed/test_indexed_query.rb +175 -0
- data/test/factbase/sync/test_sync_query.rb +30 -0
- data/test/factbase/terms/test_aggregates.rb +5 -5
- data/test/factbase/terms/test_aliases.rb +7 -7
- data/test/factbase/terms/test_casting.rb +8 -8
- data/test/factbase/terms/test_debug.rb +6 -6
- data/test/factbase/terms/test_defn.rb +14 -14
- data/test/factbase/terms/test_logical.rb +17 -19
- data/test/factbase/terms/test_math.rb +63 -61
- data/test/factbase/terms/test_meta.rb +36 -36
- data/test/factbase/terms/test_ordering.rb +9 -9
- data/test/factbase/terms/test_strings.rb +10 -10
- data/test/factbase/terms/test_system.rb +6 -6
- data/test/factbase/test_accum.rb +5 -5
- data/test/factbase/test_fact.rb +12 -12
- data/test/factbase/test_logged.rb +7 -0
- data/test/factbase/test_query.rb +110 -37
- data/test/factbase/test_rules.rb +1 -1
- data/test/factbase/test_syntax.rb +12 -12
- data/test/factbase/test_tee.rb +8 -8
- data/test/factbase/test_term.rb +39 -30
- data/test/test__helper.rb +2 -2
- data/test/test_factbase.rb +6 -0
- metadata +29 -4
- data/lib/factbase/query_once.rb +0 -54
- data/lib/factbase/term_once.rb +0 -67
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
+
# SPDX-License-Identifier: MIT
|
5
|
+
|
6
|
+
require_relative '../../test__helper'
|
7
|
+
require_relative '../../../lib/factbase'
|
8
|
+
require_relative '../../../lib/factbase/cached/cached_factbase'
|
9
|
+
|
10
|
+
# Query test.
|
11
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
13
|
+
# License:: MIT
|
14
|
+
class TestCachedFactbase < Factbase::Test
|
15
|
+
def test_inserts_and_queries
|
16
|
+
fb = Factbase::CachedFactbase.new(Factbase.new)
|
17
|
+
f = fb.insert
|
18
|
+
f.foo = 1
|
19
|
+
f.bar = 'test'
|
20
|
+
assert_equal(1, fb.query('(and (eq foo 1) (eq bar "test"))').each.to_a.size)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
+
# SPDX-License-Identifier: MIT
|
5
|
+
|
6
|
+
require_relative '../../test__helper'
|
7
|
+
require_relative '../../../lib/factbase'
|
8
|
+
require_relative '../../../lib/factbase/cached/cached_factbase'
|
9
|
+
require_relative '../../../lib/factbase/indexed/indexed_factbase'
|
10
|
+
require_relative '../../../lib/factbase/sync/sync_factbase'
|
11
|
+
|
12
|
+
# Query test.
|
13
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
14
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
15
|
+
# License:: MIT
|
16
|
+
class TestCachedQuery < Factbase::Test
|
17
|
+
def test_queries_many_times
|
18
|
+
fb = Factbase::CachedFactbase.new(Factbase.new)
|
19
|
+
total = 5
|
20
|
+
total.times { fb.insert }
|
21
|
+
total.times do
|
22
|
+
assert_equal(5, fb.query('(always)').each.to_a.size)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_negates_correctly
|
27
|
+
fb = Factbase::CachedFactbase.new(Factbase.new)
|
28
|
+
fb.insert.foo = 42
|
29
|
+
3.times do
|
30
|
+
assert_equal(1, fb.query('(always)').each.to_a.size)
|
31
|
+
assert_equal(0, fb.query('(not (always))').each.to_a.size)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_aggregates_too
|
36
|
+
fb = Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
|
37
|
+
10_000.times do |i|
|
38
|
+
f = fb.insert
|
39
|
+
f.foo = i
|
40
|
+
f.hello = 1
|
41
|
+
end
|
42
|
+
3.times do
|
43
|
+
q = fb.query('(eq foo (agg (exists hello) (min foo)))')
|
44
|
+
assert_equal(1, q.each.to_a.size)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_joins_too
|
49
|
+
fb = Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
|
50
|
+
total = 10
|
51
|
+
total.times do |i|
|
52
|
+
f = fb.insert
|
53
|
+
f.foo = i
|
54
|
+
f.hello = 1
|
55
|
+
end
|
56
|
+
3.times do
|
57
|
+
assert_equal(total, fb.query('(join "bar<=foo" (eq foo (agg (exists hello) (min foo))))').each.to_a.size)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_caches_while_being_decorated
|
62
|
+
fb = Factbase::SyncFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
|
63
|
+
10_000.times do |i|
|
64
|
+
f = fb.insert
|
65
|
+
f.foo = i
|
66
|
+
f.hello = 1
|
67
|
+
end
|
68
|
+
3.times do
|
69
|
+
assert_equal(1, fb.query('(eq foo (agg (exists hello) (min foo)))').each.to_a.size)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_deletes_too
|
74
|
+
fb = Factbase::CachedFactbase.new(Factbase.new)
|
75
|
+
fb.insert.foo = 1
|
76
|
+
fb.query('(eq foo 1)').delete!
|
77
|
+
assert_equal(0, fb.query('(always)').each.to_a.size)
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
+
# SPDX-License-Identifier: MIT
|
5
|
+
|
6
|
+
require_relative '../../test__helper'
|
7
|
+
require_relative '../../../lib/factbase'
|
8
|
+
require_relative '../../../lib/factbase/cached/cached_factbase'
|
9
|
+
require_relative '../../../lib/factbase/indexed/indexed_factbase'
|
10
|
+
|
11
|
+
# Query test.
|
12
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
+
# License:: MIT
|
15
|
+
class TestIndexedQuery < Factbase::Test
|
16
|
+
def test_queries_many_times
|
17
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
18
|
+
total = 5
|
19
|
+
total.times { fb.insert }
|
20
|
+
total.times do
|
21
|
+
assert_equal(5, fb.query('(always)').each.to_a.size)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_finds_by_eq
|
26
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
27
|
+
fb.insert.foo = 42
|
28
|
+
fb.insert
|
29
|
+
3.times do
|
30
|
+
assert_equal(1, fb.query('(eq foo 42)').each.to_a.size)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_finds_by_eq_with_symbol
|
35
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
36
|
+
f = fb.insert
|
37
|
+
f.num = 256
|
38
|
+
f.num = 42
|
39
|
+
fb.insert.num = 42
|
40
|
+
fb.insert.num = 55
|
41
|
+
fb.insert
|
42
|
+
fb.insert
|
43
|
+
3.times do
|
44
|
+
assert_equal(1, fb.query('(eq 1 (agg (eq num $num) (count)))').each.to_a.size)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_finds_by_eq_with_array
|
49
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
50
|
+
f = fb.insert
|
51
|
+
f.foo = 33
|
52
|
+
f.foo = 42
|
53
|
+
f.foo = 1
|
54
|
+
3.times do
|
55
|
+
assert_equal(1, fb.query('(eq foo 42)').each.to_a.size)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_finds_by_eq_with_agg
|
60
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
61
|
+
fb.insert.foo = 42
|
62
|
+
fb.insert.foo = 33
|
63
|
+
fb.insert
|
64
|
+
3.times do
|
65
|
+
assert_equal(1, fb.query('(eq foo (agg (exists foo) (max foo)))').each.to_a.size)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_finds_max_value
|
70
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
71
|
+
fb.insert.foo = 42
|
72
|
+
fb.insert.foo = 33
|
73
|
+
fb.insert
|
74
|
+
3.times do
|
75
|
+
assert_equal(42, fb.query('(agg (exists foo) (max foo))').one)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_finds_by_eq_with_formula
|
80
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
81
|
+
fb.insert.foo = 42
|
82
|
+
fb.insert
|
83
|
+
3.times do
|
84
|
+
assert_equal(1, fb.query('(eq foo (plus 40 2))').each.to_a.size)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_finds_by_eq_in_txn
|
89
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
90
|
+
fb.insert.foo = 42
|
91
|
+
fb.insert
|
92
|
+
3.times do
|
93
|
+
fb.txn { |fbt| assert_equal(1, fbt.query('(eq foo 42)').each.to_a.size) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_finds_with_conjunction
|
98
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
99
|
+
fb.insert.foo = 42
|
100
|
+
fb.insert.bar = 33
|
101
|
+
3.times do
|
102
|
+
assert_equal(2, fb.query('(or (exists foo) (exists bar))').each.to_a.size)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_finds_with_disjunction
|
107
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
108
|
+
fb.insert.foo = 42
|
109
|
+
fb.insert.bar = 33
|
110
|
+
f = fb.insert
|
111
|
+
f.foo = 42
|
112
|
+
f.bar = 33
|
113
|
+
3.times do
|
114
|
+
assert_equal(1, fb.query('(and (exists foo) (exists bar))').each.to_a.size)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_finds_with_inversion
|
119
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
120
|
+
fb.insert.foo = 42
|
121
|
+
fb.insert.bar = 33
|
122
|
+
3.times do
|
123
|
+
assert_equal(1, fb.query('(not (exists foo))').each.to_a.size)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_finds_with_disjunction_in_txn
|
128
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
129
|
+
fb.insert.foo = 42
|
130
|
+
fb.insert.bar = 33
|
131
|
+
f = fb.insert
|
132
|
+
f.foo = 42
|
133
|
+
f.bar = 33
|
134
|
+
3.times do
|
135
|
+
fb.txn { |fbt| assert_equal(1, fbt.query('(and (exists foo) (exists bar))').each.to_a.size) }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_attaches_alias
|
140
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
141
|
+
total = 10
|
142
|
+
total.times do |i|
|
143
|
+
f = fb.insert
|
144
|
+
f.foo = rand(0..10)
|
145
|
+
f.bar = rand(0..10)
|
146
|
+
f.xyz = i
|
147
|
+
end
|
148
|
+
3.times do
|
149
|
+
assert_equal(total, fb.query('(as boom (agg (eq foo $bar) (min xyz)))').each.to_a.size)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_joins_too
|
154
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
155
|
+
total = 10_000
|
156
|
+
total.times do |i|
|
157
|
+
f = fb.insert
|
158
|
+
f.who = i
|
159
|
+
end
|
160
|
+
total.times do |i|
|
161
|
+
f = fb.insert
|
162
|
+
f.friend = i
|
163
|
+
end
|
164
|
+
3.times do
|
165
|
+
assert_equal(total, fb.query('(and (exists who) (join "f<=friend" (eq friend $who)))').each.to_a.size)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_deletes_too
|
170
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
171
|
+
fb.insert.foo = 1
|
172
|
+
fb.query('(eq foo 1)').delete!
|
173
|
+
assert_equal(0, fb.query('(always)').each.to_a.size)
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
+
# SPDX-License-Identifier: MIT
|
5
|
+
|
6
|
+
require_relative '../../test__helper'
|
7
|
+
require_relative '../../../lib/factbase'
|
8
|
+
require_relative '../../../lib/factbase/sync/sync_factbase'
|
9
|
+
|
10
|
+
# Query test.
|
11
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
13
|
+
# License:: MIT
|
14
|
+
class TestSyncQuery < Factbase::Test
|
15
|
+
def test_queries_many_times
|
16
|
+
fb = Factbase::SyncFactbase.new(Factbase.new)
|
17
|
+
total = 5
|
18
|
+
total.times { fb.insert }
|
19
|
+
total.times do
|
20
|
+
assert_equal(5, fb.query('(always)').each.to_a.size)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_deletes_too
|
25
|
+
fb = Factbase::SyncFactbase.new(Factbase.new)
|
26
|
+
fb.insert.foo = 1
|
27
|
+
fb.query('(eq foo 1)').delete!
|
28
|
+
assert_equal(0, fb.query('(always)').each.to_a.size)
|
29
|
+
end
|
30
|
+
end
|
@@ -30,10 +30,10 @@ class TestAggregates < Factbase::Test
|
|
30
30
|
'(eq x (agg (eq y 0) (first x)))' => '(eq x 1)',
|
31
31
|
'(agg (eq foo 42) (always))' => '(eq x 1)'
|
32
32
|
}.each do |q, r|
|
33
|
-
t = Factbase::Syntax.new(
|
34
|
-
f = maps.find { |m| t.evaluate(fact(m), maps) }
|
33
|
+
t = Factbase::Syntax.new(q).to_term
|
34
|
+
f = maps.find { |m| t.evaluate(fact(m), maps, Factbase.new) }
|
35
35
|
refute_nil(f, "nothing found by: #{q}")
|
36
|
-
assert(Factbase::Syntax.new(
|
36
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(fact(f), [], Factbase.new))
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -46,8 +46,8 @@ class TestAggregates < Factbase::Test
|
|
46
46
|
'(empty (eq y 42))' => true,
|
47
47
|
'(empty (eq x 1))' => false
|
48
48
|
}.each do |q, r|
|
49
|
-
t = Factbase::Syntax.new(
|
50
|
-
assert_equal(r, t.evaluate(
|
49
|
+
t = Factbase::Syntax.new(q).to_term
|
50
|
+
assert_equal(r, t.evaluate(Factbase::Fact.new({}), maps, Factbase.new), q)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -24,11 +24,11 @@ class TestAliases < Factbase::Test
|
|
24
24
|
'(as foo (plus bar 1))' => '(absent foo)',
|
25
25
|
'(as foo (minus t1 t2))' => '(when (exists foo) (eq "Float" (type foo)))'
|
26
26
|
}.each do |q, r|
|
27
|
-
t = Factbase::Syntax.new(
|
27
|
+
t = Factbase::Syntax.new(q).to_term
|
28
28
|
maps.each do |m|
|
29
29
|
f = Factbase::Accum.new(fact(m), {}, false)
|
30
|
-
next unless t.evaluate(f, maps)
|
31
|
-
assert(Factbase::Syntax.new(
|
30
|
+
next unless t.evaluate(f, maps, Factbase.new)
|
31
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(f, [], Factbase.new), "#{q} -> #{f}")
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -44,13 +44,13 @@ class TestAliases < Factbase::Test
|
|
44
44
|
'(join "uuu" (eq x 1))' => '(absent uuu)',
|
45
45
|
'(join "uuu <= fff" (eq fff 1))' => '(absent uuu)'
|
46
46
|
}.each do |q, r|
|
47
|
-
t = Factbase::Syntax.new(
|
47
|
+
t = Factbase::Syntax.new(q).to_term
|
48
48
|
maps.each do |m|
|
49
49
|
f = Factbase::Accum.new(fact(m), {}, false)
|
50
50
|
require_relative '../../../lib/factbase/logged'
|
51
|
-
f = Factbase::Logged::Fact.new(f, Loog::NULL)
|
52
|
-
next unless t.evaluate(f, maps)
|
53
|
-
assert(Factbase::Syntax.new(
|
51
|
+
f = Factbase::Logged::Fact.new(f, log: Loog::NULL)
|
52
|
+
next unless t.evaluate(f, maps, Factbase.new)
|
53
|
+
assert(Factbase::Syntax.new(r).to_term.evaluate(f, [], Factbase.new), "#{q} -> #{f} doesn't match #{r}")
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -12,22 +12,22 @@ require_relative '../../../lib/factbase/term'
|
|
12
12
|
# License:: MIT
|
13
13
|
class TestCasting < Factbase::Test
|
14
14
|
def test_to_str
|
15
|
-
t = Factbase::Term.new(
|
16
|
-
assert_equal('String', t.evaluate(fact, []).class.to_s)
|
15
|
+
t = Factbase::Term.new(:to_string, [Time.now])
|
16
|
+
assert_equal('String', t.evaluate(fact, [], Factbase.new).class.to_s)
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_to_integer
|
20
|
-
t = Factbase::Term.new(
|
21
|
-
assert_equal('Integer', t.evaluate(fact, []).class.to_s)
|
20
|
+
t = Factbase::Term.new(:to_integer, [[42, 'hello']])
|
21
|
+
assert_equal('Integer', t.evaluate(fact, [], Factbase.new).class.to_s)
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_to_float
|
25
|
-
t = Factbase::Term.new(
|
26
|
-
assert_equal('Float', t.evaluate(fact, []).class.to_s)
|
25
|
+
t = Factbase::Term.new(:to_float, [[3.14, 'hello']])
|
26
|
+
assert_equal('Float', t.evaluate(fact, [], Factbase.new).class.to_s)
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_to_time
|
30
|
-
t = Factbase::Term.new(
|
31
|
-
assert_equal('Time', t.evaluate(fact, []).class.to_s)
|
30
|
+
t = Factbase::Term.new(:to_time, [%w[2023-01-01 hello]])
|
31
|
+
assert_equal('Time', t.evaluate(fact, [], Factbase.new).class.to_s)
|
32
32
|
end
|
33
33
|
end
|
@@ -12,14 +12,14 @@ require_relative '../../../lib/factbase/term'
|
|
12
12
|
# License:: MIT
|
13
13
|
class TestDebug < Factbase::Test
|
14
14
|
def test_traced
|
15
|
-
t = Factbase::Term.new(
|
15
|
+
t = Factbase::Term.new(:traced, [Factbase::Term.new(:defn, [:test_debug, 'self.to_s'])])
|
16
16
|
assert_output("(traced (defn test_debug 'self.to_s')) -> true\n") do
|
17
|
-
assert(t.evaluate(fact, []))
|
17
|
+
assert(t.evaluate(fact, [], Factbase.new))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_traced_raises
|
22
|
-
e = assert_raises(StandardError) { Factbase::Term.new(
|
22
|
+
e = assert_raises(StandardError) { Factbase::Term.new(:traced, ['foo']).evaluate(fact, [], Factbase.new) }
|
23
23
|
assert_match(/A term expected, but 'foo' provided/, e.message)
|
24
24
|
end
|
25
25
|
|
@@ -27,9 +27,9 @@ class TestDebug < Factbase::Test
|
|
27
27
|
e =
|
28
28
|
assert_raises(StandardError) do
|
29
29
|
Factbase::Term.new(
|
30
|
-
|
31
|
-
[Factbase::Term.new(
|
32
|
-
).evaluate(fact, [])
|
30
|
+
:traced,
|
31
|
+
[Factbase::Term.new(:defn, [:debug, 'self.to_s']), 'something']
|
32
|
+
).evaluate(fact, [], Factbase.new)
|
33
33
|
end
|
34
34
|
assert_match(/Too many \(\d+\) operands for 'traced' \(\d+ expected\)/, e.message)
|
35
35
|
end
|
@@ -12,37 +12,37 @@ require_relative '../../../lib/factbase/term'
|
|
12
12
|
# License:: MIT
|
13
13
|
class TestDefn < Factbase::Test
|
14
14
|
def test_defn_simple
|
15
|
-
t = Factbase::Term.new(
|
16
|
-
assert(t.evaluate(fact('foo' => 4), []))
|
17
|
-
t1 = Factbase::Term.new(
|
18
|
-
assert_equal('(foo \'hello, world!\')', t1.evaluate(fact, []))
|
15
|
+
t = Factbase::Term.new(:defn, [:foo, 'self.to_s'])
|
16
|
+
assert(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
17
|
+
t1 = Factbase::Term.new(:foo, ['hello, world!'])
|
18
|
+
assert_equal('(foo \'hello, world!\')', t1.evaluate(fact, [], Factbase.new))
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_defn_again_by_mistake
|
22
|
-
t = Factbase::Term.new(
|
22
|
+
t = Factbase::Term.new(:defn, [:and, 'self.to_s'])
|
23
23
|
assert_raises(StandardError) do
|
24
|
-
t.evaluate(fact, [])
|
24
|
+
t.evaluate(fact, [], Factbase.new)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_defn_bad_name_by_mistake
|
29
|
-
t = Factbase::Term.new(
|
29
|
+
t = Factbase::Term.new(:defn, [:to_s, 'self.to_s'])
|
30
30
|
assert_raises(StandardError) do
|
31
|
-
t.evaluate(fact, [])
|
31
|
+
t.evaluate(fact, [], Factbase.new)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_defn_bad_name_spelling_by_mistake
|
36
|
-
t = Factbase::Term.new(
|
36
|
+
t = Factbase::Term.new(:defn, [:'some-key', 'self.to_s'])
|
37
37
|
assert_raises(StandardError) do
|
38
|
-
t.evaluate(fact, [])
|
38
|
+
t.evaluate(fact, [], Factbase.new)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_undef_simple
|
43
|
-
t = Factbase::Term.new(
|
44
|
-
assert(t.evaluate(fact, []))
|
45
|
-
t = Factbase::Term.new(
|
46
|
-
assert(t.evaluate(fact, []))
|
43
|
+
t = Factbase::Term.new(:defn, [:hello, 'self.to_s'])
|
44
|
+
assert(t.evaluate(fact, [], Factbase.new))
|
45
|
+
t = Factbase::Term.new(:undef, [:hello])
|
46
|
+
assert(t.evaluate(fact, [], Factbase.new))
|
47
47
|
end
|
48
48
|
end
|
@@ -12,46 +12,44 @@ require_relative '../../../lib/factbase/term'
|
|
12
12
|
# License:: MIT
|
13
13
|
class TestLogical < Factbase::Test
|
14
14
|
def test_not_matching
|
15
|
-
t = Factbase::Term.new(
|
16
|
-
refute(t.evaluate(fact('foo' => [100]), []))
|
15
|
+
t = Factbase::Term.new(:not, [Factbase::Term.new(:always, [])])
|
16
|
+
refute(t.evaluate(fact('foo' => [100]), [], Factbase.new))
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_not_eq_matching
|
20
|
-
t = Factbase::Term.new(
|
21
|
-
assert(t.evaluate(fact('foo' => [42, 12, -90]), []))
|
22
|
-
refute(t.evaluate(fact('foo' => 100), []))
|
20
|
+
t = Factbase::Term.new(:not, [Factbase::Term.new(:eq, [:foo, 100])])
|
21
|
+
assert(t.evaluate(fact('foo' => [42, 12, -90]), [], Factbase.new))
|
22
|
+
refute(t.evaluate(fact('foo' => 100), [], Factbase.new))
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_either
|
26
|
-
t = Factbase::Term.new(
|
27
|
-
assert_equal([42], t.evaluate(fact('foo' => 4), []))
|
26
|
+
t = Factbase::Term.new(:either, [Factbase::Term.new(:at, [5, :foo]), 42])
|
27
|
+
assert_equal([42], t.evaluate(fact('foo' => 4), [], Factbase.new))
|
28
28
|
end
|
29
29
|
|
30
30
|
def test_or_matching
|
31
31
|
t = Factbase::Term.new(
|
32
|
-
Factbase.new,
|
33
32
|
:or,
|
34
33
|
[
|
35
|
-
Factbase::Term.new(
|
36
|
-
Factbase::Term.new(
|
34
|
+
Factbase::Term.new(:eq, [:foo, 4]),
|
35
|
+
Factbase::Term.new(:eq, [:bar, 5])
|
37
36
|
]
|
38
37
|
)
|
39
|
-
assert(t.evaluate(fact('foo' => [4]), []))
|
40
|
-
assert(t.evaluate(fact('bar' => [5]), []))
|
41
|
-
refute(t.evaluate(fact('bar' => [42]), []))
|
38
|
+
assert(t.evaluate(fact('foo' => [4]), [], Factbase.new))
|
39
|
+
assert(t.evaluate(fact('bar' => [5]), [], Factbase.new))
|
40
|
+
refute(t.evaluate(fact('bar' => [42]), [], Factbase.new))
|
42
41
|
end
|
43
42
|
|
44
43
|
def test_when_matching
|
45
44
|
t = Factbase::Term.new(
|
46
|
-
Factbase.new,
|
47
45
|
:when,
|
48
46
|
[
|
49
|
-
Factbase::Term.new(
|
50
|
-
Factbase::Term.new(
|
47
|
+
Factbase::Term.new(:eq, [:foo, 4]),
|
48
|
+
Factbase::Term.new(:eq, [:bar, 5])
|
51
49
|
]
|
52
50
|
)
|
53
|
-
assert(t.evaluate(fact('foo' => 4, 'bar' => 5), []))
|
54
|
-
refute(t.evaluate(fact('foo' => 4), []))
|
55
|
-
assert(t.evaluate(fact('foo' => 5, 'bar' => 5), []))
|
51
|
+
assert(t.evaluate(fact('foo' => 4, 'bar' => 5), [], Factbase.new))
|
52
|
+
refute(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
53
|
+
assert(t.evaluate(fact('foo' => 5, 'bar' => 5), [], Factbase.new))
|
56
54
|
end
|
57
55
|
end
|