kissifer-hash-persistent 0.0.0 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|