factbase 0.0.1 → 0.0.3
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/.github/workflows/codecov.yml +0 -2
- data/Gemfile +1 -0
- data/lib/factbase/syntax.rb +8 -3
- data/lib/factbase/term.rb +13 -1
- data/lib/factbase.rb +8 -5
- data/test/factbase/test_syntax.rb +14 -3
- data/test/factbase/test_term.rb +12 -0
- data/test/test__helper.rb +3 -1
- data/test/test_factbase.rb +10 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 270354d428517846946f93bec8e2e5b4c134306ca2c2136d5d99eae6add60b65
|
4
|
+
data.tar.gz: 170078b593a186785869f33fdb41e5152d8d34d5b7a47eb65a9b5756939592a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afecc5884796f2e67c8f95bab613c6b82f92291c424adbea1c883a19c7c3816475ea14897ea4079434da71e1a382ee40aa4e7e62347702116f999ea40de6d24a
|
7
|
+
data.tar.gz: d14d86d5ea751d540dd3ed5d52b3aba747f70b6db9ec295717abdcb30af2d57793b2d2b0cc2607eb4e90d509a53f0a6d336865afddcbce658ed2fd7e9a3f07b0
|
data/Gemfile
CHANGED
@@ -29,4 +29,5 @@ gem 'rspec-rails', '6.1.2', require: false
|
|
29
29
|
gem 'rubocop', '1.63.5', require: false
|
30
30
|
gem 'rubocop-rspec', '2.29.2', require: false
|
31
31
|
gem 'simplecov', '0.22.0', require: false
|
32
|
+
gem 'simplecov-cobertura', '2.1.0', require: false
|
32
33
|
gem 'yard', '0.9.36', require: false
|
data/lib/factbase/syntax.rb
CHANGED
@@ -20,7 +20,6 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
|
-
require 'cgi'
|
24
23
|
require_relative 'fact'
|
25
24
|
require_relative 'term'
|
26
25
|
|
@@ -70,7 +69,13 @@ class Factbase::Syntax
|
|
70
69
|
def to_tokens
|
71
70
|
list = []
|
72
71
|
acc = ''
|
72
|
+
string = false
|
73
73
|
@query.to_s.chars.each do |c|
|
74
|
+
string = !string if ['\'', '"'].include?(c)
|
75
|
+
if string
|
76
|
+
acc += c
|
77
|
+
next
|
78
|
+
end
|
74
79
|
if !acc.empty? && [' ', ')'].include?(c)
|
75
80
|
list << acc
|
76
81
|
acc = ''
|
@@ -89,8 +94,8 @@ class Factbase::Syntax
|
|
89
94
|
list.map do |t|
|
90
95
|
if t.is_a?(Symbol)
|
91
96
|
t
|
92
|
-
elsif t.start_with?('\'')
|
93
|
-
|
97
|
+
elsif t.start_with?('\'', '"')
|
98
|
+
t[1..-2]
|
94
99
|
elsif t.match?(/^[0-9]+$/)
|
95
100
|
t.to_i
|
96
101
|
else
|
data/lib/factbase/term.rb
CHANGED
@@ -55,10 +55,12 @@ class Factbase::Term
|
|
55
55
|
private
|
56
56
|
|
57
57
|
def nil(_map)
|
58
|
+
assert_args(0)
|
58
59
|
true
|
59
60
|
end
|
60
61
|
|
61
62
|
def not(map)
|
63
|
+
assert_args(1)
|
62
64
|
!@operands[0].matches?(map)
|
63
65
|
end
|
64
66
|
|
@@ -77,23 +79,27 @@ class Factbase::Term
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def exists(map)
|
82
|
+
assert_args(1)
|
80
83
|
k = @operands[0].to_s
|
81
84
|
!map[k].nil?
|
82
85
|
end
|
83
86
|
|
84
87
|
def absent(map)
|
88
|
+
assert_args(1)
|
85
89
|
k = @operands[0].to_s
|
86
90
|
map[k].nil?
|
87
91
|
end
|
88
92
|
|
89
93
|
def eq(map)
|
94
|
+
assert_args(2)
|
90
95
|
k = @operands[0].to_s
|
91
96
|
v = map[k]
|
92
97
|
return false if v.nil?
|
93
|
-
v
|
98
|
+
v.include?(@operands[1])
|
94
99
|
end
|
95
100
|
|
96
101
|
def lt(map)
|
102
|
+
assert_args(2)
|
97
103
|
k = @operands[0].to_s
|
98
104
|
v = map[k]
|
99
105
|
return false if v.nil?
|
@@ -101,9 +107,15 @@ class Factbase::Term
|
|
101
107
|
end
|
102
108
|
|
103
109
|
def gt(map)
|
110
|
+
assert_args(2)
|
104
111
|
k = @operands[0].to_s
|
105
112
|
v = map[k]
|
106
113
|
return false if v.nil?
|
107
114
|
v[0] > @operands[1]
|
108
115
|
end
|
116
|
+
|
117
|
+
def assert_args(num)
|
118
|
+
raise "Too many operands for '#{@op}'" if @operands.size > num
|
119
|
+
raise "Too few operands for '#{@op}'" if @operands.size < num
|
120
|
+
end
|
109
121
|
end
|
data/lib/factbase.rb
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
# License:: MIT
|
27
27
|
class Factbase
|
28
28
|
# Current version of the library and of this class.
|
29
|
-
VERSION = '0.0.
|
29
|
+
VERSION = '0.0.3'
|
30
30
|
|
31
31
|
# Constructor.
|
32
32
|
def initialize
|
@@ -48,15 +48,14 @@ class Factbase
|
|
48
48
|
|
49
49
|
# Create a query capable of iterating.
|
50
50
|
#
|
51
|
-
# There is a Lisp-like syntax, for example
|
52
|
-
# must be HTML-escaped):
|
51
|
+
# There is a Lisp-like syntax, for example:
|
53
52
|
#
|
54
|
-
# (eq title 'Object
|
53
|
+
# (eq title 'Object Thinking')
|
55
54
|
# (gt time '2024-03-23T03:21:43')
|
56
55
|
# (gt cost 42)
|
57
56
|
# (exists seenBy)
|
58
57
|
# (and
|
59
|
-
# (eq foo
|
58
|
+
# (eq foo 42)
|
60
59
|
# (or
|
61
60
|
# (gt bar 200)
|
62
61
|
# (absent zzz)))
|
@@ -77,6 +76,10 @@ class Factbase
|
|
77
76
|
@maps += Marshal.load(bytes)
|
78
77
|
# rubocop:enable Security/MarshalLoad
|
79
78
|
end
|
79
|
+
|
80
|
+
def to_json(_ = nil)
|
81
|
+
@maps.to_json
|
82
|
+
end
|
80
83
|
end
|
81
84
|
|
82
85
|
require_relative 'factbase/fact'
|
@@ -29,12 +29,23 @@ require_relative '../../lib/factbase/syntax'
|
|
29
29
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
30
|
# License:: MIT
|
31
31
|
class TestSyntax < Minitest::Test
|
32
|
+
def test_parses_string_right
|
33
|
+
[
|
34
|
+
"(foo 'abc')",
|
35
|
+
"(foo 'one two')",
|
36
|
+
"(foo 'one two three ')",
|
37
|
+
"(foo 'one two three ' 'tail tail')"
|
38
|
+
].each do |q|
|
39
|
+
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
32
43
|
def test_simple_parsing
|
33
44
|
[
|
34
45
|
'()',
|
35
46
|
'(foo)',
|
36
47
|
'(foo (bar) (zz 77) )',
|
37
|
-
"(eq foo 'Hello
|
48
|
+
"(eq foo 'Hello, world!')",
|
38
49
|
"(or ( a 4) (b 5) () (and () (c 5) (r 7 8s 8is 'Foo')))"
|
39
50
|
].each do |q|
|
40
51
|
Factbase::Syntax.new(q).to_term
|
@@ -49,7 +60,7 @@ class TestSyntax < Minitest::Test
|
|
49
60
|
'(foo x y z)',
|
50
61
|
"(foo x y z t f 42 'Hi!' 33)",
|
51
62
|
'(foo (x) y z)',
|
52
|
-
"(foo (x (f (t (y 42 'Hey'))) (f) (r 3)) y z)"
|
63
|
+
"(foo (x (f (t (y 42 'Hey you'))) (f) (r 3)) y z)"
|
53
64
|
].each do |q|
|
54
65
|
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s)
|
55
66
|
end
|
@@ -64,7 +75,7 @@ class TestSyntax < Minitest::Test
|
|
64
75
|
{
|
65
76
|
'(eq z 1)' => true,
|
66
77
|
'(or (eq bar 888) (eq z 1))' => true,
|
67
|
-
"(or (gt bar 100) (eq foo 'Hello
|
78
|
+
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
68
79
|
}.each do |k, v|
|
69
80
|
assert_equal(v, Factbase::Syntax.new(k).to_term.matches?(m), k)
|
70
81
|
end
|
data/test/factbase/test_term.rb
CHANGED
@@ -36,6 +36,12 @@ class TestTerm < Minitest::Test
|
|
36
36
|
assert(!t.matches?({ 'bar' => ['Hello!'] }))
|
37
37
|
end
|
38
38
|
|
39
|
+
def test_eq_matching
|
40
|
+
t = Factbase::Term.new(:eq, ['foo', 42])
|
41
|
+
assert(t.matches?({ 'foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf'] }))
|
42
|
+
assert(!t.matches?({ 'foo' => [100] }))
|
43
|
+
end
|
44
|
+
|
39
45
|
def test_lt_matching
|
40
46
|
t = Factbase::Term.new(:lt, ['foo', 42])
|
41
47
|
assert(t.matches?({ 'foo' => [10] }))
|
@@ -53,6 +59,12 @@ class TestTerm < Minitest::Test
|
|
53
59
|
assert(!t.matches?({ 'foo' => [100] }))
|
54
60
|
end
|
55
61
|
|
62
|
+
def test_not_exists_matching
|
63
|
+
t = Factbase::Term.new(:not, [Factbase::Term.new(:eq, ['foo', 100])])
|
64
|
+
assert(t.matches?({ 'foo' => [42, 12, -90] }))
|
65
|
+
assert(!t.matches?({ 'foo' => [100] }))
|
66
|
+
end
|
67
|
+
|
56
68
|
def test_or_matching
|
57
69
|
t = Factbase::Term.new(
|
58
70
|
:or,
|
data/test/test__helper.rb
CHANGED
data/test/test_factbase.rb
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
# SOFTWARE.
|
23
23
|
|
24
24
|
require 'minitest/autorun'
|
25
|
+
require 'json'
|
25
26
|
require_relative '../lib/factbase'
|
26
27
|
|
27
28
|
# Factbase main module test.
|
@@ -53,4 +54,13 @@ class TestFactbase < Minitest::Test
|
|
53
54
|
end
|
54
55
|
assert_equal(1, f2.query('(eq foo 42)').to_a.count)
|
55
56
|
end
|
57
|
+
|
58
|
+
def test_to_json
|
59
|
+
fb = Factbase.new
|
60
|
+
f = fb.insert
|
61
|
+
f.foo = 42
|
62
|
+
f.foo = 256
|
63
|
+
json = JSON.parse(fb.to_json)
|
64
|
+
assert(42, json[0]['foo'][1])
|
65
|
+
end
|
56
66
|
end
|