factbase 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.0pdd.yml +25 -0
- data/.gitattributes +7 -0
- data/.github/workflows/actionlint.yml +41 -0
- data/.github/workflows/codecov.yml +40 -0
- data/.github/workflows/markdown-lint.yml +38 -0
- data/.github/workflows/pdd.yml +15 -0
- data/.github/workflows/rake.yml +24 -0
- data/.github/workflows/xcop.yml +11 -0
- data/.github/workflows/yamllint.yml +36 -0
- data/.gitignore +9 -0
- data/.pdd +7 -0
- data/.rubocop.yml +47 -0
- data/.rultor.yml +42 -0
- data/.simplecov +41 -0
- data/.yamllint.yml +24 -0
- data/Gemfile +32 -0
- data/LICENSE.txt +21 -0
- data/README.md +55 -0
- data/Rakefile +67 -0
- data/factbase.gemspec +46 -0
- data/lib/factbase/fact.rb +58 -0
- data/lib/factbase/query.rb +56 -0
- data/lib/factbase/syntax.rb +101 -0
- data/lib/factbase/term.rb +109 -0
- data/lib/factbase.rb +83 -0
- data/renovate.json +6 -0
- data/test/factbase/test_fact.rb +40 -0
- data/test/factbase/test_query.rb +40 -0
- data/test/factbase/test_syntax.rb +72 -0
- data/test/factbase/test_term.rb +68 -0
- data/test/test__helper.rb +30 -0
- data/test/test_factbase.rb +56 -0
- metadata +78 -0
@@ -0,0 +1,58 @@
|
|
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
|
+
# Fact.
|
24
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
26
|
+
# License:: MIT
|
27
|
+
class Factbase::Fact
|
28
|
+
def initialize(mutex, map)
|
29
|
+
@mutex = mutex
|
30
|
+
@map = map
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(*args)
|
34
|
+
k = args[0].to_s
|
35
|
+
if k.end_with?('=')
|
36
|
+
k = k[0..-2]
|
37
|
+
@mutex.synchronize do
|
38
|
+
@map[k] = [] if @map[k].nil?
|
39
|
+
@map[k] << args[1]
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
else
|
43
|
+
v = @map[k]
|
44
|
+
raise "Can't find '#{k}'" if v.nil?
|
45
|
+
v[0]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
50
|
+
def respond_to?(_method, _include_private = false)
|
51
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def respond_to_missing?(_method, _include_private = false)
|
56
|
+
true
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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 'syntax'
|
24
|
+
require_relative 'fact'
|
25
|
+
|
26
|
+
# Query.
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
class Factbase::Query
|
31
|
+
def initialize(maps, mutex, query)
|
32
|
+
@maps = maps
|
33
|
+
@mutex = mutex
|
34
|
+
@query = query
|
35
|
+
end
|
36
|
+
|
37
|
+
# Iterate them one by one.
|
38
|
+
# @yield [Fact] Facts one-by-one
|
39
|
+
def each
|
40
|
+
term = Factbase::Syntax.new(@query).to_term
|
41
|
+
@maps.each do |m|
|
42
|
+
next unless term.matches?(m)
|
43
|
+
yield Factbase::Fact.new(@mutex, m)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Turn it into an array.
|
48
|
+
# @return [Array] All facts in an array
|
49
|
+
# rubocop:disable Style/MapIntoArray
|
50
|
+
def to_a
|
51
|
+
array = []
|
52
|
+
each { |f| array << f }
|
53
|
+
array
|
54
|
+
end
|
55
|
+
# rubocop:enable Style/MapIntoArray
|
56
|
+
end
|
@@ -0,0 +1,101 @@
|
|
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 'cgi'
|
24
|
+
require_relative 'fact'
|
25
|
+
require_relative 'term'
|
26
|
+
|
27
|
+
# Syntax.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class Factbase::Syntax
|
32
|
+
def initialize(query)
|
33
|
+
@query = query
|
34
|
+
end
|
35
|
+
|
36
|
+
# Convert it to a term.
|
37
|
+
# @return [Term] The term detected
|
38
|
+
def to_term
|
39
|
+
@tokens ||= to_tokens
|
40
|
+
@ast ||= to_ast(@tokens, 0)
|
41
|
+
@ast[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Reads the stream of tokens, starting at the +at+ position. If the
|
47
|
+
# token at the position is not a literal (like 42 or "Hello") but a term,
|
48
|
+
# the function recursively calls itself.
|
49
|
+
#
|
50
|
+
# The function returns an two-elements array, where the first element
|
51
|
+
# is the term/literal and the second one is the position where the
|
52
|
+
# scanning should continue.
|
53
|
+
def to_ast(tokens, at)
|
54
|
+
return [tokens[at], at + 1] unless tokens[at] == :open
|
55
|
+
at += 1
|
56
|
+
op = tokens[at]
|
57
|
+
return [Factbase::Term.new(:nil, []), at + 1] if op == :close
|
58
|
+
operands = []
|
59
|
+
at += 1
|
60
|
+
loop do
|
61
|
+
break if tokens[at] == :close
|
62
|
+
(operand, at1) = to_ast(tokens, at)
|
63
|
+
at = at1
|
64
|
+
operands << operand
|
65
|
+
break if tokens[at] == :close
|
66
|
+
end
|
67
|
+
[Factbase::Term.new(op, operands), at + 1]
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_tokens
|
71
|
+
list = []
|
72
|
+
acc = ''
|
73
|
+
@query.to_s.chars.each do |c|
|
74
|
+
if !acc.empty? && [' ', ')'].include?(c)
|
75
|
+
list << acc
|
76
|
+
acc = ''
|
77
|
+
end
|
78
|
+
case c
|
79
|
+
when '('
|
80
|
+
list << :open
|
81
|
+
when ')'
|
82
|
+
list << :close
|
83
|
+
when ' '
|
84
|
+
# ignore it
|
85
|
+
else
|
86
|
+
acc += c
|
87
|
+
end
|
88
|
+
end
|
89
|
+
list.map do |t|
|
90
|
+
if t.is_a?(Symbol)
|
91
|
+
t
|
92
|
+
elsif t.start_with?('\'')
|
93
|
+
CGI.unescapeHTML(t[1..-2])
|
94
|
+
elsif t.match?(/^[0-9]+$/)
|
95
|
+
t.to_i
|
96
|
+
else
|
97
|
+
t.to_sym
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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 'fact'
|
24
|
+
|
25
|
+
# Term.
|
26
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
28
|
+
# License:: MIT
|
29
|
+
class Factbase::Term
|
30
|
+
def initialize(operator, operands)
|
31
|
+
@op = operator
|
32
|
+
@operands = operands
|
33
|
+
end
|
34
|
+
|
35
|
+
# Does it match the map?
|
36
|
+
# @param [Map] The map
|
37
|
+
# @return [bool] TRUE if matches
|
38
|
+
def matches?(map)
|
39
|
+
send(@op, map)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
items = []
|
44
|
+
items << @op
|
45
|
+
items += @operands.map do |o|
|
46
|
+
if o.is_a?(String)
|
47
|
+
"'#{o}'"
|
48
|
+
else
|
49
|
+
o.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
"(#{items.join(' ')})"
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def nil(_map)
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def not(map)
|
62
|
+
!@operands[0].matches?(map)
|
63
|
+
end
|
64
|
+
|
65
|
+
def or(map)
|
66
|
+
@operands.each do |o|
|
67
|
+
return true if o.matches?(map)
|
68
|
+
end
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
def and(map)
|
73
|
+
@operands.each do |o|
|
74
|
+
return false unless o.matches?(map)
|
75
|
+
end
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def exists(map)
|
80
|
+
k = @operands[0].to_s
|
81
|
+
!map[k].nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
def absent(map)
|
85
|
+
k = @operands[0].to_s
|
86
|
+
map[k].nil?
|
87
|
+
end
|
88
|
+
|
89
|
+
def eq(map)
|
90
|
+
k = @operands[0].to_s
|
91
|
+
v = map[k]
|
92
|
+
return false if v.nil?
|
93
|
+
v[0] == @operands[1]
|
94
|
+
end
|
95
|
+
|
96
|
+
def lt(map)
|
97
|
+
k = @operands[0].to_s
|
98
|
+
v = map[k]
|
99
|
+
return false if v.nil?
|
100
|
+
v[0] < @operands[1]
|
101
|
+
end
|
102
|
+
|
103
|
+
def gt(map)
|
104
|
+
k = @operands[0].to_s
|
105
|
+
v = map[k]
|
106
|
+
return false if v.nil?
|
107
|
+
v[0] > @operands[1]
|
108
|
+
end
|
109
|
+
end
|
data/lib/factbase.rb
ADDED
@@ -0,0 +1,83 @@
|
|
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
|
+
# Factbase.
|
24
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
26
|
+
# License:: MIT
|
27
|
+
class Factbase
|
28
|
+
# Current version of the library and of this class.
|
29
|
+
VERSION = '0.0.1'
|
30
|
+
|
31
|
+
# Constructor.
|
32
|
+
def initialize
|
33
|
+
@maps = []
|
34
|
+
@mutex = Mutex.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# Insert a new fact.
|
38
|
+
# @return [Factbase::Fact] The fact just inserted
|
39
|
+
def insert
|
40
|
+
map = {}
|
41
|
+
@mutex.synchronize do
|
42
|
+
f = Factbase::Fact.new(Mutex.new, map)
|
43
|
+
f.id = @maps.size + 1
|
44
|
+
@maps << map
|
45
|
+
end
|
46
|
+
Factbase::Fact.new(@mutex, map)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create a query capable of iterating.
|
50
|
+
#
|
51
|
+
# There is a Lisp-like syntax, for example (all string literals
|
52
|
+
# must be HTML-escaped):
|
53
|
+
#
|
54
|
+
# (eq title 'ObjectThinking')
|
55
|
+
# (gt time '2024-03-23T03:21:43')
|
56
|
+
# (gt cost 42)
|
57
|
+
# (exists seenBy)
|
58
|
+
# (and
|
59
|
+
# (eq foo '42')
|
60
|
+
# (or
|
61
|
+
# (gt bar 200)
|
62
|
+
# (absent zzz)))
|
63
|
+
#
|
64
|
+
# @param [String] query The query to use for selections
|
65
|
+
def query(query)
|
66
|
+
Factbase::Query.new(@maps, @mutex, query)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Export it into a chain of bytes.
|
70
|
+
def export
|
71
|
+
Marshal.dump(@maps)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Import from a chain of bytes.
|
75
|
+
def import(bytes)
|
76
|
+
# rubocop:disable Security/MarshalLoad
|
77
|
+
@maps += Marshal.load(bytes)
|
78
|
+
# rubocop:enable Security/MarshalLoad
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
require_relative 'factbase/fact'
|
83
|
+
require_relative 'factbase/query'
|
data/renovate.json
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2024 Yegor Bugayenko
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
14
|
+
# copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
|
24
|
+
require 'minitest/autorun'
|
25
|
+
require_relative '../../lib/factbase'
|
26
|
+
|
27
|
+
# Fact test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestFact < Minitest::Test
|
32
|
+
def test_simple_resetting
|
33
|
+
map = {}
|
34
|
+
f = Factbase::Fact.new(Mutex.new, map)
|
35
|
+
f.foo = 42
|
36
|
+
assert_equal(42, f.foo)
|
37
|
+
f.foo = 256
|
38
|
+
assert_equal(42, f.foo)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2024 Yegor Bugayenko
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
14
|
+
# copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
|
24
|
+
require 'minitest/autorun'
|
25
|
+
require_relative '../../lib/factbase'
|
26
|
+
|
27
|
+
# Query test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestQuery < Minitest::Test
|
32
|
+
def test_simple_parsing
|
33
|
+
maps = []
|
34
|
+
maps << { 'foo' => [42] }
|
35
|
+
q = Factbase::Query.new(maps, Mutex.new, '(eq foo 42)')
|
36
|
+
q.each do |f|
|
37
|
+
assert_equal(42, f.foo)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2024 Yegor Bugayenko
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
14
|
+
# copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
|
24
|
+
require 'minitest/autorun'
|
25
|
+
require_relative '../../lib/factbase/syntax'
|
26
|
+
|
27
|
+
# Syntax test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestSyntax < Minitest::Test
|
32
|
+
def test_simple_parsing
|
33
|
+
[
|
34
|
+
'()',
|
35
|
+
'(foo)',
|
36
|
+
'(foo (bar) (zz 77) )',
|
37
|
+
"(eq foo 'Hello, world!')",
|
38
|
+
"(or ( a 4) (b 5) () (and () (c 5) (r 7 8s 8is 'Foo')))"
|
39
|
+
].each do |q|
|
40
|
+
Factbase::Syntax.new(q).to_term
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_exact_parsing
|
45
|
+
[
|
46
|
+
'(foo)',
|
47
|
+
'(foo 7)',
|
48
|
+
"(foo 7 'Dude')",
|
49
|
+
'(foo x y z)',
|
50
|
+
"(foo x y z t f 42 'Hi!' 33)",
|
51
|
+
'(foo (x) y z)',
|
52
|
+
"(foo (x (f (t (y 42 'Hey'))) (f) (r 3)) y z)"
|
53
|
+
].each do |q|
|
54
|
+
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_simple_matching
|
59
|
+
m = {
|
60
|
+
'foo' => ['Hello, world!'],
|
61
|
+
'bar' => [42],
|
62
|
+
'z' => [1, 2, 3, 4]
|
63
|
+
}
|
64
|
+
{
|
65
|
+
'(eq z 1)' => true,
|
66
|
+
'(or (eq bar 888) (eq z 1))' => true,
|
67
|
+
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
68
|
+
}.each do |k, v|
|
69
|
+
assert_equal(v, Factbase::Syntax.new(k).to_term.matches?(m), k)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2024 Yegor Bugayenko
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
14
|
+
# copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
|
24
|
+
require 'minitest/autorun'
|
25
|
+
require_relative '../../lib/factbase/term'
|
26
|
+
|
27
|
+
# Term test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestTerm < Minitest::Test
|
32
|
+
def test_simple_matching
|
33
|
+
t = Factbase::Term.new(:eq, ['foo', 42])
|
34
|
+
assert(t.matches?({ 'foo' => [42] }))
|
35
|
+
assert(!t.matches?({ 'foo' => ['Hello!'] }))
|
36
|
+
assert(!t.matches?({ 'bar' => ['Hello!'] }))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_lt_matching
|
40
|
+
t = Factbase::Term.new(:lt, ['foo', 42])
|
41
|
+
assert(t.matches?({ 'foo' => [10] }))
|
42
|
+
assert(!t.matches?({ 'foo' => [100] }))
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_gt_matching
|
46
|
+
t = Factbase::Term.new(:gt, ['foo', 42])
|
47
|
+
assert(t.matches?({ 'foo' => [100] }))
|
48
|
+
assert(!t.matches?({ 'foo' => [10] }))
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_not_matching
|
52
|
+
t = Factbase::Term.new(:not, [Factbase::Term.new(:nil, [])])
|
53
|
+
assert(!t.matches?({ 'foo' => [100] }))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_or_matching
|
57
|
+
t = Factbase::Term.new(
|
58
|
+
:or,
|
59
|
+
[
|
60
|
+
Factbase::Term.new(:eq, ['foo', 4]),
|
61
|
+
Factbase::Term.new(:eq, ['bar', 5])
|
62
|
+
]
|
63
|
+
)
|
64
|
+
assert(t.matches?({ 'foo' => [4] }))
|
65
|
+
assert(t.matches?({ 'bar' => [5] }))
|
66
|
+
assert(!t.matches?({ 'bar' => [42] }))
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2024 Yegor Bugayenko
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
14
|
+
# copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
|
24
|
+
$stdout.sync = true
|
25
|
+
|
26
|
+
require 'simplecov'
|
27
|
+
SimpleCov.start
|
28
|
+
|
29
|
+
require 'minitest/autorun'
|
30
|
+
require_relative '../lib/factbase'
|