factbase 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/factbase/syntax.rb +22 -4
- data/lib/factbase/term.rb +1 -1
- data/lib/factbase.rb +4 -5
- data/test/factbase/test_syntax.rb +36 -3
- 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: dc21a8440801909645bc06e200ca9b238ab899f6ecd5ef422eec4d082fdbbfaf
|
4
|
+
data.tar.gz: 05fb34e5249ec11dd0cddcfe74888d89a3343c44afada52926f720c102804321
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c72854f13afe4af7be6a232c12c60025cd9d286559940e96a0ebd9decf748e13e8db4993bffe64f8416d3c03cd20f9a491c06c55434bdba2f53c32edd7d7410
|
7
|
+
data.tar.gz: e44f1b7c3c83f207ead55e5aed42844eb98dd53ee6ef5241be0e0931cbe7670dc0c6103c002ce6a4a7cbc8818784de6c7f600a7102d91a20a2dcc732a62fc5d7
|
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
|
|
@@ -38,7 +37,9 @@ class Factbase::Syntax
|
|
38
37
|
def to_term
|
39
38
|
@tokens ||= to_tokens
|
40
39
|
@ast ||= to_ast(@tokens, 0)
|
41
|
-
@ast[0]
|
40
|
+
term = @ast[0]
|
41
|
+
raise 'No terms found' if term.nil?
|
42
|
+
term
|
42
43
|
end
|
43
44
|
|
44
45
|
private
|
@@ -51,6 +52,7 @@ class Factbase::Syntax
|
|
51
52
|
# is the term/literal and the second one is the position where the
|
52
53
|
# scanning should continue.
|
53
54
|
def to_ast(tokens, at)
|
55
|
+
raise "Closing too soon at ##{at}" if tokens[at] == :close
|
54
56
|
return [tokens[at], at + 1] unless tokens[at] == :open
|
55
57
|
at += 1
|
56
58
|
op = tokens[at]
|
@@ -58,8 +60,11 @@ class Factbase::Syntax
|
|
58
60
|
operands = []
|
59
61
|
at += 1
|
60
62
|
loop do
|
63
|
+
raise "End of token stream at ##{at}" if tokens[at].nil?
|
61
64
|
break if tokens[at] == :close
|
62
65
|
(operand, at1) = to_ast(tokens, at)
|
66
|
+
raise "Stuck at position ##{at}" if at == at1
|
67
|
+
raise "Jump back at position ##{at}" if at1 < at
|
63
68
|
at = at1
|
64
69
|
operands << operand
|
65
70
|
break if tokens[at] == :close
|
@@ -70,7 +75,19 @@ class Factbase::Syntax
|
|
70
75
|
def to_tokens
|
71
76
|
list = []
|
72
77
|
acc = ''
|
78
|
+
string = false
|
73
79
|
@query.to_s.chars.each do |c|
|
80
|
+
if ['\'', '"'].include?(c)
|
81
|
+
if string && acc[acc.length - 1] == '\\'
|
82
|
+
acc = acc[0..-2]
|
83
|
+
else
|
84
|
+
string = !string
|
85
|
+
end
|
86
|
+
end
|
87
|
+
if string
|
88
|
+
acc += c
|
89
|
+
next
|
90
|
+
end
|
74
91
|
if !acc.empty? && [' ', ')'].include?(c)
|
75
92
|
list << acc
|
76
93
|
acc = ''
|
@@ -86,11 +103,12 @@ class Factbase::Syntax
|
|
86
103
|
acc += c
|
87
104
|
end
|
88
105
|
end
|
106
|
+
raise 'String not closed' if string
|
89
107
|
list.map do |t|
|
90
108
|
if t.is_a?(Symbol)
|
91
109
|
t
|
92
|
-
elsif t.start_with?('\'')
|
93
|
-
|
110
|
+
elsif t.start_with?('\'', '"')
|
111
|
+
t[1..-2]
|
94
112
|
elsif t.match?(/^[0-9]+$/)
|
95
113
|
t.to_i
|
96
114
|
else
|
data/lib/factbase/term.rb
CHANGED
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.4'
|
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)))
|
@@ -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
|
@@ -46,10 +57,12 @@ class TestSyntax < Minitest::Test
|
|
46
57
|
'(foo)',
|
47
58
|
'(foo 7)',
|
48
59
|
"(foo 7 'Dude')",
|
60
|
+
"(r 'Dude\\'s Friend')",
|
61
|
+
"(r 'I\\'m \\\"good\\\"')",
|
49
62
|
'(foo x y z)',
|
50
63
|
"(foo x y z t f 42 'Hi!' 33)",
|
51
64
|
'(foo (x) y z)',
|
52
|
-
"(foo (x (f (t (y 42 'Hey'))) (f) (r 3)) y z)"
|
65
|
+
"(foo (x (f (t (y 42 'Hey you'))) (f) (r 3)) y z)"
|
53
66
|
].each do |q|
|
54
67
|
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s)
|
55
68
|
end
|
@@ -64,9 +77,29 @@ class TestSyntax < Minitest::Test
|
|
64
77
|
{
|
65
78
|
'(eq z 1)' => true,
|
66
79
|
'(or (eq bar 888) (eq z 1))' => true,
|
67
|
-
"(or (gt bar 100) (eq foo 'Hello
|
80
|
+
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
68
81
|
}.each do |k, v|
|
69
82
|
assert_equal(v, Factbase::Syntax.new(k).to_term.matches?(m), k)
|
70
83
|
end
|
71
84
|
end
|
85
|
+
|
86
|
+
def test_broken_syntax
|
87
|
+
[
|
88
|
+
'',
|
89
|
+
'(foo',
|
90
|
+
'"hello, world!',
|
91
|
+
'(foo 7',
|
92
|
+
"(foo 7 'Dude'",
|
93
|
+
'(foo x y z (',
|
94
|
+
'(foo x y (z t (f 42 ',
|
95
|
+
')foo ) y z)',
|
96
|
+
")y 42 'Hey you)",
|
97
|
+
')',
|
98
|
+
'"'
|
99
|
+
].each do |q|
|
100
|
+
assert_raises do
|
101
|
+
Factbase::Syntax.new(q).to_term
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
72
105
|
end
|