factbase 0.16.7 → 0.17.0
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/Gemfile +2 -1
- data/Gemfile.lock +25 -20
- data/README.md +28 -27
- data/Rakefile +14 -6
- data/lib/factbase/cached/cached_query.rb +2 -0
- data/lib/factbase/indexed/indexed_absent.rb +25 -0
- data/lib/factbase/indexed/indexed_and.rb +79 -0
- data/lib/factbase/indexed/indexed_eq.rb +46 -0
- data/lib/factbase/indexed/indexed_exists.rb +25 -0
- data/lib/factbase/indexed/indexed_factbase.rb +46 -0
- data/lib/factbase/indexed/indexed_gt.rb +41 -0
- data/lib/factbase/indexed/indexed_lt.rb +41 -0
- data/lib/factbase/indexed/indexed_not.rb +32 -0
- data/lib/factbase/indexed/indexed_one.rb +25 -0
- data/lib/factbase/indexed/indexed_or.rb +28 -0
- data/lib/factbase/indexed/indexed_query.rb +2 -0
- data/lib/factbase/indexed/indexed_term.rb +29 -185
- data/lib/factbase/indexed/indexed_unique.rb +25 -0
- data/lib/factbase/query.rb +22 -8
- data/lib/factbase/sync/sync_factbase.rb +11 -11
- data/lib/factbase/sync/sync_query.rb +7 -8
- data/lib/factbase/term.rb +110 -91
- data/lib/factbase/terms/absent.rb +26 -0
- data/lib/factbase/terms/aggregates.rb +0 -13
- data/lib/factbase/terms/always.rb +27 -0
- data/lib/factbase/terms/and.rb +28 -0
- data/lib/factbase/terms/arithmetic.rb +55 -0
- data/lib/factbase/terms/as.rb +31 -0
- data/lib/factbase/terms/{debug.rb → assert.rb} +17 -15
- data/lib/factbase/terms/base.rb +17 -0
- data/lib/factbase/terms/boolean.rb +28 -0
- data/lib/factbase/terms/compare.rb +38 -0
- data/lib/factbase/terms/concat.rb +26 -0
- data/lib/factbase/terms/count.rb +25 -0
- data/lib/factbase/terms/defn.rb +16 -15
- data/lib/factbase/terms/div.rb +25 -0
- data/lib/factbase/terms/either.rb +31 -0
- data/lib/factbase/terms/env.rb +28 -0
- data/lib/factbase/terms/eq.rb +28 -0
- data/lib/factbase/terms/exists.rb +27 -0
- data/lib/factbase/terms/first.rb +30 -0
- data/lib/factbase/terms/gt.rb +28 -0
- data/lib/factbase/terms/gte.rb +27 -0
- data/lib/factbase/terms/head.rb +37 -0
- data/lib/factbase/terms/inverted.rb +34 -0
- data/lib/factbase/terms/{aliases.rb → join.rb} +15 -15
- data/lib/factbase/terms/logical.rb +0 -83
- data/lib/factbase/terms/lt.rb +28 -0
- data/lib/factbase/terms/lte.rb +28 -0
- data/lib/factbase/terms/many.rb +29 -0
- data/lib/factbase/terms/{strings.rb → matches.rb} +12 -12
- data/lib/factbase/terms/minus.rb +25 -0
- data/lib/factbase/terms/never.rb +26 -0
- data/lib/factbase/terms/nil.rb +26 -0
- data/lib/factbase/terms/not.rb +27 -0
- data/lib/factbase/terms/one.rb +30 -0
- data/lib/factbase/terms/or.rb +28 -0
- data/lib/factbase/terms/plus.rb +27 -0
- data/lib/factbase/terms/prev.rb +29 -0
- data/lib/factbase/terms/shared.rb +69 -0
- data/lib/factbase/terms/size.rb +30 -0
- data/lib/factbase/terms/sorted.rb +38 -0
- data/lib/factbase/terms/sprintf.rb +29 -0
- data/lib/factbase/terms/times.rb +25 -0
- data/lib/factbase/terms/to_float.rb +28 -0
- data/lib/factbase/terms/to_integer.rb +28 -0
- data/lib/factbase/terms/to_string.rb +28 -0
- data/lib/factbase/terms/to_time.rb +28 -0
- data/lib/factbase/terms/traced.rb +33 -0
- data/lib/factbase/terms/type.rb +31 -0
- data/lib/factbase/terms/undef.rb +33 -0
- data/lib/factbase/terms/unique.rb +34 -0
- data/lib/factbase/terms/when.rb +29 -0
- data/lib/factbase/terms/zero.rb +28 -0
- data/lib/factbase/version.rb +1 -1
- data/lib/factbase.rb +10 -1
- metadata +60 -10
- data/lib/factbase/terms/casting.rb +0 -41
- data/lib/factbase/terms/lists.rb +0 -57
- data/lib/factbase/terms/math.rb +0 -103
- data/lib/factbase/terms/meta.rb +0 -58
- data/lib/factbase/terms/ordering.rb +0 -34
- data/lib/factbase/terms/system.rb +0 -19
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# Represents a 'head' term in the Factbase.
|
|
8
|
+
# It retrieves the first N results from a query.
|
|
9
|
+
class Factbase::Head < Factbase::TermBase
|
|
10
|
+
# Constructor.
|
|
11
|
+
# @param [Array] operands Operands
|
|
12
|
+
def initialize(operands)
|
|
13
|
+
super()
|
|
14
|
+
@operands = operands
|
|
15
|
+
@op = 'head'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Evaluate term on a fact.
|
|
19
|
+
# @param [Factbase::Fact] _fact The fact
|
|
20
|
+
# @param [Array<Factbase::Fact>] _maps All maps available
|
|
21
|
+
# @param [Factbase] _fb Factbase to use for sub-queries
|
|
22
|
+
# @return [Boolean] Always true
|
|
23
|
+
def evaluate(_fact, _maps, _fb)
|
|
24
|
+
true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def predict(maps, fb, params)
|
|
28
|
+
assert_args(2)
|
|
29
|
+
max = @operands[0]
|
|
30
|
+
raise "An integer is expected as first argument of '#{@op}'" unless max.is_a?(Integer)
|
|
31
|
+
term = @operands[1]
|
|
32
|
+
raise "A term is expected, but '#{term}' provided" unless term.is_a?(Factbase::Term)
|
|
33
|
+
fb.query(term, maps).each(fb, params).to_a
|
|
34
|
+
.take(max)
|
|
35
|
+
.map { |m| m.all_properties.to_h { |k| [k, m[k]] } }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# Evaluates whether a value is inverted within a given factbase context.
|
|
8
|
+
class Factbase::Inverted < Factbase::TermBase
|
|
9
|
+
# Constructor.
|
|
10
|
+
# @param [Array] operands Operands
|
|
11
|
+
def initialize(operands)
|
|
12
|
+
super()
|
|
13
|
+
@operands = operands
|
|
14
|
+
@op = 'inverted'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Evaluate term on a fact.
|
|
18
|
+
# @param [Factbase::Fact] _fact The fact
|
|
19
|
+
# @param [Array<Factbase::Fact>] _maps All maps available
|
|
20
|
+
# @param [Factbase] _fb Factbase to use for sub-queries
|
|
21
|
+
# @return [Boolean] Whether the value is inverted
|
|
22
|
+
def evaluate(_fact, _maps, _fb)
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def predict(maps, fb, params)
|
|
27
|
+
assert_args(1)
|
|
28
|
+
term = @operands[0]
|
|
29
|
+
raise "A term is expected, but '#{term}' provided" unless term.is_a?(Factbase::Term)
|
|
30
|
+
fb.query(term, maps).each(fb, params).to_a
|
|
31
|
+
.reverse
|
|
32
|
+
.map { |m| m.all_properties.to_h { |k| [k, m[k]] } }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require_relative '
|
|
6
|
+
require_relative 'base'
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
a = @operands[0]
|
|
17
|
-
raise "A symbol is expected as first argument of 'as'" unless a.is_a?(Symbol)
|
|
18
|
-
vv = _values(1, fact, maps, fb)
|
|
19
|
-
vv&.each { |v| fact.send(:"#{a}=", v) }
|
|
20
|
-
true
|
|
8
|
+
# The Factbase::Join class is a specialized term that performs
|
|
9
|
+
# join operations between facts based on specified attribute mappings.
|
|
10
|
+
class Factbase::Join < Factbase::TermBase
|
|
11
|
+
# Constructor.
|
|
12
|
+
# @param [Array] operands Operands
|
|
13
|
+
def initialize(operands)
|
|
14
|
+
super()
|
|
15
|
+
@operands = operands
|
|
21
16
|
end
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
# Evaluate term on a fact.
|
|
19
|
+
# @param [Factbase::Fact] fact The fact
|
|
20
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
21
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
22
|
+
# @return [Boolean] True if succeeded
|
|
23
|
+
def evaluate(fact, maps, fb)
|
|
24
24
|
assert_args(2)
|
|
25
25
|
jumps = @operands[0]
|
|
26
26
|
raise "A string is expected as first argument of 'join'" unless jumps.is_a?(String)
|
|
@@ -11,77 +11,6 @@ require_relative '../../factbase'
|
|
|
11
11
|
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
13
|
module Factbase::Logical
|
|
14
|
-
# Always returns true, regardless of the fact
|
|
15
|
-
# @param [Factbase::Fact] _fact The fact (unused)
|
|
16
|
-
# @param [Array<Factbase::Fact>] _maps All maps available (unused)
|
|
17
|
-
# @return [Boolean] Always returns true
|
|
18
|
-
def always(_fact, _maps, _fb)
|
|
19
|
-
assert_args(0)
|
|
20
|
-
true
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Always returns false, regardless of the fact
|
|
24
|
-
# @param [Factbase::Fact] _fact The fact (unused)
|
|
25
|
-
# @param [Array<Factbase::Fact>] _maps All maps available (unused)
|
|
26
|
-
# @return [Boolean] Always returns false
|
|
27
|
-
def never(_fact, _maps, _fb)
|
|
28
|
-
assert_args(0)
|
|
29
|
-
false
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Logical negation (NOT) of an operand
|
|
33
|
-
# @param [Factbase::Fact] fact The fact
|
|
34
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
|
35
|
-
# @return [Boolean] Negated boolean result of the operand
|
|
36
|
-
def not(fact, maps, fb)
|
|
37
|
-
assert_args(1)
|
|
38
|
-
!_only_bool(_values(0, fact, maps, fb), 0)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Logical OR of multiple operands
|
|
42
|
-
# @param [Factbase::Fact] fact The fact
|
|
43
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
|
44
|
-
# @return [Boolean] True if any operand evaluates to true, false otherwise
|
|
45
|
-
def or(fact, maps, fb)
|
|
46
|
-
(0..(@operands.size - 1)).each do |i|
|
|
47
|
-
return true if _only_bool(_values(i, fact, maps, fb), i)
|
|
48
|
-
end
|
|
49
|
-
false
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Logical AND of multiple operands
|
|
53
|
-
# @param [Factbase::Fact] fact The fact
|
|
54
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
|
55
|
-
# @return [Boolean] True if all operands evaluate to true, false otherwise
|
|
56
|
-
def and(fact, maps, fb)
|
|
57
|
-
(0..(@operands.size - 1)).each do |i|
|
|
58
|
-
return false unless _only_bool(_values(i, fact, maps, fb), i)
|
|
59
|
-
end
|
|
60
|
-
true
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Logical implication (IF...THEN)
|
|
64
|
-
# @param [Factbase::Fact] fact The fact
|
|
65
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
|
66
|
-
# @return [Boolean] True if first operand is false OR both are true
|
|
67
|
-
def when(fact, maps, fb)
|
|
68
|
-
assert_args(2)
|
|
69
|
-
a = @operands[0]
|
|
70
|
-
b = @operands[1]
|
|
71
|
-
!a.evaluate(fact, maps, fb) || (a.evaluate(fact, maps, fb) && b.evaluate(fact, maps, fb))
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# Returns the first non-nil value or the second value
|
|
75
|
-
# @param [Factbase::Fact] fact The fact
|
|
76
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
|
77
|
-
# @return [Object] First operand if not nil, otherwise second operand
|
|
78
|
-
def either(fact, maps, fb)
|
|
79
|
-
assert_args(2)
|
|
80
|
-
v = _values(0, fact, maps, fb)
|
|
81
|
-
return v unless v.nil?
|
|
82
|
-
_values(1, fact, maps, fb)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
14
|
# Simplifies AND or OR expressions by removing duplicates
|
|
86
15
|
# @return [Factbase::Term] Simplified term
|
|
87
16
|
def and_or_simplify
|
|
@@ -109,16 +38,4 @@ module Factbase::Logical
|
|
|
109
38
|
def or_simplify
|
|
110
39
|
and_or_simplify
|
|
111
40
|
end
|
|
112
|
-
|
|
113
|
-
# Helper method to ensure a value is boolean
|
|
114
|
-
# @param [Object] val The value to check
|
|
115
|
-
# @param [Integer] pos The position of the operand
|
|
116
|
-
# @return [Boolean] The boolean value
|
|
117
|
-
# @raise [RuntimeError] If value is not a boolean
|
|
118
|
-
def _only_bool(val, pos)
|
|
119
|
-
val = val[0] if val.respond_to?(:each)
|
|
120
|
-
return false if val.nil?
|
|
121
|
-
return val if val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
|
122
|
-
raise "Boolean is expected, while #{val.class} received from #{@operands[pos]}"
|
|
123
|
-
end
|
|
124
41
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
require_relative 'compare'
|
|
8
|
+
|
|
9
|
+
# Represents a less-than term in the Factbase system.
|
|
10
|
+
# This class is used to evaluate whether a given fact satisfies
|
|
11
|
+
# a less-than comparison with the specified operands.
|
|
12
|
+
class Factbase::Lt < Factbase::TermBase
|
|
13
|
+
# Constructor.
|
|
14
|
+
# @param [Array] operands Operands
|
|
15
|
+
def initialize(operands)
|
|
16
|
+
super()
|
|
17
|
+
@op = Factbase::Compare.new(:<, operands)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Evaluate term on a fact.
|
|
21
|
+
# @param [Factbase::Fact] fact The fact
|
|
22
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
23
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
24
|
+
# @return [Boolean] The result of the less-than comparison
|
|
25
|
+
def evaluate(fact, maps, fb)
|
|
26
|
+
@op.evaluate(fact, maps, fb)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
require_relative 'compare'
|
|
8
|
+
|
|
9
|
+
# Represents a less-than-equal term in the Factbase.
|
|
10
|
+
# This class is used to evaluate whether a given fact satisfies
|
|
11
|
+
# a less-than-equal comparison with the specified operands.
|
|
12
|
+
class Factbase::Lte < Factbase::TermBase
|
|
13
|
+
# Constructor.
|
|
14
|
+
# @param [Array] operands Operands
|
|
15
|
+
def initialize(operands)
|
|
16
|
+
super()
|
|
17
|
+
@op = Factbase::Compare.new(:<=, operands)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Evaluate term on a fact.
|
|
21
|
+
# @param [Factbase::Fact] fact The fact
|
|
22
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
23
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
24
|
+
# @return [Boolean] The result of the less-than-equal comparison
|
|
25
|
+
def evaluate(fact, maps, fb)
|
|
26
|
+
@op.evaluate(fact, maps, fb)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
|
|
8
|
+
# Represents a 'many' term in the Factbase that evaluates to true if a property
|
|
9
|
+
# has multiple values. This class is used to check if there are more
|
|
10
|
+
# than one values associated with a specific property in a fact.
|
|
11
|
+
class Factbase::Many < Factbase::TermBase
|
|
12
|
+
# Constructor.
|
|
13
|
+
# @param [Array] operands Operands
|
|
14
|
+
def initialize(operands)
|
|
15
|
+
super()
|
|
16
|
+
@operands = operands
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Evaluate term on a fact.
|
|
20
|
+
# @param [Factbase::Fact] fact The fact
|
|
21
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
22
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
23
|
+
# @return [Boolean] True if many
|
|
24
|
+
def evaluate(fact, maps, fb)
|
|
25
|
+
assert_args(1)
|
|
26
|
+
v = _values(0, fact, maps, fb)
|
|
27
|
+
!v.nil? && v.size > 1
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -3,25 +3,25 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require_relative '
|
|
6
|
+
require_relative 'base'
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Matches term.
|
|
9
9
|
#
|
|
10
10
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
11
11
|
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
12
12
|
# License:: MIT
|
|
13
|
-
|
|
14
|
-
def
|
|
15
|
-
(
|
|
13
|
+
class Factbase::Matches < Factbase::TermBase
|
|
14
|
+
def initialize(operands)
|
|
15
|
+
super()
|
|
16
|
+
@operands = operands
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def matches(fact, maps, fb)
|
|
19
|
+
# Evaluate term on a fact.
|
|
20
|
+
# @param [Factbase::Fact] fact The fact
|
|
21
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
22
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
23
|
+
# @return [Boolean] True if the string matches the regexp, false otherwise
|
|
24
|
+
def evaluate(fact, maps, fb)
|
|
25
25
|
assert_args(2)
|
|
26
26
|
str = _values(0, fact, maps, fb)
|
|
27
27
|
return false if str.nil?
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# This class represents a 'minus' term within the Factbase.
|
|
8
|
+
# It performs a subtraction operation over the given operands.
|
|
9
|
+
class Factbase::Minus < Factbase::TermBase
|
|
10
|
+
# Constructor.
|
|
11
|
+
# @param [Array] operands Operands
|
|
12
|
+
def initialize(operands)
|
|
13
|
+
super()
|
|
14
|
+
@minus = Factbase::Arithmetic.new(:-, operands)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Evaluate term on a fact.
|
|
18
|
+
# @param [Factbase::Fact] fact The fact
|
|
19
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
20
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
21
|
+
# @return [Object] Result of the subtraction
|
|
22
|
+
def evaluate(fact, maps, fb)
|
|
23
|
+
@minus.evaluate(fact, maps, fb)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# The term 'never' that never evaluates to true.
|
|
8
|
+
class Factbase::Never < Factbase::TermBase
|
|
9
|
+
# Constructor.
|
|
10
|
+
# @param [Array] operands Operands
|
|
11
|
+
def initialize(operands = [])
|
|
12
|
+
super()
|
|
13
|
+
@operands = operands
|
|
14
|
+
@op = :never
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Evaluate term on a fact.
|
|
18
|
+
# @param [Factbase::Fact] _fact The fact
|
|
19
|
+
# @param [Array<Factbase::Fact>] _maps All maps available
|
|
20
|
+
# @param [Factbase] _fb Factbase to use for sub-queries
|
|
21
|
+
# @return [Boolean] Always returns false
|
|
22
|
+
def evaluate(_fact, _maps, _fb)
|
|
23
|
+
assert_args(0)
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# A class representing a "nil" term in the Factbase system.
|
|
8
|
+
# It evaluates to true if the value is nil.
|
|
9
|
+
class Factbase::Nil < Factbase::TermBase
|
|
10
|
+
# Constructor.
|
|
11
|
+
# @param [Array] operands Operands
|
|
12
|
+
def initialize(operands)
|
|
13
|
+
super()
|
|
14
|
+
@operands = operands
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Evaluate term on a fact.
|
|
18
|
+
# @param [Factbase::Fact] fact The fact
|
|
19
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
20
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
21
|
+
# @return [Boolean] True if nil
|
|
22
|
+
def evaluate(fact, maps, fb)
|
|
23
|
+
assert_args(1)
|
|
24
|
+
_values(0, fact, maps, fb).nil?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
require_relative 'boolean'
|
|
8
|
+
# The 'not' term that negates a boolean operand.
|
|
9
|
+
# Logical negation (NOT) of an operand.
|
|
10
|
+
class Factbase::Not < Factbase::TermBase
|
|
11
|
+
# Constructor.
|
|
12
|
+
# @param [Array] operands Operands
|
|
13
|
+
def initialize(operands)
|
|
14
|
+
super()
|
|
15
|
+
@operands = operands
|
|
16
|
+
@op = :not
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Evaluate term on a fact.
|
|
20
|
+
# @param [Factbase::Fact] fact The fact
|
|
21
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
22
|
+
# @return [Boolean] Negated boolean result of the operand
|
|
23
|
+
def evaluate(fact, maps, fb)
|
|
24
|
+
assert_args(1)
|
|
25
|
+
!Factbase::Boolean.new(_values(0, fact, maps, fb), @operands[0]).bool?
|
|
26
|
+
end
|
|
27
|
+
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 'base'
|
|
7
|
+
|
|
8
|
+
# The term which property has exactly one value.
|
|
9
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
10
|
+
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
11
|
+
# License:: MIT
|
|
12
|
+
class Factbase::One < Factbase::TermBase
|
|
13
|
+
# Constructor.
|
|
14
|
+
# @param [Array] operands Operands
|
|
15
|
+
def initialize(operands)
|
|
16
|
+
super()
|
|
17
|
+
@operands = operands
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Evaluate term on a fact.
|
|
21
|
+
# @param [Factbase::Fact] fact The fact
|
|
22
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
23
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
24
|
+
# @return [Boolean] True if exactly one value
|
|
25
|
+
def evaluate(fact, maps, fb)
|
|
26
|
+
assert_args(1)
|
|
27
|
+
v = _values(0, fact, maps, fb)
|
|
28
|
+
!v.nil? && v.size == 1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
require_relative 'boolean'
|
|
8
|
+
# The 'or' term that represents a logical OR operation between multiple operands.
|
|
9
|
+
class Factbase::Or < Factbase::TermBase
|
|
10
|
+
# Constructor.
|
|
11
|
+
# @param [Array] operands Operands
|
|
12
|
+
def initialize(operands)
|
|
13
|
+
super()
|
|
14
|
+
@operands = operands
|
|
15
|
+
@op = :or
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Evaluate term on a fact.
|
|
19
|
+
# @param [Factbase::Fact] fact The fact
|
|
20
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
21
|
+
# @return [Boolean] True if any operand evaluates to true, false otherwise
|
|
22
|
+
def evaluate(fact, maps, fb)
|
|
23
|
+
(0..(@operands.size - 1)).each do |i|
|
|
24
|
+
return true if Factbase::Boolean.new(_values(i, fact, maps, fb), @operands[i]).bool?
|
|
25
|
+
end
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
require_relative 'arithmetic'
|
|
8
|
+
|
|
9
|
+
# Represents a Plus term in the Factbase system.
|
|
10
|
+
# This class is used to perform addition operations on operands.
|
|
11
|
+
class Factbase::Plus < Factbase::TermBase
|
|
12
|
+
# Constructor.
|
|
13
|
+
# @param [Array] operands Operands
|
|
14
|
+
def initialize(operands)
|
|
15
|
+
super()
|
|
16
|
+
@plus = Factbase::Arithmetic.new(:+, operands)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Evaluate term on a fact.
|
|
20
|
+
# @param [Factbase::Fact] fact The fact
|
|
21
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
22
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
23
|
+
# @return [Object] Result of the addition
|
|
24
|
+
def evaluate(fact, maps, fb)
|
|
25
|
+
@plus.evaluate(fact, maps, fb)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'base'
|
|
7
|
+
# The Factbase::Unique class provides functionality for evaluating the uniqueness
|
|
8
|
+
# of terms based on provided operands and facts.
|
|
9
|
+
class Factbase::Prev < Factbase::TermBase
|
|
10
|
+
# Constructor.
|
|
11
|
+
# @param [Array] operands Operands
|
|
12
|
+
def initialize(operands)
|
|
13
|
+
super()
|
|
14
|
+
@operands = operands
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Evaluate term on a fact.
|
|
18
|
+
# @param [Factbase::Fact] fact The fact
|
|
19
|
+
# @param [Array<Factbase::Fact>] maps All maps available
|
|
20
|
+
# @param [Factbase] fb Factbase to use for sub-queries
|
|
21
|
+
# @return [Object] The previous value
|
|
22
|
+
def evaluate(fact, maps, fb)
|
|
23
|
+
assert_args(1)
|
|
24
|
+
before = @prev
|
|
25
|
+
v = _values(0, fact, maps, fb)
|
|
26
|
+
@prev = v
|
|
27
|
+
before
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
# This module provides shared methods for Factbase terms, including argument validation,
|
|
7
|
+
# symbol-based lookups, and handling of operand values.
|
|
8
|
+
# @todo #302:30min Remove this module and move its methods to Factbase::TermBase.
|
|
9
|
+
# Currently, we use it because we are required to inject all thesse methods into Factbase::Term.
|
|
10
|
+
# When all the terms will inherit from Factbase::TermBase, we can remove this module.
|
|
11
|
+
module Factbase::TermShared
|
|
12
|
+
# Turns it into a string.
|
|
13
|
+
# @return [String] The string of it
|
|
14
|
+
def to_s
|
|
15
|
+
@to_s ||=
|
|
16
|
+
begin
|
|
17
|
+
items = []
|
|
18
|
+
items << @op
|
|
19
|
+
items +=
|
|
20
|
+
@operands.map do |o|
|
|
21
|
+
if o.is_a?(String)
|
|
22
|
+
"'#{o.gsub("'", "\\\\'").gsub('"', '\\\\"')}'"
|
|
23
|
+
elsif o.is_a?(Time)
|
|
24
|
+
o.utc.iso8601
|
|
25
|
+
else
|
|
26
|
+
o.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
"(#{items.join(' ')})"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def assert_args(num)
|
|
36
|
+
c = @operands.size
|
|
37
|
+
raise "Too many (#{c}) operands for '#{@op}' (#{num} expected)" if c > num
|
|
38
|
+
raise "Too few (#{c}) operands for '#{@op}' (#{num} expected)" if c < num
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def _by_symbol(pos, fact)
|
|
42
|
+
o = @operands[pos]
|
|
43
|
+
raise "A symbol expected at ##{pos}, but '#{o}' (#{o.class}) provided" unless o.is_a?(Symbol)
|
|
44
|
+
k = o.to_s
|
|
45
|
+
fact[k]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Array|nil] Either array of values or NIL
|
|
49
|
+
def _values(pos, fact, maps, fb)
|
|
50
|
+
v = @operands[pos]
|
|
51
|
+
v = v.evaluate(fact, maps, fb) if v.is_a?(Factbase::Term)
|
|
52
|
+
v = v.evaluate(fact, maps, fb) if v.is_a?(Factbase::TermBase)
|
|
53
|
+
v = fact[v.to_s] if v.is_a?(Symbol)
|
|
54
|
+
return v if v.nil?
|
|
55
|
+
unless v.is_a?(Array)
|
|
56
|
+
v =
|
|
57
|
+
if v.respond_to?(:each)
|
|
58
|
+
v.to_a
|
|
59
|
+
else
|
|
60
|
+
[v]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
raise 'Why not array?' unless v.is_a?(Array)
|
|
64
|
+
unless v.all? { |i| [Float, Integer, String, Time, TrueClass, FalseClass].any? { |t| i.is_a?(t) } }
|
|
65
|
+
raise 'Wrong type inside'
|
|
66
|
+
end
|
|
67
|
+
v
|
|
68
|
+
end
|
|
69
|
+
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 'base'
|
|
7
|
+
|
|
8
|
+
# Factbase::Size is a term that calculates the size of an operand
|
|
9
|
+
# when evaluated on a given fact.
|
|
10
|
+
class Factbase::Size < Factbase::TermBase
|
|
11
|
+
# Constructor.
|
|
12
|
+
# @param [Array] operands Operands
|
|
13
|
+
def initialize(operands)
|
|
14
|
+
super()
|
|
15
|
+
@operands = operands
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Evaluate term on a fact.
|
|
19
|
+
# @param [Factbase::Fact] fact The fact
|
|
20
|
+
# @param [Array<Factbase::Fact>] _maps All maps available
|
|
21
|
+
# @param [Factbase] _fb Factbase to use for sub-queries
|
|
22
|
+
# @return [Integer] Size of the operand
|
|
23
|
+
def evaluate(fact, _maps, _fb)
|
|
24
|
+
assert_args(1)
|
|
25
|
+
v = _by_symbol(0, fact)
|
|
26
|
+
return 0 if v.nil?
|
|
27
|
+
return 1 unless v.respond_to?(:to_a)
|
|
28
|
+
v.size
|
|
29
|
+
end
|
|
30
|
+
end
|