factbase 0.19.11 → 0.19.12
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 +5 -4
- data/Gemfile.lock +16 -12
- data/README.md +49 -18
- data/Rakefile +2 -7
- data/factbase.gemspec +11 -11
- data/lib/factbase/accum.rb +1 -1
- data/lib/factbase/cached/cached_fact.rb +1 -2
- data/lib/factbase/cached/cached_factbase.rb +3 -3
- data/lib/factbase/cached/cached_query.rb +4 -6
- data/lib/factbase/cached/cached_term.rb +1 -2
- data/lib/factbase/churn.rb +4 -8
- data/lib/factbase/fact.rb +12 -9
- data/lib/factbase/flatten.rb +2 -2
- data/lib/factbase/impatient.rb +14 -13
- data/lib/factbase/indexed/indexed_and.rb +14 -20
- data/lib/factbase/indexed/indexed_eq.rb +5 -1
- data/lib/factbase/indexed/indexed_fact.rb +1 -4
- data/lib/factbase/indexed/indexed_factbase.rb +4 -4
- data/lib/factbase/indexed/indexed_gt.rb +3 -1
- data/lib/factbase/indexed/indexed_gte.rb +51 -0
- data/lib/factbase/indexed/indexed_lt.rb +3 -1
- data/lib/factbase/indexed/indexed_lte.rb +51 -0
- data/lib/factbase/indexed/indexed_not.rb +1 -1
- data/lib/factbase/indexed/indexed_or.rb +2 -2
- data/lib/factbase/indexed/indexed_query.rb +6 -7
- data/lib/factbase/indexed/indexed_term.rb +10 -6
- data/lib/factbase/indexed/indexed_unique.rb +4 -2
- data/lib/factbase/inv.rb +3 -3
- data/lib/factbase/lazy_taped.rb +10 -13
- data/lib/factbase/lazy_taped_hash.rb +2 -1
- data/lib/factbase/light.rb +1 -1
- data/lib/factbase/logged.rb +37 -34
- data/lib/factbase/pre.rb +3 -3
- data/lib/factbase/query.rb +4 -5
- data/lib/factbase/rules.rb +8 -8
- data/lib/factbase/sync/sync_factbase.rb +2 -2
- data/lib/factbase/syntax.rb +18 -19
- data/lib/factbase/tallied.rb +6 -7
- data/lib/factbase/taped.rb +5 -11
- data/lib/factbase/tee.rb +2 -2
- data/lib/factbase/term.rb +53 -60
- data/lib/factbase/terms/agg.rb +3 -4
- data/lib/factbase/terms/arithmetic.rb +7 -7
- data/lib/factbase/terms/as.rb +2 -2
- data/lib/factbase/terms/assert.rb +5 -13
- data/lib/factbase/terms/base.rb +6 -7
- data/lib/factbase/terms/best.rb +1 -1
- data/lib/factbase/terms/boolean.rb +1 -1
- data/lib/factbase/terms/compare.rb +2 -1
- data/lib/factbase/terms/defn.rb +8 -6
- data/lib/factbase/terms/empty.rb +1 -1
- data/lib/factbase/terms/first.rb +2 -2
- data/lib/factbase/terms/head.rb +3 -3
- data/lib/factbase/terms/inverted.rb +2 -2
- data/lib/factbase/terms/join.rb +8 -7
- data/lib/factbase/terms/matches.rb +4 -4
- data/lib/factbase/terms/max.rb +1 -1
- data/lib/factbase/terms/min.rb +1 -1
- data/lib/factbase/terms/nth.rb +3 -3
- data/lib/factbase/terms/plus.rb +1 -1
- data/lib/factbase/terms/prev.rb +3 -6
- data/lib/factbase/terms/sorted.rb +2 -2
- data/lib/factbase/terms/sprintf.rb +5 -4
- data/lib/factbase/terms/sum.rb +1 -1
- data/lib/factbase/terms/to_float.rb +2 -2
- data/lib/factbase/terms/to_integer.rb +2 -2
- data/lib/factbase/terms/to_string.rb +1 -1
- data/lib/factbase/terms/to_time.rb +2 -2
- data/lib/factbase/terms/traced.rb +2 -2
- data/lib/factbase/terms/undef.rb +2 -2
- data/lib/factbase/terms/unique.rb +3 -7
- data/lib/factbase/to_json.rb +1 -1
- data/lib/factbase/to_xml.rb +5 -9
- data/lib/factbase/to_yaml.rb +1 -1
- data/lib/factbase/version.rb +1 -2
- data/lib/factbase.rb +27 -10
- data/lib/fuzz.rb +3 -3
- metadata +3 -1
data/lib/factbase/terms/max.rb
CHANGED
data/lib/factbase/terms/min.rb
CHANGED
data/lib/factbase/terms/nth.rb
CHANGED
|
@@ -23,11 +23,11 @@ class Factbase::Nth < Factbase::TermBase
|
|
|
23
23
|
def evaluate(_fact, maps, _fb)
|
|
24
24
|
assert_args(2)
|
|
25
25
|
pos = @operands[0]
|
|
26
|
-
raise "An integer is expected, but #{pos} provided" unless pos.is_a?(Integer)
|
|
26
|
+
raise(ArgumentError, "An integer is expected, but #{pos} provided") unless pos.is_a?(Integer)
|
|
27
27
|
k = @operands[1]
|
|
28
|
-
raise "A symbol is expected, but #{k} provided" unless k.is_a?(Symbol)
|
|
28
|
+
raise(ArgumentError, "A symbol is expected, but #{k} provided") unless k.is_a?(Symbol)
|
|
29
29
|
m = maps[pos]
|
|
30
|
-
return
|
|
30
|
+
return if m.nil?
|
|
31
31
|
m[k.to_s]
|
|
32
32
|
end
|
|
33
33
|
end
|
data/lib/factbase/terms/plus.rb
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require_relative 'base'
|
|
7
6
|
require_relative 'arithmetic'
|
|
7
|
+
require_relative 'base'
|
|
8
8
|
|
|
9
9
|
# Represents a Plus term in the Factbase system.
|
|
10
10
|
# This class is used to perform addition operations on operands.
|
data/lib/factbase/terms/prev.rb
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require_relative 'base'
|
|
7
|
-
# The Factbase::
|
|
8
|
-
#
|
|
7
|
+
# The Factbase::Prev class returns the previous value of a property
|
|
8
|
+
# during iteration, enabling comparisons between consecutive facts.
|
|
9
9
|
class Factbase::Prev < Factbase::TermBase
|
|
10
10
|
# Constructor.
|
|
11
11
|
# @param [Array] operands Operands
|
|
@@ -21,9 +21,6 @@ class Factbase::Prev < Factbase::TermBase
|
|
|
21
21
|
# @return [Object] The previous value
|
|
22
22
|
def evaluate(fact, maps, fb)
|
|
23
23
|
assert_args(1)
|
|
24
|
-
|
|
25
|
-
v = _values(0, fact, maps, fb)
|
|
26
|
-
@prev = v
|
|
27
|
-
before
|
|
24
|
+
@prev.tap { @prev = _values(0, fact, maps, fb) }
|
|
28
25
|
end
|
|
29
26
|
end
|
|
@@ -27,9 +27,9 @@ class Factbase::Sorted < Factbase::TermBase
|
|
|
27
27
|
def predict(maps, fb, params)
|
|
28
28
|
assert_args(2)
|
|
29
29
|
prop = @operands[0]
|
|
30
|
-
raise "A symbol is expected as first argument of 'sorted'" unless prop.is_a?(Symbol)
|
|
30
|
+
raise(ArgumentError, "A symbol is expected as first argument of 'sorted'") unless prop.is_a?(Symbol)
|
|
31
31
|
term = @operands[1]
|
|
32
|
-
raise "A term is expected, but '#{term}' provided" unless term.is_a?(Factbase::Term)
|
|
32
|
+
raise(ArgumentError, "A term is expected, but '#{term}' provided") unless term.is_a?(Factbase::Term)
|
|
33
33
|
fb.query(term, maps).each(fb, params).to_a
|
|
34
34
|
.reject { |m| m[prop].nil? }
|
|
35
35
|
.sort_by { |m| m[prop].first }
|
|
@@ -22,9 +22,10 @@ class Factbase::Sprintf < Factbase::TermBase
|
|
|
22
22
|
# @param [Factbase] fb Factbase to use for sub-queries
|
|
23
23
|
# @return [String] The formatted string
|
|
24
24
|
def evaluate(fact, maps, fb)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
formatted(
|
|
26
|
+
_values(0, fact, maps, fb)[0],
|
|
27
|
+
(1..(@operands.length - 1)).map { |i| _values(i, fact, maps, fb)&.first }
|
|
28
|
+
)
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
private
|
|
@@ -32,6 +33,6 @@ class Factbase::Sprintf < Factbase::TermBase
|
|
|
32
33
|
def formatted(fmt, ops)
|
|
33
34
|
format(*([fmt] + ops))
|
|
34
35
|
rescue ArgumentError => e
|
|
35
|
-
raise "Cannot format #{ops.inspect} with '#{fmt}' in (sprintf ...): #{e.message}"
|
|
36
|
+
raise(RuntimeError, "Cannot format #{ops.inspect} with '#{fmt}' in (sprintf ...): #{e.message}")
|
|
36
37
|
end
|
|
37
38
|
end
|
data/lib/factbase/terms/sum.rb
CHANGED
|
@@ -23,7 +23,7 @@ class Factbase::Sum < Factbase::TermBase
|
|
|
23
23
|
# @return [Integer] The sum of values for the specified key across all maps
|
|
24
24
|
def evaluate(_fact, maps, _fb)
|
|
25
25
|
k = @operands[0]
|
|
26
|
-
raise "A symbol is expected, but '#{k}' provided" unless k.is_a?(Symbol)
|
|
26
|
+
raise(ArgumentError, "A symbol is expected, but '#{k}' provided") unless k.is_a?(Symbol)
|
|
27
27
|
sum = 0
|
|
28
28
|
maps.each do |m|
|
|
29
29
|
vv = m[k.to_s]
|
|
@@ -22,7 +22,7 @@ class Factbase::ToTime < Factbase::TermBase
|
|
|
22
22
|
def evaluate(fact, maps, fb)
|
|
23
23
|
assert_args(1)
|
|
24
24
|
vv = _values(0, fact, maps, fb)
|
|
25
|
-
return
|
|
25
|
+
return if vv.nil?
|
|
26
26
|
parse(vv[0])
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -31,6 +31,6 @@ class Factbase::ToTime < Factbase::TermBase
|
|
|
31
31
|
def parse(value)
|
|
32
32
|
Time.parse(value.to_s)
|
|
33
33
|
rescue ArgumentError => e
|
|
34
|
-
raise "Cannot parse '#{value}' as Time in (to_time ...): #{e.message}"
|
|
34
|
+
raise(RuntimeError, "Cannot parse '#{value}' as Time in (to_time ...): #{e.message}")
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -25,9 +25,9 @@ class Factbase::Traced < Factbase::TermBase
|
|
|
25
25
|
def evaluate(fact, maps, fb)
|
|
26
26
|
assert_args(1)
|
|
27
27
|
t = @operands[0]
|
|
28
|
-
raise "A term is expected, but '#{t}' provided" unless t.is_a?(Factbase::Term)
|
|
28
|
+
raise(ArgumentError, "A term is expected, but '#{t}' provided") unless t.is_a?(Factbase::Term)
|
|
29
29
|
r = t.evaluate(fact, maps, fb)
|
|
30
|
-
puts
|
|
30
|
+
puts("#{self} -> #{r}") # rubocop:disable Lint/Debugger
|
|
31
31
|
r
|
|
32
32
|
end
|
|
33
33
|
end
|
data/lib/factbase/terms/undef.rb
CHANGED
|
@@ -24,9 +24,9 @@ class Factbase::Undef < Factbase::TermBase
|
|
|
24
24
|
def evaluate(_fact, _maps, _fb)
|
|
25
25
|
assert_args(1)
|
|
26
26
|
fn = @operands[0]
|
|
27
|
-
raise "A symbol expected as first argument of 'undef'" unless fn.is_a?(Symbol)
|
|
27
|
+
raise(ArgumentError, "A symbol expected as first argument of 'undef'") unless fn.is_a?(Symbol)
|
|
28
28
|
if Factbase::Term.private_method_defined?(fn, false)
|
|
29
|
-
Factbase::Term.class_eval("undef :#{fn}", __FILE__, __LINE__ - 1)
|
|
29
|
+
Factbase::Term.class_eval("undef :#{fn}", __FILE__, __LINE__ - 1)
|
|
30
30
|
end
|
|
31
31
|
true
|
|
32
32
|
end
|
|
@@ -21,14 +21,10 @@ class Factbase::Unique < Factbase::TermBase
|
|
|
21
21
|
# @return [Boolean] True if the value is unique, false otherwise
|
|
22
22
|
def evaluate(fact, maps, fb)
|
|
23
23
|
@seen = Set.new if @seen.nil?
|
|
24
|
-
raise "Too few operands for 'unique' (at least 1 expected)" if @operands.empty?
|
|
24
|
+
raise(ArgumentError, "Too few operands for 'unique' (at least 1 expected)") if @operands.empty?
|
|
25
25
|
vv = (0..(@operands.size - 1)).map { |i| _values(i, fact, maps, fb) }
|
|
26
26
|
return false if vv.any?(nil)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
pass = false if @seen.include?(t)
|
|
30
|
-
@seen << t
|
|
31
|
-
end
|
|
32
|
-
pass
|
|
27
|
+
tuples = Enumerator.product(*vv).to_a
|
|
28
|
+
tuples.none? { |t| @seen.include?(t) }.tap { tuples.each { |t| @seen << t } }
|
|
33
29
|
end
|
|
34
30
|
end
|
data/lib/factbase/to_json.rb
CHANGED
|
@@ -28,6 +28,6 @@ class Factbase::ToJSON
|
|
|
28
28
|
# Convert the entire factbase into JSON.
|
|
29
29
|
# @return [String] The factbase in JSON format
|
|
30
30
|
def json
|
|
31
|
-
Factbase::Flatten.new(
|
|
31
|
+
Factbase::Flatten.new(@fb.each.to_a, @sorter).it.to_json
|
|
32
32
|
end
|
|
33
33
|
end
|
data/lib/factbase/to_xml.rb
CHANGED
|
@@ -29,24 +29,20 @@ class Factbase::ToXML
|
|
|
29
29
|
# Convert the entire factbase into XML.
|
|
30
30
|
# @return [String] The factbase in XML format
|
|
31
31
|
def xml
|
|
32
|
-
|
|
33
|
-
meta = {
|
|
34
|
-
version: Factbase::VERSION,
|
|
35
|
-
size: bytes.size
|
|
36
|
-
}
|
|
32
|
+
meta = { version: Factbase::VERSION, size: @fb.export.size }
|
|
37
33
|
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
|
38
34
|
xml.fb(meta) do
|
|
39
|
-
Factbase::Flatten.new(
|
|
35
|
+
Factbase::Flatten.new(@fb.each.to_a, @sorter).it.each do |m|
|
|
40
36
|
xml.f_ do
|
|
41
37
|
m.sort.to_h.each do |k, vv|
|
|
42
38
|
if vv.is_a?(Array)
|
|
43
|
-
xml.
|
|
39
|
+
xml.__send__(:"#{k}_") do
|
|
44
40
|
vv.each do |v|
|
|
45
|
-
xml.
|
|
41
|
+
xml.__send__(:v, to_str(v), t: type_of(v))
|
|
46
42
|
end
|
|
47
43
|
end
|
|
48
44
|
else
|
|
49
|
-
xml.
|
|
45
|
+
xml.__send__(:"#{k}_", to_str(vv), t: type_of(vv))
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
end
|
data/lib/factbase/to_yaml.rb
CHANGED
|
@@ -28,6 +28,6 @@ class Factbase::ToYAML
|
|
|
28
28
|
# Convert the entire factbase into YAML.
|
|
29
29
|
# @return [String] The factbase in YAML format
|
|
30
30
|
def yaml
|
|
31
|
-
YAML.dump(Factbase::Flatten.new(
|
|
31
|
+
YAML.dump(Factbase::Flatten.new(@fb.each.to_a, @sorter).it)
|
|
32
32
|
end
|
|
33
33
|
end
|
data/lib/factbase/version.rb
CHANGED
|
@@ -8,6 +8,5 @@
|
|
|
8
8
|
# Copyright:: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
9
9
|
# License:: MIT
|
|
10
10
|
class Factbase
|
|
11
|
-
|
|
12
|
-
VERSION = '0.19.11' unless const_defined?(:VERSION)
|
|
11
|
+
VERSION = '0.19.12' unless const_defined?(:VERSION)
|
|
13
12
|
end
|
data/lib/factbase.rb
CHANGED
|
@@ -98,6 +98,13 @@ class Factbase
|
|
|
98
98
|
@maps.size
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
# Iterate over all facts yielding plain hashes.
|
|
102
|
+
# @yieldparam [Hash] fact Each fact as a plain Hash
|
|
103
|
+
# @return [Integer, Enumerator] Total number of facts or Enumerator
|
|
104
|
+
def each(&)
|
|
105
|
+
@maps.each(&)
|
|
106
|
+
end
|
|
107
|
+
|
|
101
108
|
# Insert a new fact and return it.
|
|
102
109
|
#
|
|
103
110
|
# A fact, when inserted, is empty. It doesn't contain any properties.
|
|
@@ -106,7 +113,7 @@ class Factbase
|
|
|
106
113
|
def insert
|
|
107
114
|
map = {}
|
|
108
115
|
@maps << map
|
|
109
|
-
require_relative
|
|
116
|
+
require_relative('factbase/fact')
|
|
110
117
|
Factbase::Fact.new(map)
|
|
111
118
|
end
|
|
112
119
|
|
|
@@ -132,7 +139,7 @@ class Factbase
|
|
|
132
139
|
def query(term, maps = nil)
|
|
133
140
|
maps ||= @maps
|
|
134
141
|
term = to_term(term) if term.is_a?(String)
|
|
135
|
-
require_relative
|
|
142
|
+
require_relative('factbase/query')
|
|
136
143
|
Factbase::Query.new(maps, term, self)
|
|
137
144
|
end
|
|
138
145
|
|
|
@@ -140,7 +147,7 @@ class Factbase
|
|
|
140
147
|
# @param [String] query The query to convert
|
|
141
148
|
# @return [Factbase::Term] The term
|
|
142
149
|
def to_term(query)
|
|
143
|
-
require_relative
|
|
150
|
+
require_relative('factbase/syntax')
|
|
144
151
|
Factbase::Syntax.new(query).to_term
|
|
145
152
|
end
|
|
146
153
|
|
|
@@ -161,15 +168,15 @@ class Factbase
|
|
|
161
168
|
#
|
|
162
169
|
# @return [Factbase::Churn] How many facts have been changed (zero if rolled back)
|
|
163
170
|
def txn
|
|
164
|
-
require_relative
|
|
171
|
+
require_relative('factbase/lazy_taped')
|
|
165
172
|
taped = Factbase::LazyTaped.new(@maps)
|
|
166
|
-
require_relative
|
|
173
|
+
require_relative('factbase/churn')
|
|
167
174
|
churn = Factbase::Churn.new
|
|
168
|
-
catch
|
|
169
|
-
require_relative
|
|
175
|
+
catch(:commit) do
|
|
176
|
+
require_relative('factbase/light')
|
|
170
177
|
commit = false
|
|
171
|
-
catch
|
|
172
|
-
yield
|
|
178
|
+
catch(:rollback) do
|
|
179
|
+
yield(Factbase::Light.new(Factbase.new(taped)))
|
|
173
180
|
commit = true
|
|
174
181
|
end
|
|
175
182
|
return churn unless commit
|
|
@@ -233,9 +240,19 @@ class Factbase
|
|
|
233
240
|
# This method supports both the original format (Array of maps) and
|
|
234
241
|
# the IndexedFactbase format (Hash with :maps and :idx keys).
|
|
235
242
|
#
|
|
243
|
+
# SECURITY: the input must come from a source you trust, because it is
|
|
244
|
+
# deserialized with +Marshal.load+. Loading a +Marshal+ stream crafted
|
|
245
|
+
# by an attacker can execute arbitrary code in the calling process,
|
|
246
|
+
# so never call +import+ on bytes received over the network, read from
|
|
247
|
+
# a user-supplied path, or pulled from any other untrusted channel
|
|
248
|
+
# without an out-of-band integrity check. See the official Ruby
|
|
249
|
+
# security notes for +Marshal.load+ at
|
|
250
|
+
# https://docs.ruby-lang.org/en/3.3/security_rdoc.html#label-Marshal.load
|
|
251
|
+
# for details.
|
|
252
|
+
#
|
|
236
253
|
# @param [String] bytes Binary string to import
|
|
237
254
|
def import(bytes)
|
|
238
|
-
raise 'Empty input, cannot load a factbase' if bytes.empty?
|
|
255
|
+
raise(StandardError, 'Empty input, cannot load a factbase') if bytes.empty?
|
|
239
256
|
data = Marshal.load(bytes)
|
|
240
257
|
@maps +=
|
|
241
258
|
if data.is_a?(Hash) && data.key?(:maps)
|
data/lib/fuzz.rb
CHANGED
|
@@ -36,18 +36,18 @@ class Factbase::Fuzz
|
|
|
36
36
|
def initialize
|
|
37
37
|
@next_num = 0
|
|
38
38
|
@max_comments = 10
|
|
39
|
-
raise 'Not enough messages for fuzzing' if MESSAGES.size < @max_comments
|
|
39
|
+
raise(StandardError, 'Not enough messages for fuzzing') if MESSAGES.size < @max_comments
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def self.make(count = 1000)
|
|
43
|
-
raise "Count must be positive: #{count}" if count.negative?
|
|
43
|
+
raise(ArgumentError, "Count must be positive: #{count}") if count.negative?
|
|
44
44
|
fb = Factbase.new
|
|
45
45
|
Factbase::Fuzz.new.feed(fb, count)
|
|
46
46
|
fb
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def feed(fb, count = 1)
|
|
50
|
-
raise "Count must be positive: #{count}" if count.negative?
|
|
50
|
+
raise(ArgumentError, "Count must be positive: #{count}") if count.negative?
|
|
51
51
|
count.times do
|
|
52
52
|
pull_request(fb, @next_num += 1)
|
|
53
53
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: factbase
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.19.
|
|
4
|
+
version: 0.19.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
@@ -187,7 +187,9 @@ files:
|
|
|
187
187
|
- lib/factbase/indexed/indexed_fact.rb
|
|
188
188
|
- lib/factbase/indexed/indexed_factbase.rb
|
|
189
189
|
- lib/factbase/indexed/indexed_gt.rb
|
|
190
|
+
- lib/factbase/indexed/indexed_gte.rb
|
|
190
191
|
- lib/factbase/indexed/indexed_lt.rb
|
|
192
|
+
- lib/factbase/indexed/indexed_lte.rb
|
|
191
193
|
- lib/factbase/indexed/indexed_not.rb
|
|
192
194
|
- lib/factbase/indexed/indexed_one.rb
|
|
193
195
|
- lib/factbase/indexed/indexed_or.rb
|