factbase 0.0.46 → 0.0.48
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/README.md +2 -2
- data/lib/factbase/fact.rb +4 -5
- data/lib/factbase/flatten.rb +45 -0
- data/lib/factbase/looged.rb +2 -2
- data/lib/factbase/term.rb +1 -0
- data/lib/factbase/to_json.rb +2 -2
- data/lib/factbase/to_xml.rb +2 -2
- data/lib/factbase/to_yaml.rb +2 -2
- data/lib/factbase.rb +6 -6
- data/test/factbase/test_fact.rb +12 -1
- data/test/factbase/test_flatten.rb +39 -0
- data/test/factbase/test_looged.rb +9 -0
- data/test/factbase/test_query.rb +2 -1
- data/test/factbase/test_term.rb +1 -0
- data/test/factbase/test_to_yaml.rb +3 -3
- data/test/test_factbase.rb +48 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56a6a221e2344538c324a601f49ad655f4d5e3b6682b5e717e8f798a6eb46030
|
4
|
+
data.tar.gz: 94bb595173fbea968c4a8e8af2b8d6cf08689127e2dfd2c2c296420659da5304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe4eb95604ae3ba22d24ef01a4c86b1dcdf4c9b3ff38969cbc459653a6a72a201d317bdf86f71c22206c771deebb5511ba1c64ce014c77fdf995e18926646fa2
|
7
|
+
data.tar.gz: b48c9c7243f74713bcf5b9fbad3f0ef901aa79d107d7be78e3d08d9970e898a21f9bb4938cfaac5057edc11c53150b0934a46b125019c132906114a702c90d89
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Single-Table NoSQL In-Memory Database
|
1
|
+
# Single-Table NoSQL-ish In-Memory Database
|
2
2
|
|
3
3
|
[](http://www.rultor.com/p/yegor256/factbase)
|
4
4
|
[](https://www.jetbrains.com/ruby/)
|
@@ -18,7 +18,7 @@ It is possible to delete a fact, but impossible to delete a property
|
|
18
18
|
from a fact.
|
19
19
|
|
20
20
|
**ATTENTION**: The current implemention is naive and,
|
21
|
-
because of that, very slow
|
21
|
+
because of that, **very slow**. I will be very happy
|
22
22
|
if you suggest a better implementation without the change of the interface.
|
23
23
|
The `Factbase::query()` method is what mostly needs performance optimization:
|
24
24
|
currently it simply iterates through all facts in the factbase in order
|
data/lib/factbase/fact.rb
CHANGED
@@ -72,12 +72,11 @@ class Factbase::Fact
|
|
72
72
|
before = @map[kk]
|
73
73
|
return if before == v
|
74
74
|
if before.nil?
|
75
|
-
@map[kk] = v
|
76
|
-
|
75
|
+
@map[kk] = [v]
|
76
|
+
else
|
77
|
+
@map[kk] << v
|
78
|
+
@map[kk].uniq!
|
77
79
|
end
|
78
|
-
@map[kk] = [@map[kk]] unless @map[kk].is_a?(Array)
|
79
|
-
@map[kk] << v
|
80
|
-
@map[kk].uniq!
|
81
80
|
end
|
82
81
|
nil
|
83
82
|
elsif k == '[]'
|
@@ -0,0 +1,45 @@
|
|
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 '../factbase'
|
24
|
+
|
25
|
+
# Make maps suitable for printing.
|
26
|
+
#
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
class Factbase::Flatten
|
31
|
+
# Constructor.
|
32
|
+
def initialize(maps, sorter = '_id')
|
33
|
+
@maps = maps
|
34
|
+
@sorter = sorter
|
35
|
+
end
|
36
|
+
|
37
|
+
# Improve the maps.
|
38
|
+
# @return [Array<HashMap>] The hashmaps, but improved
|
39
|
+
def it
|
40
|
+
@maps
|
41
|
+
.sort_by { |m| m[@sorter] }
|
42
|
+
.map { |m| m.sort.to_h }
|
43
|
+
.map { |m| m.transform_values { |v| v.size == 1 ? v[0] : v } }
|
44
|
+
end
|
45
|
+
end
|
data/lib/factbase/looged.rb
CHANGED
@@ -55,9 +55,9 @@ class Factbase::Looged
|
|
55
55
|
def txn(this = self, &)
|
56
56
|
before = @fb.size
|
57
57
|
tail = nil
|
58
|
-
r = @fb.txn(this) do |
|
58
|
+
r = @fb.txn(this) do |fbt|
|
59
59
|
tail = Factbase::Looged.elapsed do
|
60
|
-
yield
|
60
|
+
yield fbt
|
61
61
|
end
|
62
62
|
end
|
63
63
|
@loog.debug("Txn #{r ? 'modified' : 'didn\'t touch'} #{before} facts #{tail}")
|
data/lib/factbase/term.rb
CHANGED
data/lib/factbase/to_json.rb
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'json'
|
24
24
|
require_relative '../factbase'
|
25
|
+
require_relative '../factbase/flatten'
|
25
26
|
|
26
27
|
# Factbase to JSON converter.
|
27
28
|
#
|
@@ -44,7 +45,6 @@ class Factbase::ToJSON
|
|
44
45
|
# Convert the entire factbase into JSON.
|
45
46
|
# @return [String] The factbase in JSON format
|
46
47
|
def json
|
47
|
-
|
48
|
-
maps.sort_by { |m| m[@sorter] }.map { |m| m.sort.to_h }.to_json
|
48
|
+
Factbase::Flatten.new(Marshal.load(@fb.export), @sorter).it.to_json
|
49
49
|
end
|
50
50
|
end
|
data/lib/factbase/to_xml.rb
CHANGED
@@ -23,6 +23,7 @@
|
|
23
23
|
require 'nokogiri'
|
24
24
|
require 'time'
|
25
25
|
require_relative '../factbase'
|
26
|
+
require_relative '../factbase/flatten'
|
26
27
|
|
27
28
|
# Factbase to XML converter.
|
28
29
|
#
|
@@ -46,14 +47,13 @@ class Factbase::ToXML
|
|
46
47
|
# @return [String] The factbase in XML format
|
47
48
|
def xml
|
48
49
|
bytes = @fb.export
|
49
|
-
maps = Marshal.load(bytes)
|
50
50
|
meta = {
|
51
51
|
version: Factbase::VERSION,
|
52
52
|
size: bytes.size
|
53
53
|
}
|
54
54
|
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
55
55
|
xml.fb(meta) do
|
56
|
-
|
56
|
+
Factbase::Flatten.new(Marshal.load(bytes), @sorter).it.each do |m|
|
57
57
|
xml.f_ do
|
58
58
|
m.sort.to_h.each do |k, vv|
|
59
59
|
if vv.is_a?(Array)
|
data/lib/factbase/to_yaml.rb
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'yaml'
|
24
24
|
require_relative '../factbase'
|
25
|
+
require_relative '../factbase/flatten'
|
25
26
|
|
26
27
|
# Factbase to YAML converter.
|
27
28
|
#
|
@@ -44,7 +45,6 @@ class Factbase::ToYAML
|
|
44
45
|
# Convert the entire factbase into YAML.
|
45
46
|
# @return [String] The factbase in YAML format
|
46
47
|
def yaml
|
47
|
-
|
48
|
-
YAML.dump({ 'facts' => maps.sort_by { |m| m[@sorter] }.map { |m| m.sort.to_h } })
|
48
|
+
YAML.dump(Factbase::Flatten.new(Marshal.load(@fb.export), @sorter).it)
|
49
49
|
end
|
50
50
|
end
|
data/lib/factbase.rb
CHANGED
@@ -79,7 +79,7 @@ require 'yaml'
|
|
79
79
|
# License:: MIT
|
80
80
|
class Factbase
|
81
81
|
# Current version of the gem (changed by .rultor.yml on every release)
|
82
|
-
VERSION = '0.0.
|
82
|
+
VERSION = '0.0.48'
|
83
83
|
|
84
84
|
# An exception that may be thrown in a transaction, to roll it back.
|
85
85
|
class Rollback < StandardError; end
|
@@ -91,10 +91,10 @@ class Factbase
|
|
91
91
|
@mutex = Mutex.new
|
92
92
|
end
|
93
93
|
|
94
|
-
# Make a duplicate of this factbase.
|
94
|
+
# Make a deep duplicate of this factbase.
|
95
95
|
# @return [Factbase] A new factbase
|
96
96
|
def dup
|
97
|
-
Factbase.new(@maps.dup)
|
97
|
+
Factbase.new(@maps.map { |m| m.transform_values(&:dup) })
|
98
98
|
end
|
99
99
|
|
100
100
|
# Size.
|
@@ -175,9 +175,9 @@ class Factbase
|
|
175
175
|
@maps << {}
|
176
176
|
modified = true
|
177
177
|
end
|
178
|
-
m.each do |k,
|
179
|
-
next if @maps[i][k] ==
|
180
|
-
@maps[i][k] =
|
178
|
+
m.each do |k, vv|
|
179
|
+
next if @maps[i][k] == vv
|
180
|
+
@maps[i][k] = vv
|
181
181
|
modified = true
|
182
182
|
end
|
183
183
|
end
|
data/test/factbase/test_fact.rb
CHANGED
@@ -29,6 +29,17 @@ require_relative '../../lib/factbase/fact'
|
|
29
29
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
30
|
# License:: MIT
|
31
31
|
class TestFact < Minitest::Test
|
32
|
+
def test_injects_data_correctly
|
33
|
+
map = {}
|
34
|
+
f = Factbase::Fact.new(Mutex.new, map)
|
35
|
+
f.foo = 1
|
36
|
+
f.bar = 2
|
37
|
+
f.bar = 3
|
38
|
+
assert_equal(2, map.size)
|
39
|
+
assert_equal([1], map['foo'])
|
40
|
+
assert_equal([2, 3], map['bar'])
|
41
|
+
end
|
42
|
+
|
32
43
|
def test_simple_resetting
|
33
44
|
map = {}
|
34
45
|
f = Factbase::Fact.new(Mutex.new, map)
|
@@ -89,7 +100,7 @@ class TestFact < Minitest::Test
|
|
89
100
|
f = Factbase::Fact.new(Mutex.new, map)
|
90
101
|
f.foo = 42
|
91
102
|
f.foo = 42
|
92
|
-
assert_equal(42, map['foo'])
|
103
|
+
assert_equal([42], map['foo'])
|
93
104
|
end
|
94
105
|
|
95
106
|
def test_time_in_utc
|
@@ -0,0 +1,39 @@
|
|
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 'minitest/autorun'
|
24
|
+
require_relative '../../lib/factbase'
|
25
|
+
require_relative '../../lib/factbase/flatten'
|
26
|
+
|
27
|
+
# Test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestFlatten < Minitest::Test
|
32
|
+
def test_mapping
|
33
|
+
maps = [{ 'b' => [42] }, { 'a' => 33 }, { 'c' => %w[hey you] }]
|
34
|
+
to = Factbase::Flatten.new(maps).it
|
35
|
+
assert(33, to[0]['a'])
|
36
|
+
assert(42, to[1]['b'])
|
37
|
+
assert(2, to[2]['c'].size)
|
38
|
+
end
|
39
|
+
end
|
@@ -57,6 +57,15 @@ class TestLooged < Minitest::Test
|
|
57
57
|
assert(log.to_s.include?('modified'), log)
|
58
58
|
end
|
59
59
|
|
60
|
+
def test_with_modifying_txn
|
61
|
+
log = Loog::Buffer.new
|
62
|
+
fb = Factbase::Looged.new(Factbase.new, log)
|
63
|
+
fb.insert.foo = 1
|
64
|
+
assert(!fb.txn { |fbt| fbt.query('(always)').each.to_a }, log)
|
65
|
+
assert(fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 }, log)
|
66
|
+
assert(log.to_s.include?('modified'), log)
|
67
|
+
end
|
68
|
+
|
60
69
|
def test_with_empty_txn
|
61
70
|
log = Loog::Buffer.new
|
62
71
|
fb = Factbase::Looged.new(Factbase.new, log)
|
data/test/factbase/test_query.rb
CHANGED
@@ -46,7 +46,7 @@ class TestQuery < Minitest::Test
|
|
46
46
|
maps = []
|
47
47
|
maps << { 'num' => 42, 'name' => 'Jeff' }
|
48
48
|
maps << { 'pi' => 3.14, 'num' => [42, 66, 0], 'name' => 'peter' }
|
49
|
-
maps << { 'time' => Time.now - 100, 'num' => 0 }
|
49
|
+
maps << { 'time' => Time.now - 100, 'num' => 0, 'hi' => [4] }
|
50
50
|
{
|
51
51
|
'(eq num 444)' => 0,
|
52
52
|
'(eq time 0)' => 0,
|
@@ -56,6 +56,7 @@ class TestQuery < Minitest::Test
|
|
56
56
|
'(eq pi +3.14)' => 1,
|
57
57
|
'(not (exists hello))' => 3,
|
58
58
|
'(eq "Integer" (type num))' => 2,
|
59
|
+
'(eq "Integer" (type hi))' => 1,
|
59
60
|
'(when (eq num 0) (exists time))' => 2,
|
60
61
|
'(unique num)' => 2,
|
61
62
|
'(unique name)' => 2,
|
data/test/factbase/test_term.rb
CHANGED
@@ -120,6 +120,7 @@ class TestTerm < Minitest::Test
|
|
120
120
|
def test_type_matching
|
121
121
|
t = Factbase::Term.new(:type, [:foo])
|
122
122
|
assert_equal('Integer', t.evaluate(fact('foo' => 42), []))
|
123
|
+
assert_equal('Integer', t.evaluate(fact('foo' => [42]), []))
|
123
124
|
assert_equal('Array', t.evaluate(fact('foo' => [1, 2, 3]), []))
|
124
125
|
assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), []))
|
125
126
|
assert_equal('Float', t.evaluate(fact('foo' => 3.14), []))
|
@@ -39,9 +39,9 @@ class TestToYAML < Minitest::Test
|
|
39
39
|
fb.insert._id = 2
|
40
40
|
to = Factbase::ToYAML.new(fb)
|
41
41
|
yaml = YAML.load(to.yaml)
|
42
|
-
assert_equal(2, yaml
|
43
|
-
assert_equal(42, yaml[
|
44
|
-
assert_equal(256, yaml[
|
42
|
+
assert_equal(2, yaml.size)
|
43
|
+
assert_equal(42, yaml[0]['foo'][0])
|
44
|
+
assert_equal(256, yaml[0]['foo'][1])
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_sorts_keys
|
data/test/test_factbase.rb
CHANGED
@@ -23,12 +23,31 @@
|
|
23
23
|
require 'minitest/autorun'
|
24
24
|
require 'loog'
|
25
25
|
require_relative '../lib/factbase'
|
26
|
+
require_relative '../lib/factbase/rules'
|
27
|
+
require_relative '../lib/factbase/inv'
|
28
|
+
require_relative '../lib/factbase/pre'
|
29
|
+
require_relative '../lib/factbase/looged'
|
26
30
|
|
27
31
|
# Factbase main module test.
|
28
32
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
33
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
30
34
|
# License:: MIT
|
31
35
|
class TestFactbase < Minitest::Test
|
36
|
+
def test_injects_data_correctly
|
37
|
+
maps = []
|
38
|
+
fb = Factbase.new(maps)
|
39
|
+
fb.insert
|
40
|
+
f = fb.insert
|
41
|
+
f.foo = 1
|
42
|
+
f.bar = 2
|
43
|
+
f.bar = 3
|
44
|
+
assert_equal(2, maps.size)
|
45
|
+
assert_equal(0, maps[0].size)
|
46
|
+
assert_equal(2, maps[1].size)
|
47
|
+
assert_equal([1], maps[1]['foo'])
|
48
|
+
assert_equal([2, 3], maps[1]['bar'])
|
49
|
+
end
|
50
|
+
|
32
51
|
def test_simple_setting
|
33
52
|
fb = Factbase.new
|
34
53
|
fb.insert
|
@@ -44,6 +63,22 @@ class TestFactbase < Minitest::Test
|
|
44
63
|
assert_equal(2, fb.size)
|
45
64
|
end
|
46
65
|
|
66
|
+
def test_modify_via_query
|
67
|
+
fb = Factbase.new
|
68
|
+
fb.insert.bar = 1
|
69
|
+
fb.query('(exists bar)').each do |f|
|
70
|
+
f.bar = 42
|
71
|
+
assert_equal([1, 42], f['bar'])
|
72
|
+
end
|
73
|
+
found = 0
|
74
|
+
fb.query('(always)').each do |f|
|
75
|
+
assert_equal([1, 42], f['bar'])
|
76
|
+
found += 1
|
77
|
+
end
|
78
|
+
assert_equal(1, found)
|
79
|
+
assert_equal([1, 42], fb.query('(always)').each.to_a[0]['bar'])
|
80
|
+
end
|
81
|
+
|
47
82
|
def test_serialize_and_deserialize
|
48
83
|
f1 = Factbase.new
|
49
84
|
f2 = Factbase.new
|
@@ -78,6 +113,8 @@ class TestFactbase < Minitest::Test
|
|
78
113
|
assert(fb.txn(&:insert).is_a?(TrueClass))
|
79
114
|
assert(fb.txn { |fbt| fbt.insert.bar = 42 })
|
80
115
|
assert(!fb.txn { |fbt| fbt.query('(always)').each.to_a })
|
116
|
+
assert(fb.txn { |fbt| fbt.query('(always)').each { |f| f.hello = 33 } })
|
117
|
+
assert(fb.txn { |fbt| fbt.query('(always)').each.to_a[0].zzz = 33 })
|
81
118
|
end
|
82
119
|
|
83
120
|
def test_run_txn
|
@@ -98,6 +135,17 @@ class TestFactbase < Minitest::Test
|
|
98
135
|
assert_equal(2, fb.size)
|
99
136
|
end
|
100
137
|
|
138
|
+
def test_run_txn_via_query
|
139
|
+
fb = Factbase.new
|
140
|
+
fb.insert.foo = 1
|
141
|
+
assert(
|
142
|
+
fb.txn do |fbt|
|
143
|
+
fbt.query('(always)').each { |f| f.foo = 42 }
|
144
|
+
end
|
145
|
+
)
|
146
|
+
assert_equal([1, 42], fb.query('(always)').each.to_a[0]['foo'])
|
147
|
+
end
|
148
|
+
|
101
149
|
def test_run_txn_with_inv
|
102
150
|
fb = Factbase::Inv.new(Factbase.new) { |_p, v| throw 'oops' if v == 42 }
|
103
151
|
fb.insert.bar = 3
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.48
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- factbase.gemspec
|
103
103
|
- lib/factbase.rb
|
104
104
|
- lib/factbase/fact.rb
|
105
|
+
- lib/factbase/flatten.rb
|
105
106
|
- lib/factbase/inv.rb
|
106
107
|
- lib/factbase/looged.rb
|
107
108
|
- lib/factbase/pre.rb
|
@@ -115,6 +116,7 @@ files:
|
|
115
116
|
- lib/factbase/tuples.rb
|
116
117
|
- renovate.json
|
117
118
|
- test/factbase/test_fact.rb
|
119
|
+
- test/factbase/test_flatten.rb
|
118
120
|
- test/factbase/test_inv.rb
|
119
121
|
- test/factbase/test_looged.rb
|
120
122
|
- test/factbase/test_pre.rb
|