kissifer-hash-persistent 0.0.0 → 0.0.3
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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/hash-persistent.gemspec +12 -21
- data/lib/hash-persistent.rb +2 -5
- data/lib/hash-persistent/basic.rb +36 -0
- data/lib/hash-persistent/counting.rb +40 -0
- data/spec/basic_spec.rb +188 -0
- data/spec/counting_spec.rb +196 -0
- data/spec/spec_helper.rb +0 -2
- metadata +9 -18
- data/lib/hash-persistent/collection.rb +0 -59
- data/lib/hash-persistent/counter.rb +0 -26
- data/lib/hash-persistent/extended_store.rb +0 -49
- data/lib/hash-persistent/resource.rb +0 -20
- data/lib/hash-persistent/store.rb +0 -67
- data/spec/collection_spec.rb +0 -269
- data/spec/counter_spec.rb +0 -61
- data/spec/extended_store_spec.rb +0 -103
- data/spec/resource_spec.rb +0 -48
- data/spec/store_spec.rb +0 -370
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "hash-persistent"
|
8
|
-
gem.summary = %Q{Library of base classes to simplify persisting objects
|
8
|
+
gem.summary = %Q{Library of base classes to simplify persisting objects in a moneta store}
|
9
9
|
gem.email = "tierneydrchris@gmail.com"
|
10
10
|
gem.homepage = "http://github.com/kissifer/hash-persistent"
|
11
11
|
gem.authors = ["kissifer"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/hash-persistent.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{hash-persistent}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["kissifer"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-05-22}
|
10
10
|
s.email = %q{tierneydrchris@gmail.com}
|
11
11
|
s.extra_rdoc_files = [
|
12
12
|
"LICENSE",
|
@@ -21,31 +21,22 @@ Gem::Specification.new do |s|
|
|
21
21
|
"VERSION",
|
22
22
|
"hash-persistent.gemspec",
|
23
23
|
"lib/hash-persistent.rb",
|
24
|
-
"lib/hash-persistent/
|
25
|
-
"lib/hash-persistent/
|
26
|
-
"
|
27
|
-
"
|
28
|
-
"lib/hash-persistent/store.rb",
|
29
|
-
"spec/collection_spec.rb",
|
30
|
-
"spec/counter_spec.rb",
|
31
|
-
"spec/extended_store_spec.rb",
|
32
|
-
"spec/resource_spec.rb",
|
24
|
+
"lib/hash-persistent/basic.rb",
|
25
|
+
"lib/hash-persistent/counting.rb",
|
26
|
+
"spec/basic_spec.rb",
|
27
|
+
"spec/counting_spec.rb",
|
33
28
|
"spec/spec.opts",
|
34
|
-
"spec/spec_helper.rb"
|
35
|
-
"spec/store_spec.rb"
|
29
|
+
"spec/spec_helper.rb"
|
36
30
|
]
|
37
31
|
s.homepage = %q{http://github.com/kissifer/hash-persistent}
|
38
32
|
s.rdoc_options = ["--charset=UTF-8"]
|
39
33
|
s.require_paths = ["lib"]
|
40
|
-
s.rubygems_version = %q{1.3.
|
41
|
-
s.summary = %q{Library of base classes to simplify persisting objects
|
34
|
+
s.rubygems_version = %q{1.3.3}
|
35
|
+
s.summary = %q{Library of base classes to simplify persisting objects in a moneta store}
|
42
36
|
s.test_files = [
|
43
|
-
"spec/
|
44
|
-
"spec/
|
45
|
-
"spec/
|
46
|
-
"spec/resource_spec.rb",
|
47
|
-
"spec/spec_helper.rb",
|
48
|
-
"spec/store_spec.rb"
|
37
|
+
"spec/basic_spec.rb",
|
38
|
+
"spec/counting_spec.rb",
|
39
|
+
"spec/spec_helper.rb"
|
49
40
|
]
|
50
41
|
|
51
42
|
if s.respond_to? :specification_version then
|
data/lib/hash-persistent.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
$LOAD_PATH << File.dirname(__FILE__)
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require 'hash-persistent/
|
5
|
-
require 'hash-persistent/
|
6
|
-
require 'hash-persistent/resource'
|
7
|
-
require 'hash-persistent/collection'
|
8
|
-
require 'hash-persistent/counter'
|
4
|
+
require 'hash-persistent/basic'
|
5
|
+
require 'hash-persistent/counting'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module HashPersistent
|
2
|
+
class Basic
|
3
|
+
class << self
|
4
|
+
@@store = {}
|
5
|
+
@@prefix = ""
|
6
|
+
|
7
|
+
def setup(store, prefix)
|
8
|
+
raise ArgumentError unless store.respond_to?(:has_key?) and prefix.respond_to?(:to_s)
|
9
|
+
@@store = store
|
10
|
+
@@prefix = prefix
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(key)
|
14
|
+
@@store[@@prefix + key]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :key
|
19
|
+
|
20
|
+
def initialize(key)
|
21
|
+
raise RuntimeError if @@store.has_key?(key)
|
22
|
+
@key = key
|
23
|
+
@@store[@@prefix + @key] = self
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete
|
27
|
+
raise RuntimeError unless @@store.has_key?(@@prefix + @key)
|
28
|
+
@@store.delete(@@prefix + @key)
|
29
|
+
end
|
30
|
+
|
31
|
+
def update
|
32
|
+
raise RuntimeError unless @@store.has_key?(@@prefix + @key)
|
33
|
+
@@store[@@prefix + @key] = self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module HashPersistent
|
2
|
+
class Counting
|
3
|
+
class << self
|
4
|
+
@@store = {}
|
5
|
+
@@prefix = ""
|
6
|
+
@@next_key = 0
|
7
|
+
@@next_key_inc_lock = Mutex.new
|
8
|
+
|
9
|
+
def setup(store, prefix)
|
10
|
+
raise ArgumentError unless store.respond_to?(:has_key?) and prefix.respond_to?(:to_s)
|
11
|
+
@@store = store
|
12
|
+
@@prefix = prefix
|
13
|
+
end
|
14
|
+
|
15
|
+
def find(key)
|
16
|
+
@@store[@@prefix + key]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :key
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@@next_key_inc_lock.synchronize do
|
24
|
+
@key = @@next_key.to_s
|
25
|
+
@@next_key += 1
|
26
|
+
end
|
27
|
+
@@store[@@prefix + @key] = self
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete
|
31
|
+
raise RuntimeError unless @@store.has_key?(@@prefix + @key)
|
32
|
+
@@store.delete(@@prefix + @key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update
|
36
|
+
raise RuntimeError unless @@store.has_key?(@@prefix + @key)
|
37
|
+
@@store[@@prefix + @key] = self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/basic_spec.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "HashPersistent::Basic" do
|
4
|
+
context "(before use)" do
|
5
|
+
it "should accept a hash-like store, and a string-like prefix, as class initialisers" do
|
6
|
+
HashPersistent::Basic.setup({}, "_prefix")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should reject a non-hash-like store" do
|
10
|
+
lambda {HashPersistent::Basic.setup(1, "_prefix")}.should raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should reject a non-string-like prefix" do
|
14
|
+
lambda {HashPersistent::Basic.setup({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "(creating objects)" do
|
19
|
+
it "should allow not objects to be created without a key" do
|
20
|
+
HashPersistent::Basic.setup({}, "")
|
21
|
+
lambda{HashPersistent::Basic.new}.should raise_error
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow objects to be created with a key" do
|
25
|
+
HashPersistent::Basic.setup({}, "")
|
26
|
+
lambda{HashPersistent::Basic.new("a_key")}.should_not raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not allow objects to be created with a duplicate key" do
|
30
|
+
HashPersistent::Basic.setup({}, "")
|
31
|
+
HashPersistent::Basic.new("a_key")
|
32
|
+
lambda{HashPersistent::Basic.new("a_key")}.should raise_error
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return an object after creation" do
|
36
|
+
HashPersistent::Basic.setup({}, "")
|
37
|
+
new_object = HashPersistent::Basic.new("a_key")
|
38
|
+
new_object.class.should == HashPersistent::Basic
|
39
|
+
new_object.key.should == "a_key"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "(retrieving objects)" do
|
44
|
+
it "should not return an object when no objects have been created" do
|
45
|
+
HashPersistent::Basic.setup({}, "")
|
46
|
+
HashPersistent::Basic.find("a_key").should be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return created objects when given the correct key" do
|
50
|
+
HashPersistent::Basic.setup({}, "")
|
51
|
+
HashPersistent::Basic.new("a_key")
|
52
|
+
new_object = HashPersistent::Basic.find("a_key")
|
53
|
+
new_object.class.should == HashPersistent::Basic
|
54
|
+
new_object.key.should == "a_key"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not return an object when given an incorrect key" do
|
58
|
+
HashPersistent::Basic.setup({}, "")
|
59
|
+
HashPersistent::Basic.new("a_key")
|
60
|
+
HashPersistent::Basic.find("another_key").should be_nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "(deleting objects)" do
|
65
|
+
it "should delete an object when asked" do
|
66
|
+
HashPersistent::Basic.setup({}, "")
|
67
|
+
new_object = HashPersistent::Basic.new("a_key")
|
68
|
+
new_object.delete
|
69
|
+
HashPersistent::Basic.find("a_key").should be_nil
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not allow an object to be deleted twice" do
|
73
|
+
HashPersistent::Basic.setup({}, "")
|
74
|
+
new_object = HashPersistent::Basic.new("a_key")
|
75
|
+
new_object.delete
|
76
|
+
lambda{new_object.delete}.should raise_error
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "(key namespacing)" do
|
81
|
+
it "should (transparently) prepend the supplied prefix to the key of the created object" do
|
82
|
+
store = {}
|
83
|
+
HashPersistent::Basic.setup(store, "a_namespace::")
|
84
|
+
new_object = HashPersistent::Basic.new("a_key")
|
85
|
+
new_object.class.should == HashPersistent::Basic
|
86
|
+
new_object.key.should == "a_key"
|
87
|
+
store.should_not have_key("a_key")
|
88
|
+
store.should have_key("a_namespace::a_key")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should correctly find objects when given a namespace" do
|
92
|
+
HashPersistent::Basic.setup({}, "a_namespace::")
|
93
|
+
HashPersistent::Basic.new("a_key")
|
94
|
+
new_object = HashPersistent::Basic.find("a_key")
|
95
|
+
new_object.should_not be_nil
|
96
|
+
new_object.key.should == "a_key"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should not find objects when mistakenly given a namespaced key" do
|
100
|
+
HashPersistent::Basic.setup({}, "a_namespace::")
|
101
|
+
HashPersistent::Basic.new("a_key")
|
102
|
+
HashPersistent::Basic.find("a_namespace::a_key").should be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should correctly delete objects when given a namespace" do
|
106
|
+
store = {}
|
107
|
+
HashPersistent::Basic.setup(store, "a_namespace::")
|
108
|
+
new_object = HashPersistent::Basic.new("a_key")
|
109
|
+
new_object.delete
|
110
|
+
|
111
|
+
HashPersistent::Basic.find("a_key").should be_nil
|
112
|
+
store.should_not have_key("a_namespace::a_key")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
class Dummy_BasicDerivedClass < HashPersistent::Basic
|
118
|
+
attr_accessor :dummy
|
119
|
+
|
120
|
+
def initialize(key, dummy)
|
121
|
+
super(key)
|
122
|
+
@dummy = dummy
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "(derived classes)" do
|
127
|
+
it "should correctly store the full member list of a derived class" do
|
128
|
+
Dummy_BasicDerivedClass.setup({}, "")
|
129
|
+
created_dummy = Dummy_BasicDerivedClass.new("a_key", 123)
|
130
|
+
created_dummy.key.should == "a_key"
|
131
|
+
created_dummy.dummy.should == 123
|
132
|
+
|
133
|
+
retrieved_dummy = Dummy_BasicDerivedClass.find("a_key")
|
134
|
+
retrieved_dummy.key.should == "a_key"
|
135
|
+
retrieved_dummy.dummy.should == 123
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "(updating objects)" do
|
140
|
+
it "should correctly update members of a derived class" do
|
141
|
+
Dummy_BasicDerivedClass.setup({}, "prefix::")
|
142
|
+
created_dummy = Dummy_BasicDerivedClass.new("a_key", 123)
|
143
|
+
|
144
|
+
duplicated_dummy = created_dummy.dup
|
145
|
+
duplicated_dummy.dummy = 456
|
146
|
+
duplicated_dummy.update
|
147
|
+
|
148
|
+
retrieved_dummy = Dummy_BasicDerivedClass.find("a_key")
|
149
|
+
retrieved_dummy.dummy.should_not == 123
|
150
|
+
retrieved_dummy.dummy.should == 456
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not allow a deleted object to update" do
|
154
|
+
Dummy_BasicDerivedClass.setup({}, "prefix::")
|
155
|
+
created_dummy = Dummy_BasicDerivedClass.new("a_key", 123)
|
156
|
+
created_dummy.delete
|
157
|
+
created_dummy.dummy = 456
|
158
|
+
lambda{created_dummy.update}.should raise_error
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "(restricted hash api)" do
|
163
|
+
it "should use only the restricted hash api provided by moneta" do
|
164
|
+
lambda {
|
165
|
+
Dummy_BasicDerivedClass.setup(Dummy_RestrictedHash.new, "prefix::")
|
166
|
+
created_dummy = Dummy_BasicDerivedClass.new("a_key", 123)
|
167
|
+
|
168
|
+
duplicated_dummy = created_dummy.dup
|
169
|
+
duplicated_dummy.dummy = 456
|
170
|
+
duplicated_dummy.update
|
171
|
+
|
172
|
+
retrieved_dummy = Dummy_BasicDerivedClass.find("a_key")
|
173
|
+
retrieved_dummy.delete
|
174
|
+
}.should_not raise_error
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "(concurrent access)" do
|
179
|
+
it "should be careful doing various operations" do
|
180
|
+
# What to test here? Duplicate in the other similar classes
|
181
|
+
# Test: Update, update vs delete, delete vs find, update vs find
|
182
|
+
# Eugh, how best to do this? Options:
|
183
|
+
# Subclass Hash and slow the set/get methods down?
|
184
|
+
# Monkey patch the Mutex class to add lock/unlock callbacks?
|
185
|
+
pending
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "HashPersistent::Counting" do
|
4
|
+
context "(before use)" do
|
5
|
+
it "should accept a hash-like store, and a string-like prefix, as class initialisers" do
|
6
|
+
HashPersistent::Counting.setup({}, "_prefix")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should reject a non-hash-like store" do
|
10
|
+
lambda {HashPersistent::Counting.setup(1, "_prefix")}.should raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should reject a non-string-like prefix" do
|
14
|
+
lambda {HashPersistent::Counting.setup({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "(creating objects)" do
|
19
|
+
it "should not allow objects to be created with a key" do
|
20
|
+
HashPersistent::Counting.setup({}, "")
|
21
|
+
lambda{HashPersistent::Counting.new("a_key")}.should raise_error
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow objects to be created without a key" do
|
25
|
+
HashPersistent::Counting.setup({}, "")
|
26
|
+
lambda{HashPersistent::Counting.new}.should_not raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return an object after creation" do
|
30
|
+
HashPersistent::Counting.setup({}, "")
|
31
|
+
new_object = HashPersistent::Counting.new
|
32
|
+
new_object.class.should == HashPersistent::Counting
|
33
|
+
end
|
34
|
+
|
35
|
+
it "generate unique keys for each object creation" do
|
36
|
+
HashPersistent::Counting.setup({}, "")
|
37
|
+
keys = []
|
38
|
+
lots = 100 # How many is enough here? We just have to pick a number I guess...
|
39
|
+
lots.times do
|
40
|
+
keys << HashPersistent::Counting.new.key
|
41
|
+
end
|
42
|
+
keys.uniq.should == keys
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "(retrieving objects)" do
|
47
|
+
it "should not return an object when no objects have been created" do
|
48
|
+
HashPersistent::Counting.setup({}, "")
|
49
|
+
HashPersistent::Counting.find("1").should be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return created objects when given the correct key" do
|
53
|
+
HashPersistent::Counting.setup({}, "")
|
54
|
+
key = HashPersistent::Counting.new.key
|
55
|
+
new_object = HashPersistent::Counting.find(key)
|
56
|
+
new_object.class.should == HashPersistent::Counting
|
57
|
+
new_object.key.should == key
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not return an object when given an incorrect key" do
|
61
|
+
HashPersistent::Counting.setup({}, "")
|
62
|
+
key = HashPersistent::Counting.new.key.to_s + "_not_a_valid_key"
|
63
|
+
HashPersistent::Counting.find(key).should be_nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "(deleting objects)" do
|
68
|
+
it "should delete an object when asked" do
|
69
|
+
HashPersistent::Counting.setup({}, "")
|
70
|
+
new_object = HashPersistent::Counting.new
|
71
|
+
key = new_object.key
|
72
|
+
new_object.delete
|
73
|
+
HashPersistent::Counting.find(key).should be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not allow an object to be deleted twice" do
|
77
|
+
HashPersistent::Counting.setup({}, "")
|
78
|
+
new_object = HashPersistent::Counting.new
|
79
|
+
new_object.delete
|
80
|
+
lambda{new_object.delete}.should raise_error
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "(key namespacing)" do
|
85
|
+
it "should (transparently) prepend the supplied prefix to the key of the created object" do
|
86
|
+
store = {}
|
87
|
+
HashPersistent::Counting.setup(store, "a_namespace::")
|
88
|
+
new_object = HashPersistent::Counting.new
|
89
|
+
new_object.class.should == HashPersistent::Counting
|
90
|
+
store.should_not have_key("#{new_object.key}")
|
91
|
+
store.should_not have_key(new_object.key)
|
92
|
+
store.should have_key("a_namespace::#{new_object.key}")
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should correctly find objects when given a namespace" do
|
96
|
+
HashPersistent::Counting.setup({}, "a_namespace::")
|
97
|
+
key = HashPersistent::Counting.new.key
|
98
|
+
new_object = HashPersistent::Counting.find(key)
|
99
|
+
new_object.should_not be_nil
|
100
|
+
new_object.key.should == key
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should not find objects when mistakenly given a namespaced key" do
|
104
|
+
HashPersistent::Counting.setup({}, "a_namespace::")
|
105
|
+
key = HashPersistent::Counting.new
|
106
|
+
HashPersistent::Counting.find("a_namespace::#{key}").should be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should correctly delete objects when given a namespace" do
|
110
|
+
store = {}
|
111
|
+
HashPersistent::Counting.setup(store, "a_namespace::")
|
112
|
+
new_object = HashPersistent::Counting.new
|
113
|
+
key = new_object.key
|
114
|
+
new_object.delete
|
115
|
+
|
116
|
+
HashPersistent::Counting.find(key).should be_nil
|
117
|
+
store.should_not have_key("a_namespace::#{key}")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
class Dummy_CountingDerivedClass < HashPersistent::Counting
|
123
|
+
attr_accessor :dummy
|
124
|
+
|
125
|
+
def initialize(dummy)
|
126
|
+
super()
|
127
|
+
@dummy = dummy
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "(derived classes)" do
|
132
|
+
it "should correctly store the full member list of a derived class" do
|
133
|
+
Dummy_CountingDerivedClass.setup({}, "")
|
134
|
+
created_dummy = Dummy_CountingDerivedClass.new(123)
|
135
|
+
created_dummy.dummy.should == 123
|
136
|
+
|
137
|
+
retrieved_dummy = Dummy_CountingDerivedClass.find(created_dummy.key)
|
138
|
+
retrieved_dummy.key.should == created_dummy.key
|
139
|
+
retrieved_dummy.dummy.should == 123
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "(updating objects)" do
|
144
|
+
it "should correctly update members of a derived class" do
|
145
|
+
Dummy_CountingDerivedClass.setup({}, "prefix::")
|
146
|
+
created_dummy = Dummy_CountingDerivedClass.new(123)
|
147
|
+
key = created_dummy.key
|
148
|
+
|
149
|
+
duplicated_dummy = created_dummy.dup
|
150
|
+
duplicated_dummy.dummy = 456
|
151
|
+
duplicated_dummy.update
|
152
|
+
|
153
|
+
retrieved_dummy = Dummy_CountingDerivedClass.find(key)
|
154
|
+
retrieved_dummy.dummy.should_not == 123
|
155
|
+
retrieved_dummy.dummy.should == 456
|
156
|
+
|
157
|
+
retrieved_dummy.key.should == key
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should not allow a deleted object to update" do
|
161
|
+
Dummy_CountingDerivedClass.setup({}, "prefix::")
|
162
|
+
created_dummy = Dummy_CountingDerivedClass.new(123)
|
163
|
+
created_dummy.delete
|
164
|
+
created_dummy.dummy = 456
|
165
|
+
lambda{created_dummy.update}.should raise_error
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "(restricted hash api)" do
|
170
|
+
it "should use only the restricted hash api provided by moneta" do
|
171
|
+
lambda {
|
172
|
+
Dummy_CountingDerivedClass.setup(Dummy_RestrictedHash.new, "prefix::")
|
173
|
+
created_dummy = Dummy_CountingDerivedClass.new(123)
|
174
|
+
key = created_dummy.key
|
175
|
+
|
176
|
+
duplicated_dummy = created_dummy.dup
|
177
|
+
duplicated_dummy.dummy = 456
|
178
|
+
duplicated_dummy.update
|
179
|
+
|
180
|
+
retrieved_dummy = Dummy_CountingDerivedClass.find(key)
|
181
|
+
retrieved_dummy.delete
|
182
|
+
}.should_not raise_error
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "(concurrent access)" do
|
187
|
+
it "should be careful incrementing the auto-generated key" do
|
188
|
+
# TODO. Subclass Hash, adda delay into the []= method (or another one?)
|
189
|
+
# Kick off two threads and create a bunch of objects
|
190
|
+
# Collect keys into arrays, merge, sort and compare for equality with
|
191
|
+
# an array of sequential numbers the same size as the number of objects
|
192
|
+
# we created
|
193
|
+
pending
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|