factbase 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.0pdd.yml +1 -1
- data/.github/workflows/actionlint.yml +1 -1
- data/.github/workflows/benchmark.yml +64 -0
- data/.github/workflows/codecov.yml +4 -2
- data/.github/workflows/copyrights.yml +2 -2
- data/.github/workflows/markdown-lint.yml +1 -1
- data/.github/workflows/pdd.yml +1 -1
- data/.github/workflows/rake.yml +2 -2
- data/.github/workflows/xcop.yml +1 -1
- data/.github/workflows/yamllint.yml +1 -1
- data/.gitignore +1 -1
- data/.rubocop.yml +6 -1
- data/.rultor.yml +2 -2
- data/.simplecov +1 -1
- data/.yamllint.yml +9 -4
- data/Gemfile +9 -7
- data/Gemfile.lock +99 -78
- data/LICENSE.txt +1 -1
- data/README.md +33 -0
- data/Rakefile +6 -1
- data/benchmarks/simple.rb +96 -0
- data/factbase.gemspec +1 -1
- data/lib/factbase/accum.rb +2 -2
- data/lib/factbase/fact.rb +6 -4
- data/lib/factbase/flatten.rb +2 -2
- data/lib/factbase/inv.rb +2 -2
- data/lib/factbase/looged.rb +6 -5
- data/lib/factbase/pre.rb +2 -2
- data/lib/factbase/query.rb +16 -8
- data/lib/factbase/query_once.rb +71 -0
- data/lib/factbase/rules.rb +3 -3
- data/lib/factbase/syntax.rb +13 -8
- data/lib/factbase/tee.rb +2 -2
- data/lib/factbase/term.rb +33 -5
- data/lib/factbase/term_once.rb +84 -0
- data/lib/factbase/terms/aggregates.rb +4 -4
- data/lib/factbase/terms/aliases.rb +5 -5
- data/lib/factbase/terms/casting.rb +2 -2
- data/lib/factbase/terms/debug.rb +2 -2
- data/lib/factbase/terms/defn.rb +2 -2
- data/lib/factbase/terms/logical.rb +3 -3
- data/lib/factbase/terms/math.rb +2 -2
- data/lib/factbase/terms/meta.rb +2 -2
- data/lib/factbase/terms/ordering.rb +2 -2
- data/lib/factbase/terms/strings.rb +2 -2
- data/lib/factbase/terms/system.rb +2 -2
- data/lib/factbase/to_json.rb +2 -2
- data/lib/factbase/to_xml.rb +2 -2
- data/lib/factbase/to_yaml.rb +2 -2
- data/lib/factbase.rb +16 -6
- data/test/factbase/terms/test_aggregates.rb +6 -6
- data/test/factbase/terms/test_aliases.rb +6 -6
- data/test/factbase/terms/test_casting.rb +6 -6
- data/test/factbase/terms/test_debug.rb +53 -0
- data/test/factbase/terms/test_defn.rb +15 -15
- data/test/factbase/terms/test_logical.rb +15 -13
- data/test/factbase/terms/test_math.rb +42 -42
- data/test/factbase/terms/test_meta.rb +87 -0
- data/test/factbase/terms/test_ordering.rb +45 -0
- data/test/factbase/terms/test_strings.rb +8 -8
- data/test/factbase/terms/test_system.rb +6 -6
- data/test/factbase/test_accum.rb +9 -9
- data/test/factbase/test_fact.rb +22 -22
- data/test/factbase/test_flatten.rb +6 -6
- data/test/factbase/test_inv.rb +3 -3
- data/test/factbase/test_looged.rb +13 -13
- data/test/factbase/test_pre.rb +2 -2
- data/test/factbase/test_query.rb +17 -17
- data/test/factbase/test_rules.rb +8 -8
- data/test/factbase/test_syntax.rb +29 -9
- data/test/factbase/test_tee.rb +11 -11
- data/test/factbase/test_term.rb +18 -18
- data/test/factbase/test_to_json.rb +4 -4
- data/test/factbase/test_to_xml.rb +12 -14
- data/test/factbase/test_to_yaml.rb +3 -3
- data/test/test__helper.rb +2 -2
- data/test/test_factbase.rb +198 -18
- metadata +12 -5
data/test/factbase/test_inv.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -28,7 +28,7 @@ require_relative '../../lib/factbase/pre'
|
|
28
28
|
|
29
29
|
# Test.
|
30
30
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
31
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
31
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
32
32
|
# License:: MIT
|
33
33
|
class TestInv < Minitest::Test
|
34
34
|
def test_simple_checking
|
@@ -38,7 +38,7 @@ class TestInv < Minitest::Test
|
|
38
38
|
end
|
39
39
|
f = fb.insert
|
40
40
|
f.a = 42
|
41
|
-
assert_raises do
|
41
|
+
assert_raises(StandardError) do
|
42
42
|
f.b = 'here we should crash'
|
43
43
|
end
|
44
44
|
f.c = 256
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,7 +27,7 @@ require_relative '../../lib/factbase/looged'
|
|
27
27
|
|
28
28
|
# Test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestLooged < Minitest::Test
|
33
33
|
def test_simple_setting
|
@@ -36,7 +36,7 @@ class TestLooged < Minitest::Test
|
|
36
36
|
fb.insert.bar = 3
|
37
37
|
found = 0
|
38
38
|
fb.query('(exists bar)').each do |f|
|
39
|
-
|
39
|
+
assert_predicate(f.bar, :positive?)
|
40
40
|
f.foo = 42
|
41
41
|
assert_equal(42, f.foo)
|
42
42
|
found += 1
|
@@ -62,32 +62,32 @@ class TestLooged < Minitest::Test
|
|
62
62
|
end
|
63
63
|
)
|
64
64
|
assert_equal(1, fb.size)
|
65
|
-
|
65
|
+
assert_includes(log.to_s, 'modified', log)
|
66
66
|
end
|
67
67
|
|
68
68
|
def test_with_txn_rollback
|
69
69
|
log = Loog::Buffer.new
|
70
70
|
fb = Factbase::Looged.new(Factbase.new, log)
|
71
|
-
|
71
|
+
refute(fb.txn { raise Factbase::Rollback })
|
72
72
|
assert_equal(0, fb.size)
|
73
|
-
|
74
|
-
|
73
|
+
assert_includes(log.to_s, 'rolled back', log)
|
74
|
+
refute_includes(log.to_s, 'didn\'t touch', log)
|
75
75
|
end
|
76
76
|
|
77
77
|
def test_with_modifying_txn
|
78
78
|
log = Loog::Buffer.new
|
79
79
|
fb = Factbase::Looged.new(Factbase.new, log)
|
80
80
|
fb.insert.foo = 1
|
81
|
-
|
82
|
-
assert(fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 }
|
83
|
-
|
81
|
+
refute(fb.txn { |fbt| fbt.query('(always)').each.to_a }, log)
|
82
|
+
assert(fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 })
|
83
|
+
assert_includes(log.to_s, 'modified', log)
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_with_empty_txn
|
87
87
|
log = Loog::Buffer.new
|
88
88
|
fb = Factbase::Looged.new(Factbase.new, log)
|
89
|
-
|
90
|
-
|
89
|
+
refute(fb.txn { |fbt| fbt.query('(always)').each.to_a })
|
90
|
+
assert_includes(log.to_s, 'didn\'t touch', log)
|
91
91
|
end
|
92
92
|
|
93
93
|
def test_returns_int
|
@@ -140,7 +140,7 @@ class TestLooged < Minitest::Test
|
|
140
140
|
'Found 1 fact(s) by \'(exists bar)\'',
|
141
141
|
'Deleted 3 fact(s) out of 4 by \'(not (exists bar))\''
|
142
142
|
].each do |s|
|
143
|
-
|
143
|
+
assert_includes(log.to_s, s, "#{log}\n")
|
144
144
|
end
|
145
145
|
end
|
146
146
|
end
|
data/test/factbase/test_pre.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -26,7 +26,7 @@ require_relative '../../lib/factbase/pre'
|
|
26
26
|
|
27
27
|
# Test.
|
28
28
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
30
30
|
# License:: MIT
|
31
31
|
class TestPre < Minitest::Test
|
32
32
|
def test_simple_setting
|
data/test/factbase/test_query.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,13 +27,13 @@ require_relative '../../lib/factbase/query'
|
|
27
27
|
|
28
28
|
# Query test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestQuery < Minitest::Test
|
33
33
|
def test_simple_parsing
|
34
34
|
maps = []
|
35
35
|
maps << { 'foo' => [42] }
|
36
|
-
q = Factbase::Query.new(maps, Mutex.new, '(eq foo 42)')
|
36
|
+
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo 42)')
|
37
37
|
assert_equal(
|
38
38
|
1,
|
39
39
|
q.each do |f|
|
@@ -88,7 +88,7 @@ class TestQuery < Minitest::Test
|
|
88
88
|
"(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
|
89
89
|
'(eq 3 (agg (eq num $num) (count)))' => 1
|
90
90
|
}.each do |q, r|
|
91
|
-
assert_equal(r, Factbase::Query.new(maps, Mutex.new, q).each.to_a.size, q)
|
91
|
+
assert_equal(r, Factbase::Query.new(Factbase.new, maps, Mutex.new, q).each.to_a.size, q)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -96,7 +96,7 @@ class TestQuery < Minitest::Test
|
|
96
96
|
maps = []
|
97
97
|
now = Time.now.utc
|
98
98
|
maps << { 'foo' => [now] }
|
99
|
-
q = Factbase::Query.new(maps, Mutex.new, "(eq foo #{now.iso8601})")
|
99
|
+
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, "(eq foo #{now.iso8601})")
|
100
100
|
assert_equal(1, q.each.to_a.size)
|
101
101
|
end
|
102
102
|
|
@@ -105,7 +105,7 @@ class TestQuery < Minitest::Test
|
|
105
105
|
maps << { 'foo' => [42] }
|
106
106
|
maps << { 'bar' => [4, 5] }
|
107
107
|
maps << { 'bar' => [5] }
|
108
|
-
q = Factbase::Query.new(maps, Mutex.new, '(eq bar 5)')
|
108
|
+
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq bar 5)')
|
109
109
|
assert_equal(2, q.delete!)
|
110
110
|
assert_equal(1, maps.size)
|
111
111
|
end
|
@@ -121,7 +121,7 @@ class TestQuery < Minitest::Test
|
|
121
121
|
'(agg (eq bar $v) (count))' => 1,
|
122
122
|
'(agg (eq z 40) (count))' => 0
|
123
123
|
}.each do |q, expected|
|
124
|
-
result = Factbase::Query.new(maps, Mutex.new, q).one(v: 4)
|
124
|
+
result = Factbase::Query.new(Factbase.new, maps, Mutex.new, q).one(v: 4)
|
125
125
|
if expected.nil?
|
126
126
|
assert_nil(result, "#{q} -> nil")
|
127
127
|
else
|
@@ -135,7 +135,7 @@ class TestQuery < Minitest::Test
|
|
135
135
|
maps << { 'foo' => [42] }
|
136
136
|
maps << { 'bar' => [4, 5] }
|
137
137
|
maps << { 'bar' => [5] }
|
138
|
-
q = Factbase::Query.new(maps, Mutex.new, '(never)')
|
138
|
+
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(never)')
|
139
139
|
assert_equal(0, q.delete!)
|
140
140
|
assert_equal(3, maps.size)
|
141
141
|
end
|
@@ -143,20 +143,20 @@ class TestQuery < Minitest::Test
|
|
143
143
|
def test_to_array
|
144
144
|
maps = []
|
145
145
|
maps << { 'foo' => [42] }
|
146
|
-
assert_equal(1, Factbase::Query.new(maps, Mutex.new, '(eq foo 42)').each.to_a.size)
|
146
|
+
assert_equal(1, Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo 42)').each.to_a.size)
|
147
147
|
end
|
148
148
|
|
149
149
|
def test_returns_int
|
150
150
|
maps = []
|
151
151
|
maps << { 'foo' => [1] }
|
152
|
-
q = Factbase::Query.new(maps, Mutex.new, '(eq foo 1)')
|
152
|
+
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo 1)')
|
153
153
|
assert_equal(1, q.each(&:to_s))
|
154
154
|
end
|
155
155
|
|
156
156
|
def test_with_aliases
|
157
157
|
maps = []
|
158
158
|
maps << { 'foo' => [42] }
|
159
|
-
assert_equal(45, Factbase::Query.new(maps, Mutex.new, '(as bar (plus foo 3))').each.to_a[0].bar)
|
159
|
+
assert_equal(45, Factbase::Query.new(Factbase.new, maps, Mutex.new, '(as bar (plus foo 3))').each.to_a[0].bar)
|
160
160
|
assert_equal(1, maps[0].size)
|
161
161
|
end
|
162
162
|
|
@@ -165,24 +165,24 @@ class TestQuery < Minitest::Test
|
|
165
165
|
maps << { 'foo' => [42] }
|
166
166
|
maps << { 'foo' => [17] }
|
167
167
|
found = 0
|
168
|
-
Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: [42]) do
|
168
|
+
Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo $bar)').each(bar: [42]) do
|
169
169
|
found += 1
|
170
170
|
end
|
171
171
|
assert_equal(1, found)
|
172
|
-
assert_equal(1, Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: 42).to_a.size)
|
173
|
-
assert_equal(0, Factbase::Query.new(maps, Mutex.new, '(eq foo $bar)').each(bar: 555).to_a.size)
|
172
|
+
assert_equal(1, Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo $bar)').each(bar: 42).to_a.size)
|
173
|
+
assert_equal(0, Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo $bar)').each(bar: 555).to_a.size)
|
174
174
|
end
|
175
175
|
|
176
176
|
def test_with_nil_alias
|
177
177
|
maps = []
|
178
178
|
maps << { 'foo' => [42] }
|
179
|
-
|
179
|
+
assert_nil(Factbase::Query.new(Factbase.new, maps, Mutex.new, '(as bar (plus xxx 3))').each.to_a[0]['bar'])
|
180
180
|
end
|
181
181
|
|
182
182
|
def test_get_all_properties
|
183
183
|
maps = []
|
184
184
|
maps << { 'foo' => [42] }
|
185
|
-
f = Factbase::Query.new(maps, Mutex.new, '(always)').each.to_a[0]
|
186
|
-
|
185
|
+
f = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(always)').each.to_a[0]
|
186
|
+
assert_includes(f.all_properties, 'foo')
|
187
187
|
end
|
188
188
|
end
|
data/test/factbase/test_rules.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,7 +27,7 @@ require_relative '../../lib/factbase/pre'
|
|
27
27
|
|
28
28
|
# Test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestRules < Minitest::Test
|
33
33
|
def test_simple_checking
|
@@ -38,8 +38,8 @@ class TestRules < Minitest::Test
|
|
38
38
|
f1 = fb.insert
|
39
39
|
f1.second = 2
|
40
40
|
f1.first = 1
|
41
|
-
|
42
|
-
|
41
|
+
f2 = fb.insert
|
42
|
+
assert_raises(StandardError) do
|
43
43
|
f2.first = 1
|
44
44
|
end
|
45
45
|
end
|
@@ -60,7 +60,7 @@ class TestRules < Minitest::Test
|
|
60
60
|
f = fb.insert
|
61
61
|
f.foo = 42
|
62
62
|
s = f.to_s
|
63
|
-
|
63
|
+
assert_predicate(s.length, :positive?, s)
|
64
64
|
assert_equal('[ foo: [42] ]', s)
|
65
65
|
end
|
66
66
|
|
@@ -74,7 +74,7 @@ class TestRules < Minitest::Test
|
|
74
74
|
def test_check_only_when_txn_is_closed
|
75
75
|
fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
|
76
76
|
ok = false
|
77
|
-
assert_raises do
|
77
|
+
assert_raises(StandardError) do
|
78
78
|
fb.txn do |fbt|
|
79
79
|
f = fbt.insert
|
80
80
|
f.a = 1
|
@@ -87,7 +87,7 @@ class TestRules < Minitest::Test
|
|
87
87
|
|
88
88
|
def test_rollback_on_violation
|
89
89
|
fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
|
90
|
-
assert_raises do
|
90
|
+
assert_raises(StandardError) do
|
91
91
|
fb.txn do |fbt|
|
92
92
|
f = fbt.insert
|
93
93
|
f.a = 1
|
@@ -104,7 +104,7 @@ class TestRules < Minitest::Test
|
|
104
104
|
f.hello = 42
|
105
105
|
end
|
106
106
|
ok = false
|
107
|
-
assert_raises do
|
107
|
+
assert_raises(StandardError) do
|
108
108
|
fb.txn do |fbt|
|
109
109
|
f = fbt.insert
|
110
110
|
f.a = 1
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -25,7 +25,7 @@ require_relative '../../lib/factbase/syntax'
|
|
25
25
|
|
26
26
|
# Syntax test.
|
27
27
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
28
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
29
29
|
# License:: MIT
|
30
30
|
class TestSyntax < Minitest::Test
|
31
31
|
def test_parses_string_right
|
@@ -35,7 +35,27 @@ class TestSyntax < Minitest::Test
|
|
35
35
|
"(foo 'one two three ')",
|
36
36
|
"(foo 'one two three ' 'tail tail')"
|
37
37
|
].each do |q|
|
38
|
-
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
38
|
+
assert_equal(q, Factbase::Syntax.new(Factbase.new, q).to_term.to_s, q)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_makes_abstract_terms
|
43
|
+
{
|
44
|
+
'(foo $bar)' => true,
|
45
|
+
'(foo (bar (a (b c (f $bar)))))' => true,
|
46
|
+
'(foo (bar (a (b c (f bar)))))' => false
|
47
|
+
}.each do |q, a|
|
48
|
+
assert_equal(a, Factbase::Syntax.new(Factbase.new, q).to_term.abstract?)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_makes_static_terms
|
53
|
+
{
|
54
|
+
'(foo bar)' => false,
|
55
|
+
'(foo "bar")' => true,
|
56
|
+
'(agg (always) (max id))' => true
|
57
|
+
}.each do |q, a|
|
58
|
+
assert_equal(a, Factbase::Syntax.new(Factbase.new, q).to_term.static?)
|
39
59
|
end
|
40
60
|
end
|
41
61
|
|
@@ -50,7 +70,7 @@ class TestSyntax < Minitest::Test
|
|
50
70
|
"(foo 'Hello,\n\nworld!\r\t\n')\n",
|
51
71
|
"(or ( a 4) (b 5) (always) (and (always) (c 5) \t\t(r 7 w8s w8is 'Foo')))"
|
52
72
|
].each do |q|
|
53
|
-
|
73
|
+
refute_nil(Factbase::Syntax.new(Factbase.new, q).to_term)
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
@@ -70,7 +90,7 @@ class TestSyntax < Minitest::Test
|
|
70
90
|
'(eq t 3.0e+21)',
|
71
91
|
"(foo (x (f (t (y 42 'Hey you'))) (never) (r 3)) y z)"
|
72
92
|
].each do |q|
|
73
|
-
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
93
|
+
assert_equal(q, Factbase::Syntax.new(Factbase.new, q).to_term.to_s, q)
|
74
94
|
end
|
75
95
|
end
|
76
96
|
|
@@ -85,7 +105,7 @@ class TestSyntax < Minitest::Test
|
|
85
105
|
'(or (eq bar 888) (eq z 1))' => true,
|
86
106
|
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
87
107
|
}.each do |k, v|
|
88
|
-
assert_equal(v, Factbase::Syntax.new(k).to_term.evaluate(m, []), k)
|
108
|
+
assert_equal(v, Factbase::Syntax.new(Factbase.new, k).to_term.evaluate(m, []), k)
|
89
109
|
end
|
90
110
|
end
|
91
111
|
|
@@ -109,9 +129,9 @@ class TestSyntax < Minitest::Test
|
|
109
129
|
'"'
|
110
130
|
].each do |q|
|
111
131
|
msg = assert_raises(q) do
|
112
|
-
Factbase::Syntax.new(q).to_term
|
132
|
+
Factbase::Syntax.new(Factbase.new, q).to_term
|
113
133
|
end.message
|
114
|
-
|
134
|
+
assert_includes(msg, q, msg)
|
115
135
|
end
|
116
136
|
end
|
117
137
|
|
@@ -121,7 +141,7 @@ class TestSyntax < Minitest::Test
|
|
121
141
|
'(and (foo) (foo))' => '(foo)',
|
122
142
|
'(and (foo) (or (and (eq a 1))) (eq a 1) (foo))' => '(and (foo) (eq a 1))'
|
123
143
|
}.each do |s, t|
|
124
|
-
assert_equal(t, Factbase::Syntax.new(s).to_term.to_s)
|
144
|
+
assert_equal(t, Factbase::Syntax.new(Factbase.new, s).to_term.to_s)
|
125
145
|
end
|
126
146
|
end
|
127
147
|
end
|
data/test/factbase/test_tee.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,13 +27,13 @@ require_relative '../../lib/factbase/fact'
|
|
27
27
|
|
28
28
|
# Tee test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestTee < Minitest::Test
|
33
33
|
def test_two_facts
|
34
|
-
prim = Factbase::Fact.new(Mutex.new, {})
|
34
|
+
prim = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
35
35
|
prim.foo = 42
|
36
|
-
upper = Factbase::Fact.new(Mutex.new, {})
|
36
|
+
upper = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
37
37
|
upper.bar = 13
|
38
38
|
t = Factbase::Tee.new(prim, upper)
|
39
39
|
assert_equal(42, t.foo)
|
@@ -41,18 +41,18 @@ class TestTee < Minitest::Test
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_all_properties
|
44
|
-
prim = Factbase::Fact.new(Mutex.new, {})
|
44
|
+
prim = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
45
45
|
prim.foo = 42
|
46
|
-
upper = Factbase::Fact.new(Mutex.new, {})
|
46
|
+
upper = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
47
47
|
upper.bar = 13
|
48
48
|
t = Factbase::Tee.new(prim, upper)
|
49
|
-
|
50
|
-
|
49
|
+
assert_includes(t.all_properties, 'foo')
|
50
|
+
assert_includes(t.all_properties, 'bar')
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_recursively
|
54
54
|
map = {}
|
55
|
-
prim = Factbase::Fact.new(Mutex.new, map)
|
55
|
+
prim = Factbase::Fact.new(Factbase.new, Mutex.new, map)
|
56
56
|
prim.foo = 42
|
57
57
|
t = Factbase::Tee.new(nil, { 'bar' => 7 })
|
58
58
|
assert_equal(7, t['$bar'])
|
@@ -61,9 +61,9 @@ class TestTee < Minitest::Test
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_prints_to_string
|
64
|
-
prim = Factbase::Fact.new(Mutex.new, {})
|
64
|
+
prim = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
65
65
|
prim.foo = 42
|
66
|
-
upper = Factbase::Fact.new(Mutex.new, {})
|
66
|
+
upper = Factbase::Fact.new(Factbase.new, Mutex.new, {})
|
67
67
|
upper.bar = 13
|
68
68
|
t = Factbase::Tee.new(prim, upper)
|
69
69
|
assert_equal('[ foo: [42] ]', t.to_s)
|
data/test/factbase/test_term.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -25,34 +25,34 @@ require_relative '../../lib/factbase/term'
|
|
25
25
|
|
26
26
|
# Term test.
|
27
27
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
28
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
29
29
|
# License:: MIT
|
30
30
|
class TestTerm < Minitest::Test
|
31
31
|
def test_false_matching
|
32
|
-
t = Factbase::Term.new(:never, [])
|
33
|
-
|
32
|
+
t = Factbase::Term.new(Factbase.new, :never, [])
|
33
|
+
refute(t.evaluate(fact('foo' => [100]), []))
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_size_matching
|
37
|
-
t = Factbase::Term.new(:size, [:foo])
|
37
|
+
t = Factbase::Term.new(Factbase.new, :size, [:foo])
|
38
38
|
assert_equal(3, t.evaluate(fact('foo' => [42, 12, -90]), []))
|
39
39
|
assert_equal(0, t.evaluate(fact('bar' => 100), []))
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_exists_matching
|
43
|
-
t = Factbase::Term.new(:exists, [:foo])
|
43
|
+
t = Factbase::Term.new(Factbase.new, :exists, [:foo])
|
44
44
|
assert(t.evaluate(fact('foo' => [42, 12, -90]), []))
|
45
|
-
|
45
|
+
refute(t.evaluate(fact('bar' => 100), []))
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_absent_matching
|
49
|
-
t = Factbase::Term.new(:absent, [:foo])
|
49
|
+
t = Factbase::Term.new(Factbase.new, :absent, [:foo])
|
50
50
|
assert(t.evaluate(fact('z' => [42, 12, -90]), []))
|
51
|
-
|
51
|
+
refute(t.evaluate(fact('foo' => 100), []))
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_type_matching
|
55
|
-
t = Factbase::Term.new(:type, [:foo])
|
55
|
+
t = Factbase::Term.new(Factbase.new, :type, [:foo])
|
56
56
|
assert_equal('Integer', t.evaluate(fact('foo' => 42), []))
|
57
57
|
assert_equal('Integer', t.evaluate(fact('foo' => [42]), []))
|
58
58
|
assert_equal('Array', t.evaluate(fact('foo' => [1, 2, 3]), []))
|
@@ -64,30 +64,30 @@ class TestTerm < Minitest::Test
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_past
|
67
|
-
t = Factbase::Term.new(:prev, [:foo])
|
67
|
+
t = Factbase::Term.new(Factbase.new, :prev, [:foo])
|
68
68
|
assert_nil(t.evaluate(fact('foo' => 4), []))
|
69
69
|
assert_equal([4], t.evaluate(fact('foo' => 5), []))
|
70
70
|
end
|
71
71
|
|
72
72
|
def test_at
|
73
|
-
t = Factbase::Term.new(:at, [1, :foo])
|
73
|
+
t = Factbase::Term.new(Factbase.new, :at, [1, :foo])
|
74
74
|
assert_nil(t.evaluate(fact('foo' => 4), []))
|
75
75
|
assert_equal(5, t.evaluate(fact('foo' => [4, 5]), []))
|
76
76
|
end
|
77
77
|
|
78
78
|
def test_report_missing_term
|
79
|
-
t = Factbase::Term.new(:something, [])
|
80
|
-
msg = assert_raises do
|
79
|
+
t = Factbase::Term.new(Factbase.new, :something, [])
|
80
|
+
msg = assert_raises(StandardError) do
|
81
81
|
t.evaluate(fact, [])
|
82
82
|
end.message
|
83
|
-
|
83
|
+
assert_includes(msg, 'not defined at (something)', msg)
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_report_other_error
|
87
|
-
t = Factbase::Term.new(:at, [])
|
88
|
-
msg = assert_raises do
|
87
|
+
t = Factbase::Term.new(Factbase.new, :at, [])
|
88
|
+
msg = assert_raises(StandardError) do
|
89
89
|
t.evaluate(fact, [])
|
90
90
|
end.message
|
91
|
-
|
91
|
+
assert_includes(msg, 'at (at)', msg)
|
92
92
|
end
|
93
93
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,7 +27,7 @@ require_relative '../../lib/factbase/to_json'
|
|
27
27
|
|
28
28
|
# Test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestToJSON < Minitest::Test
|
33
33
|
def test_simple_rendering
|
@@ -37,7 +37,7 @@ class TestToJSON < Minitest::Test
|
|
37
37
|
f.foo = 256
|
38
38
|
to = Factbase::ToJSON.new(fb)
|
39
39
|
json = JSON.parse(to.json)
|
40
|
-
|
40
|
+
assert_equal(256, json[0]['foo'][1])
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_sort_keys
|
@@ -47,6 +47,6 @@ class TestToJSON < Minitest::Test
|
|
47
47
|
f.b = 1
|
48
48
|
f.a = 256
|
49
49
|
json = Factbase::ToJSON.new(fb).json
|
50
|
-
|
50
|
+
assert_includes(json, '{"a":256,"b":1,"c":42}', json)
|
51
51
|
end
|
52
52
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Yegor Bugayenko
|
3
|
+
# Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the 'Software'), to deal
|
@@ -27,7 +27,7 @@ require_relative '../../lib/factbase/to_xml'
|
|
27
27
|
|
28
28
|
# Test.
|
29
29
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
-
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
31
31
|
# License:: MIT
|
32
32
|
class TestToXML < Minitest::Test
|
33
33
|
def test_simple_rendering
|
@@ -35,11 +35,9 @@ class TestToXML < Minitest::Test
|
|
35
35
|
fb.insert.t = Time.now
|
36
36
|
to = Factbase::ToXML.new(fb)
|
37
37
|
xml = Nokogiri::XML.parse(to.xml)
|
38
|
-
|
39
|
-
|
40
|
-
xml.xpath('/fb/f/t/text()').text
|
41
|
-
/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$/
|
42
|
-
)
|
38
|
+
refute_empty(xml.xpath('/fb/f[t]'))
|
39
|
+
assert_match(
|
40
|
+
/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$/, xml.xpath('/fb/f/t/text()').text
|
43
41
|
)
|
44
42
|
end
|
45
43
|
|
@@ -48,7 +46,7 @@ class TestToXML < Minitest::Test
|
|
48
46
|
fb.insert.t = "\uffff < > & ' \""
|
49
47
|
to = Factbase::ToXML.new(fb)
|
50
48
|
xml = Nokogiri::XML.parse(to.xml)
|
51
|
-
|
49
|
+
refute_empty(xml.xpath('/fb/f[t]'))
|
52
50
|
end
|
53
51
|
|
54
52
|
def test_meta_data_presence
|
@@ -56,8 +54,8 @@ class TestToXML < Minitest::Test
|
|
56
54
|
fb.insert.x = 42
|
57
55
|
to = Factbase::ToXML.new(fb)
|
58
56
|
xml = Nokogiri::XML.parse(to.xml)
|
59
|
-
|
60
|
-
|
57
|
+
refute_empty(xml.xpath('/fb[@version]'))
|
58
|
+
refute_empty(xml.xpath('/fb[@size]'))
|
61
59
|
end
|
62
60
|
|
63
61
|
def test_to_xml_with_short_names
|
@@ -67,8 +65,8 @@ class TestToXML < Minitest::Test
|
|
67
65
|
f.f = 2
|
68
66
|
to = Factbase::ToXML.new(fb)
|
69
67
|
xml = Nokogiri::XML.parse(to.xml)
|
70
|
-
|
71
|
-
|
68
|
+
refute_empty(xml.xpath('/fb/f/type'))
|
69
|
+
refute_empty(xml.xpath('/fb/f/f'))
|
72
70
|
end
|
73
71
|
|
74
72
|
def test_show_types_as_attributes
|
@@ -89,7 +87,7 @@ class TestToXML < Minitest::Test
|
|
89
87
|
'/fb/f/d[@t="T"]',
|
90
88
|
'/fb/f/e/v[@t="S"]',
|
91
89
|
'/fb/f/e/v[@t="I"]'
|
92
|
-
].each { |x|
|
90
|
+
].each { |x| refute_empty(xml.xpath(x), out) }
|
93
91
|
end
|
94
92
|
|
95
93
|
def test_sorts_keys
|
@@ -102,7 +100,7 @@ class TestToXML < Minitest::Test
|
|
102
100
|
to = Factbase::ToXML.new(fb)
|
103
101
|
xml = Nokogiri::XML.parse(to.xml)
|
104
102
|
%w[a c t x].each_with_index do |e, i|
|
105
|
-
|
103
|
+
refute_empty(xml.xpath("/fb/f/#{e}[count(preceding-sibling::*) = #{i}]"), e)
|
106
104
|
end
|
107
105
|
end
|
108
106
|
end
|