perobs 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/Rakefile +2 -4
- data/lib/perobs/Array.rb +58 -108
- data/lib/perobs/BTreeDB.rb +1 -1
- data/lib/perobs/Cache.rb +12 -0
- data/lib/perobs/Delegator.rb +78 -0
- data/lib/perobs/DynamoDB.rb +1 -1
- data/lib/perobs/Hash.rb +56 -110
- data/lib/perobs/Object.rb +35 -19
- data/lib/perobs/ObjectBase.rb +82 -28
- data/lib/perobs/Store.rb +75 -9
- data/lib/perobs/version.rb +1 -1
- data/tasks/test.rake +2 -1
- data/test/Array_spec.rb +208 -0
- data/{spec → test}/BTreeDB_spec.rb +23 -23
- data/{spec → test}/ClassMap_spec.rb +15 -15
- data/test/Hash_spec.rb +157 -0
- data/{spec → test}/Object_spec.rb +53 -28
- data/{spec → test}/Store_spec.rb +135 -129
- data/{spec → test}/perobs_spec.rb +44 -47
- data/{spec/Array_spec.rb → test/spec_helper.rb} +9 -61
- metadata +29 -26
- data/spec/Hash_spec.rb +0 -96
@@ -40,20 +40,20 @@ describe PEROBS::BTreeDB do
|
|
40
40
|
|
41
41
|
it 'should create database' do
|
42
42
|
@db = PEROBS::BTreeDB.new('fs_test')
|
43
|
-
Dir.exists?('fs_test').
|
43
|
+
expect(Dir.exists?('fs_test')).to be true
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should write and read a simple Hash' do
|
47
47
|
@db = PEROBS::BTreeDB.new('fs_test')
|
48
|
-
@db.get_hash('test').
|
48
|
+
expect(@db.get_hash('test')).to eq({})
|
49
49
|
h = { 'A' => 1, 'B' => 2, 'D' => 4 }
|
50
50
|
@db.put_hash('test', h)
|
51
|
-
@db.get_hash('test').
|
51
|
+
expect(@db.get_hash('test')).to eq(h)
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should support object insertion and retrieval' do
|
55
55
|
@db = PEROBS::BTreeDB.new('fs_test')
|
56
|
-
@db.include?(0).
|
56
|
+
expect(@db.include?(0)).to be false
|
57
57
|
h = {
|
58
58
|
'String' => 'What god has wrought',
|
59
59
|
'Fixnum' => 42,
|
@@ -64,15 +64,15 @@ describe PEROBS::BTreeDB do
|
|
64
64
|
'Array' => [ 0, 1, 2, 3 ]
|
65
65
|
}
|
66
66
|
@db.put_object(h, 0)
|
67
|
-
@db.include?(0).
|
68
|
-
@db.check(0, false).
|
69
|
-
@db.get_object(0).
|
67
|
+
expect(@db.include?(0)).to be true
|
68
|
+
expect(@db.check(0, false)).to be true
|
69
|
+
expect(@db.get_object(0)).to eq(h)
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'should support most Ruby objects types' do
|
73
73
|
[ :marshal, :yaml ].each do |serializer|
|
74
74
|
@db = PEROBS::BTreeDB.new('fs_test', { :serializer => serializer })
|
75
|
-
@db.include?(0).
|
75
|
+
expect(@db.include?(0)).to be false
|
76
76
|
h = {
|
77
77
|
'String' => 'What god has wrought',
|
78
78
|
'Fixnum' => 42,
|
@@ -85,9 +85,9 @@ describe PEROBS::BTreeDB do
|
|
85
85
|
'Struct' => UStruct.new("Where's", 'your', 'towel?')
|
86
86
|
}
|
87
87
|
@db.put_object(h, 0)
|
88
|
-
@db.include?(0).
|
89
|
-
@db.check(0, false).
|
90
|
-
@db.get_object(0).
|
88
|
+
expect(@db.include?(0)).to be true
|
89
|
+
expect(@db.check(0, false)).to be true
|
90
|
+
expect(@db.get_object(0)).to eq(h)
|
91
91
|
PEROBS::BTreeDB::delete_db('fs_test')
|
92
92
|
end
|
93
93
|
end
|
@@ -98,7 +98,7 @@ describe PEROBS::BTreeDB do
|
|
98
98
|
@db.put_object({ "foo #{i}" => i }, i)
|
99
99
|
end
|
100
100
|
0.upto(10) do |i|
|
101
|
-
@db.get_object(i)["foo #{i}"].
|
101
|
+
expect(@db.get_object(i)["foo #{i}"]).to eq(i)
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
@@ -119,12 +119,12 @@ describe PEROBS::BTreeDB do
|
|
119
119
|
@db.put_object({ 'C' => 'c' * 129 }, 6)
|
120
120
|
@db.put_object({ 'D' => 'd' * 1025 }, 7)
|
121
121
|
|
122
|
-
@db.get_object(0).
|
123
|
-
@db.get_object(2).
|
124
|
-
@db.get_object(4).
|
125
|
-
@db.get_object(5).
|
126
|
-
@db.get_object(6).
|
127
|
-
@db.get_object(7).
|
122
|
+
expect(@db.get_object(0)).to eq({ 'a' => 'a' * 257 })
|
123
|
+
expect(@db.get_object(2)).to eq({ 'c' => 'c' * 129 })
|
124
|
+
expect(@db.get_object(4)).to eq({ 'A' => 'a' * 257 })
|
125
|
+
expect(@db.get_object(5)).to eq({ 'B' => 'b' * 513 })
|
126
|
+
expect(@db.get_object(6)).to eq({ 'C' => 'c' * 129 })
|
127
|
+
expect(@db.get_object(7)).to eq({ 'D' => 'd' * 1025 })
|
128
128
|
end
|
129
129
|
|
130
130
|
it 'should mark objects and detect markings' do
|
@@ -133,14 +133,14 @@ describe PEROBS::BTreeDB do
|
|
133
133
|
@db.put_object(h, 1)
|
134
134
|
@db.put_object(h, 2)
|
135
135
|
@db.clear_marks
|
136
|
-
@db.is_marked?(1).
|
136
|
+
expect(@db.is_marked?(1)).to be false
|
137
137
|
@db.mark(1)
|
138
|
-
@db.is_marked?(1).
|
138
|
+
expect(@db.is_marked?(1)).to be true
|
139
139
|
|
140
|
-
@db.include?(2).
|
140
|
+
expect(@db.include?(2)).to be true
|
141
141
|
@db.delete_unmarked_objects
|
142
|
-
@db.include?(1).
|
143
|
-
@db.include?(2).
|
142
|
+
expect(@db.include?(1)).to be true
|
143
|
+
expect(@db.include?(2)).to be false
|
144
144
|
end
|
145
145
|
|
146
146
|
end
|
@@ -23,7 +23,7 @@
|
|
23
23
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
24
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
25
|
|
26
|
-
|
26
|
+
require 'spec_helper'
|
27
27
|
|
28
28
|
require 'perobs/ClassMap'
|
29
29
|
require 'perobs/BTreeDB'
|
@@ -31,40 +31,40 @@ require 'perobs/BTreeDB'
|
|
31
31
|
describe PEROBS::ClassMap do
|
32
32
|
|
33
33
|
before(:all) do
|
34
|
-
|
35
|
-
@db = PEROBS::BTreeDB.new(
|
34
|
+
@db_name = generate_db_name(__FILE__)
|
35
|
+
@db = PEROBS::BTreeDB.new(@db_name)
|
36
36
|
@map = PEROBS::ClassMap.new(@db)
|
37
37
|
end
|
38
38
|
|
39
39
|
after(:all) do
|
40
|
-
FileUtils.rm_rf(
|
40
|
+
FileUtils.rm_rf(@db_name)
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should return nil for an unknown ID' do
|
44
|
-
@map.id_to_class(0).
|
44
|
+
expect(@map.id_to_class(0)).to be_nil
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'should add a class' do
|
48
|
-
@map.class_to_id('Foo').
|
48
|
+
expect(@map.class_to_id('Foo')).to eq(0)
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'should find the class again' do
|
52
|
-
@map.id_to_class(0).
|
52
|
+
expect(@map.id_to_class(0)).to eq('Foo')
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'should still return nil for an unknown ID' do
|
56
|
-
@map.id_to_class(1).
|
56
|
+
expect(@map.id_to_class(1)).to be_nil
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'should forget classes not in keep list' do
|
60
|
-
@map.class_to_id('Bar').
|
61
|
-
@map.class_to_id('Foobar').
|
60
|
+
expect(@map.class_to_id('Bar')).to eq(1)
|
61
|
+
expect(@map.class_to_id('Foobar')).to eq(2)
|
62
62
|
@map.keep([ 'Bar' ])
|
63
|
-
@map.id_to_class(0).
|
64
|
-
@map.id_to_class(1).
|
65
|
-
@map.id_to_class(2).
|
66
|
-
@map.class_to_id('Foo1').
|
67
|
-
@map.class_to_id('Foo2').
|
63
|
+
expect(@map.id_to_class(0)).to be_nil
|
64
|
+
expect(@map.id_to_class(1)).to eq('Bar')
|
65
|
+
expect(@map.id_to_class(2)).to be_nil
|
66
|
+
expect(@map.class_to_id('Foo1')).to eq(0)
|
67
|
+
expect(@map.class_to_id('Foo2')).to eq(2)
|
68
68
|
end
|
69
69
|
|
70
70
|
end
|
data/test/Hash_spec.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright (c) 2015 by Chris Schlaeger <chris@taskjuggler.org>
|
4
|
+
#
|
5
|
+
# This file contains tests for Hash that are similar to the tests for the
|
6
|
+
# Hash implementation in MRI. The ideas of these tests were replicated in
|
7
|
+
# this code.
|
8
|
+
#
|
9
|
+
# MIT License
|
10
|
+
#
|
11
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
12
|
+
# a copy of this software and associated documentation files (the
|
13
|
+
# "Software"), to deal in the Software without restriction, including
|
14
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
15
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
16
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
17
|
+
# the following conditions:
|
18
|
+
#
|
19
|
+
# The above copyright notice and this permission notice shall be
|
20
|
+
# included in all copies or substantial portions of the Software.
|
21
|
+
#
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
23
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
24
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
25
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
26
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
27
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
28
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
29
|
+
|
30
|
+
require 'spec_helper'
|
31
|
+
|
32
|
+
require 'perobs'
|
33
|
+
|
34
|
+
|
35
|
+
class PO < PEROBS::Object
|
36
|
+
|
37
|
+
po_attr :name
|
38
|
+
|
39
|
+
def initialize(store, name = nil)
|
40
|
+
super(store)
|
41
|
+
@name = name
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe PEROBS::Hash do
|
47
|
+
|
48
|
+
before(:all) do
|
49
|
+
@db_name = generate_db_name(__FILE__)
|
50
|
+
end
|
51
|
+
|
52
|
+
before(:each) do
|
53
|
+
@store = PEROBS::Store.new(@db_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
after(:each) do
|
57
|
+
@store.delete_store
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should store simple objects persistently' do
|
61
|
+
@store['h'] = h = @store.new(PEROBS::Hash)
|
62
|
+
h['a'] = 'A'
|
63
|
+
h['b'] = 'B'
|
64
|
+
h['po'] = po = @store.new(PO)
|
65
|
+
po.name = 'foobar'
|
66
|
+
h['b'] = 'B'
|
67
|
+
|
68
|
+
expect(h['a']).to eq('A')
|
69
|
+
expect(h['b']).to eq('B')
|
70
|
+
@store.sync
|
71
|
+
|
72
|
+
@store = PEROBS::Store.new(@db_name)
|
73
|
+
h = @store['h']
|
74
|
+
expect(h['a']).to eq('A')
|
75
|
+
expect(h['b']).to eq('B')
|
76
|
+
expect(h['po'].name).to eq('foobar')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should have an each method to iterate' do
|
80
|
+
@store['h'] = h = @store.new(PEROBS::Hash)
|
81
|
+
h['a'] = 'A'
|
82
|
+
h['b'] = 'B'
|
83
|
+
h['c'] = 'C'
|
84
|
+
vs = []
|
85
|
+
h.each { |k, v| vs << k + v }
|
86
|
+
expect(vs.sort.join).to eq('aAbBcC')
|
87
|
+
|
88
|
+
@store = PEROBS::Store.new(@db_name)
|
89
|
+
@store['h'] = h = @store.new(PEROBS::Hash)
|
90
|
+
h['a'] = @store.new(PO, 'A')
|
91
|
+
h['b'] = @store.new(PO, 'B')
|
92
|
+
h['c'] = @store.new(PO, 'C')
|
93
|
+
vs = []
|
94
|
+
h.each { |k, v| vs << k + v.name }
|
95
|
+
expect(vs.sort.join).to eq('aAbBcC')
|
96
|
+
end
|
97
|
+
|
98
|
+
# Utility method to create a PEROBS::Hash from a normal Hash.
|
99
|
+
def cph(hash = nil)
|
100
|
+
a = @store.new(PEROBS::Hash)
|
101
|
+
a.replace(hash) unless hash.nil?
|
102
|
+
@store['a'] = a
|
103
|
+
end
|
104
|
+
|
105
|
+
def pcheck
|
106
|
+
yield
|
107
|
+
@store.sync
|
108
|
+
@store = PEROBS::Store.new(@db_name)
|
109
|
+
yield
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should support reading method' do
|
113
|
+
expect(cph({ [1] => [2] }).flatten).to eq([ [1], [2] ])
|
114
|
+
|
115
|
+
a = cph({ 1 => "one", 2 => [ 2, "two" ], 3 => [ 3, [ "three" ] ] })
|
116
|
+
expect(a.flatten).to eq([ 1, "one", 2, [ 2, "two" ], 3, [ 3, ["three"] ] ])
|
117
|
+
expect(a.flatten(0)).to eq([
|
118
|
+
[ 1, "one" ],
|
119
|
+
[ 2, [ 2, "two" ] ],
|
120
|
+
[ 3, [ 3, [ "three" ] ] ]
|
121
|
+
])
|
122
|
+
expect(a.has_key?(2)).to be true
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should support Enumberable methods' do
|
126
|
+
h = cph({ 1 => 'a', 2 => 'b' })
|
127
|
+
expect(h.first).to eq([ 1, 'a' ])
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should support rewriting methods' do
|
131
|
+
h = cph({ 1 => 'a', 2 => 'b' })
|
132
|
+
h.clear
|
133
|
+
expect(h.size).to eq(0)
|
134
|
+
expect(h[1]).to be_nil
|
135
|
+
|
136
|
+
h = cph({ 1 => 'a', 2 => 'b' })
|
137
|
+
expect(h.delete_if { |k, v| k == 1 }.size).to eq(1)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should support merge!' do
|
141
|
+
h1 = cph({ 1 => 2, 2 => 3, 3 => 4 })
|
142
|
+
h2 = cph({ 2 => 'two', 4 => 'four' })
|
143
|
+
|
144
|
+
ha = { 1 => 2, 2 => 'two', 3 => 4, 4 => 'four' }
|
145
|
+
hb = { 1 => 2, 2 => 3, 3 => 4, 4 => 'four' }
|
146
|
+
|
147
|
+
expect(h1.update(h2)).to eq(ha)
|
148
|
+
pcheck { expect(h1).to eq(ha) }
|
149
|
+
|
150
|
+
h1 = cph({ 1 => 2, 2 => 3, 3 => 4 })
|
151
|
+
h2 = cph({ 2 => 'two', 4 => 'four' })
|
152
|
+
|
153
|
+
expect(h2.update(h1)).to eq(hb)
|
154
|
+
pcheck { expect(h2).to eq(hb) }
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
@@ -23,10 +23,7 @@
|
|
23
23
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
24
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
require 'fileutils'
|
29
|
-
require 'time'
|
26
|
+
require 'spec_helper'
|
30
27
|
require 'perobs'
|
31
28
|
|
32
29
|
class O1 < PEROBS::Object
|
@@ -50,59 +47,87 @@ class O2 < PEROBS::Object
|
|
50
47
|
init_attr(:a4, 42)
|
51
48
|
end
|
52
49
|
|
50
|
+
def a3_deref
|
51
|
+
@a3.a1
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class O3 < PEROBS::Object
|
57
|
+
|
58
|
+
def initialize(store)
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
53
62
|
end
|
54
63
|
|
55
64
|
describe PEROBS::Store do
|
56
65
|
|
66
|
+
before(:all) do
|
67
|
+
@db_name = File.join(Dir.tmpdir, "Object_spec.#{rand(2**32)}")
|
68
|
+
end
|
69
|
+
|
57
70
|
before(:each) do
|
58
|
-
|
59
|
-
@store = PEROBS::Store.new('test_db')
|
71
|
+
@store = PEROBS::Store.new(@db_name)
|
60
72
|
end
|
61
73
|
|
62
|
-
after(:
|
63
|
-
FileUtils.rm_rf(
|
74
|
+
after(:each) do
|
75
|
+
FileUtils.rm_rf(@db_name)
|
64
76
|
end
|
65
77
|
|
66
78
|
it 'should initialize attributes with default values' do
|
67
|
-
@store['o1'] = o1 =
|
68
|
-
@store['o2'] = o2 =
|
69
|
-
o2.a1.
|
70
|
-
o2.a2.
|
71
|
-
o2.a3.
|
72
|
-
o2.a4.
|
79
|
+
@store['o1'] = o1 = @store.new(O1)
|
80
|
+
@store['o2'] = o2 = @store.new(O2)
|
81
|
+
expect(o2.a1).to eq('a1')
|
82
|
+
expect(o2.a2).to be_nil
|
83
|
+
expect(o2.a3).to be_nil
|
84
|
+
expect(o2.a4).to eq(42)
|
73
85
|
end
|
74
86
|
|
75
87
|
it 'should assign values to attributes' do
|
76
|
-
@store['o1'] = o1 =
|
77
|
-
@store['o2'] = o2 =
|
88
|
+
@store['o1'] = o1 = @store.new(O1)
|
89
|
+
@store['o2'] = o2 = @store.new(O2)
|
78
90
|
o1.a1 = 'a1'
|
79
91
|
o2.a1 = nil
|
80
92
|
o2.a3 = o1
|
81
93
|
|
82
|
-
o1.a1.
|
83
|
-
o2.a1.
|
84
|
-
o2.a3.
|
85
|
-
o2.a4.
|
94
|
+
expect(o1.a1).to eq('a1')
|
95
|
+
expect(o2.a1).to be_nil
|
96
|
+
expect(o2.a3).to eq(o1)
|
97
|
+
expect(o2.a4).to eq(42)
|
86
98
|
@store.sync
|
87
99
|
end
|
88
100
|
|
89
101
|
it 'should persist assigned values' do
|
90
|
-
@store['o1'] = o1 =
|
91
|
-
@store['o2'] = o2 =
|
102
|
+
@store['o1'] = o1 = @store.new(O1)
|
103
|
+
@store['o2'] = o2 = @store.new(O2)
|
92
104
|
o1.a1 = 'a1'
|
93
105
|
o2.a1 = nil
|
94
106
|
o2.a3 = o1
|
95
|
-
o2.a4 = PEROBS::Array
|
107
|
+
o2.a4 = @store.new(PEROBS::Array)
|
96
108
|
o2.a4 += [ 0, 1, 2 ]
|
97
109
|
@store.sync
|
98
110
|
|
99
|
-
@store = PEROBS::Store.new(
|
111
|
+
@store = PEROBS::Store.new(@db_name)
|
100
112
|
o1 = @store['o1']
|
101
113
|
o2 = @store['o2']
|
102
|
-
o1.a1.
|
103
|
-
o2.a1.
|
104
|
-
o2.a3.
|
105
|
-
o2.a4.
|
114
|
+
expect(o1.a1).to eq('a1')
|
115
|
+
expect(o2.a1).to be_nil
|
116
|
+
expect(o2.a3).to eq(o1)
|
117
|
+
expect(o2.a4).to eq([ 0, 1, 2 ])
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should transparently access a referenced object' do
|
121
|
+
@store['o1'] = o1 = @store.new(O1)
|
122
|
+
@store['o2'] = o2 = @store.new(O2)
|
123
|
+
o1.a1 = 'a1'
|
124
|
+
o2.a3 = o1
|
125
|
+
expect(o2.a3_deref).to eq('a1')
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should raise an error when no attributes are defined' do
|
129
|
+
@store['o3'] = @store.new(O3)
|
130
|
+
expect { @store.sync }.to raise_error(StandardError)
|
106
131
|
end
|
107
132
|
|
108
133
|
end
|