kissifer-hash-persistent 0.0.3 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.1.1
@@ -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.3"
5
+ s.version = "0.1.1"
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-05-22}
9
+ s.date = %q{2009-05-27}
10
10
  s.email = %q{tierneydrchris@gmail.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
21
21
  "VERSION",
22
22
  "hash-persistent.gemspec",
23
23
  "lib/hash-persistent.rb",
24
- "lib/hash-persistent/basic.rb",
25
- "lib/hash-persistent/counting.rb",
26
- "spec/basic_spec.rb",
27
- "spec/counting_spec.rb",
24
+ "lib/hash-persistent/counter.rb",
25
+ "lib/hash-persistent/resource.rb",
26
+ "spec/counter_spec.rb",
27
+ "spec/resource_spec.rb",
28
28
  "spec/spec.opts",
29
29
  "spec/spec_helper.rb"
30
30
  ]
@@ -34,8 +34,8 @@ Gem::Specification.new do |s|
34
34
  s.rubygems_version = %q{1.3.3}
35
35
  s.summary = %q{Library of base classes to simplify persisting objects in a moneta store}
36
36
  s.test_files = [
37
- "spec/basic_spec.rb",
38
- "spec/counting_spec.rb",
37
+ "spec/counter_spec.rb",
38
+ "spec/resource_spec.rb",
39
39
  "spec/spec_helper.rb"
40
40
  ]
41
41
 
@@ -0,0 +1,22 @@
1
+ module HashPersistent
2
+ module Counter
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.module_eval do
6
+ @next_key = 0
7
+ @key_inc_lock = Mutex.new
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def next_key
13
+ the_key = nil
14
+ @key_inc_lock.synchronize do
15
+ the_key = @next_key.to_s
16
+ @next_key += 1
17
+ end
18
+ the_key
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ module HashPersistent
2
+ module Resource
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.module_eval do
6
+ @store = {}
7
+ @prefix = ""
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def persist_to(store, prefix)
13
+ raise ArgumentError unless store.respond_to?(:has_key?) and prefix.respond_to?(:to_s)
14
+ @store = store
15
+ @prefix = prefix
16
+ end
17
+
18
+ def find(key)
19
+ @store[@prefix + key]
20
+ end
21
+
22
+ attr_reader :store, :prefix
23
+ end
24
+
25
+ attr_accessor :key
26
+
27
+ def prefix_key
28
+ self.class.prefix + key
29
+ end
30
+
31
+ def save
32
+ raise RuntimeError unless key
33
+ self.class.store[prefix_key] = self
34
+ end
35
+
36
+ def delete
37
+ raise RuntimeError unless self.class.store.has_key?(prefix_key)
38
+ self.class.store.delete(prefix_key)
39
+ end
40
+
41
+ end
42
+ end
43
+
@@ -1,5 +1,5 @@
1
1
  $LOAD_PATH << File.dirname(__FILE__)
2
2
 
3
3
  require 'rubygems'
4
- require 'hash-persistent/basic'
5
- require 'hash-persistent/counting'
4
+ require 'hash-persistent/counter'
5
+ require 'hash-persistent/resource'
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "HashPersistent::Counter" do
4
+ context "when mixed-in to a class" do
5
+ before(:each) do
6
+ class CounterFoo
7
+ include HashPersistent::Counter
8
+ end
9
+ end
10
+
11
+ it "should impart a next_key class method" do
12
+ CounterFoo.respond_to?(:next_key).should be_true
13
+ end
14
+
15
+ it "should supply a new key on each next_key call" do
16
+ CounterFoo.next_key.should_not == CounterFoo.next_key
17
+ end
18
+
19
+ it "should be careful when incrementing the key in multi-threaded/process environment" do
20
+ pending
21
+ end
22
+ end
23
+
24
+ context "when mixed-in to more than one class" do
25
+ before(:each) do
26
+ class CounterFred
27
+ include HashPersistent::Counter
28
+ end
29
+ class CounterBarney
30
+ include HashPersistent::Counter
31
+ end
32
+ end
33
+
34
+ it "should count independently for each class" do
35
+ CounterFred.next_key.should == CounterBarney.next_key
36
+ CounterFred.next_key.should == CounterBarney.next_key
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,271 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class ResourceFoo
4
+ include HashPersistent::Resource
5
+ end
6
+
7
+ class ResourceFooWithState
8
+ include HashPersistent::Resource
9
+ attr_accessor :dummy
10
+
11
+ def ==(other)
12
+ return self.class == other.class &&
13
+ self.dummy == other.dummy
14
+ end
15
+ end
16
+
17
+ class ResourceFooOnlyUsedOnce
18
+ include HashPersistent::Resource
19
+ attr_accessor :dummy
20
+
21
+ def ==(other)
22
+ return self.class == other.class &&
23
+ self.dummy == other.dummy
24
+ end
25
+ end
26
+
27
+ describe "A class that includes HashPersistent::Resource" do
28
+ context "(class methods)" do
29
+ it "should acquire a persist_to class method" do
30
+ ResourceFoo.respond_to?(:persist_to).should be_true
31
+ end
32
+ end
33
+
34
+ context "(persistence mechanism)" do
35
+ it "should expect to persist to a hash-like store, with a string-like prefix" do
36
+ ResourceFoo.persist_to({}, "_prefix")
37
+ end
38
+
39
+ it "should reject a non-hash-like store" do
40
+ lambda {ResourceFoo.persist_to(1, "_prefix")}.should raise_error(ArgumentError)
41
+ end
42
+
43
+ it "should reject a non-string-like prefix" do
44
+ lambda {ResourceFoo.persist_to({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError)
45
+ end
46
+ end
47
+
48
+ context "(an instance that has not been saved)" do
49
+ it "should maintain a key attribute" do
50
+ ResourceFoo.new.respond_to?(:key).should be_true
51
+ ResourceFoo.new.respond_to?(:key=).should be_true
52
+ end
53
+
54
+ it "should respond to a save method" do
55
+ ResourceFoo.new.respond_to?(:save).should be_true
56
+ end
57
+
58
+ it "should respond to a delete method" do
59
+ ResourceFoo.new.respond_to?(:delete).should be_true
60
+ end
61
+
62
+ it "should not save unless the key has been explictly set" do
63
+ lambda{ResourceFoo.new.save}.should raise_error
64
+ end
65
+
66
+ it "should not be deletable, even after a key is set" do
67
+ ResourceFoo.persist_to(Hash.new, "")
68
+ resource = ResourceFoo.new
69
+ lambda{resource.delete}.should raise_error
70
+ resource.key = "fred"
71
+ lambda{resource.delete}.should raise_error
72
+ end
73
+
74
+ it "should not be findable via its key" do
75
+ ResourceFoo.persist_to(Hash.new, "")
76
+ resource = ResourceFoo.new
77
+ resource.key = "fred"
78
+ ResourceFoo.find("fred").should == nil
79
+ ResourceFoo.find("barney").should == nil
80
+ end
81
+ end
82
+
83
+ context "(an instance that has been saved)" do
84
+ it "should be findable via its key" do
85
+ ResourceFoo.persist_to(Hash.new, "")
86
+ resource = ResourceFoo.new
87
+ resource.key = "fred"
88
+ resource.save
89
+ ResourceFoo.find("fred").should_not be_nil
90
+ end
91
+
92
+ it "should correctly recover all of its state" do
93
+ ResourceFooWithState.persist_to(Hash.new, "")
94
+ resource = ResourceFooWithState.new
95
+ resource.key = "fred"
96
+ resource.dummy = ["something random", {}]
97
+ resource.save
98
+ resource_dup = resource.dup
99
+ ResourceFooWithState.find("fred").should == resource_dup
100
+ end
101
+
102
+ it "should be deletable" do
103
+ ResourceFoo.persist_to(Hash.new, "")
104
+ resource = ResourceFoo.new
105
+ resource.key = "fred"
106
+ resource.save
107
+ lambda{resource.delete}.should_not raise_error
108
+ end
109
+
110
+ it "should save a new state when asked" do
111
+ ResourceFooWithState.persist_to(Hash.new, "")
112
+ resource = ResourceFooWithState.new
113
+ resource.key = "fred"
114
+
115
+ resource.dummy = ["something random", {}]
116
+ resource.save
117
+ resource_dup_1 = resource.dup
118
+
119
+ resource.dummy = ["something else random", 1]
120
+ resource.save
121
+ resource_dup_2 = resource.dup
122
+
123
+ ResourceFooWithState.find("fred").should_not == resource_dup_1
124
+ ResourceFooWithState.find("fred").should == resource_dup_2
125
+ end
126
+ end
127
+
128
+ context "(an instance that has been saved and then deleted)" do
129
+ it "should not be findable via its key" do
130
+ ResourceFoo.persist_to(Hash.new, "")
131
+ resource = ResourceFoo.new
132
+ resource.key = "fred"
133
+ resource.save
134
+ resource.delete
135
+ ResourceFoo.find("fred").should == nil
136
+ end
137
+
138
+ it "should not be deletable" do
139
+ ResourceFoo.persist_to(Hash.new, "")
140
+ resource = ResourceFoo.new
141
+ resource.key = "fred"
142
+ resource.save
143
+ resource.delete
144
+ lambda{resource.delete}.should raise_error
145
+ end
146
+ end
147
+
148
+ context "(use of prefix to namespace keys)" do
149
+ it "should (transparently) prepend the supplied prefix to the key of the saved instance" do
150
+ store = Hash.new
151
+ ResourceFoo.persist_to(store, "a_random_namespace::")
152
+ resource = ResourceFoo.new
153
+ resource.key = "fred"
154
+ resource.save
155
+ store.should_not have_key("fred")
156
+ store.should have_key("a_random_namespace::fred")
157
+ end
158
+
159
+ it "should find instances when using a namespace, using only the key" do
160
+ store = Hash.new
161
+ ResourceFoo.persist_to(store, "a_random_namespace::")
162
+ resource = ResourceFoo.new
163
+ resource.key = "fred"
164
+ resource.save
165
+ ResourceFoo.find("fred").should_not == nil
166
+ end
167
+
168
+ it "should not find instances when mistakenly given a namespaced key" do
169
+ store = Hash.new
170
+ ResourceFoo.persist_to(store, "a_random_namespace::")
171
+ resource = ResourceFoo.new
172
+ resource.key = "fred"
173
+ resource.save
174
+ ResourceFoo.find("a_random_namespace::fred").should == nil
175
+ end
176
+
177
+ it "should correctly delete an instance from the store when using a prefix" do
178
+ store = Hash.new
179
+ ResourceFoo.persist_to(store, "a_random_namespace::")
180
+ resource = ResourceFoo.new
181
+ resource.key = "fred"
182
+ resource.save
183
+ resource.delete
184
+ ResourceFoo.find("fred").should == nil
185
+ end
186
+ end
187
+
188
+ context "(use of store)" do
189
+ it "should correctly delete items from the store" do
190
+ store = Hash.new
191
+ ResourceFoo.persist_to(store, "")
192
+ resource_1 = ResourceFoo.new
193
+ resource_1.key = "fred"
194
+ resource_1.save
195
+
196
+ resource_2 = ResourceFoo.new
197
+ resource_2.key = "barney"
198
+ resource_2.save
199
+ store.should_not == Hash.new
200
+
201
+ resource_1.delete
202
+ resource_2.delete
203
+ store.should == Hash.new
204
+ end
205
+ end
206
+
207
+ context "(use of restricted hash api)" do
208
+ it "should use only the restricted hash api provided by moneta" do
209
+ lambda {
210
+ ResourceFooWithState.persist_to(Dummy_RestrictedHash.new, "prefix::")
211
+ resource_1 = ResourceFooWithState.new
212
+ resource_1.key = "fred"
213
+ resource_1.dummy = ["barney"]
214
+ resource_1.save
215
+ ResourceFooWithState.find("fred").delete
216
+ }.should_not raise_error
217
+ end
218
+ end
219
+
220
+ context "(default store)" do
221
+ it "should function with a vdefault store/prefix if none is supplied" do
222
+ # This is implicitly tested elsewhere. Which makes this test documentation, I guess
223
+ resource_1 = ResourceFooOnlyUsedOnce.new
224
+ resource_1.key = "fred"
225
+ resource_1.dummy = ["barney"]
226
+ resource_1.save
227
+ ResourceFooOnlyUsedOnce.find("fred").should == resource_1.dup
228
+ lambda {ResourceFooOnlyUsedOnce.find("fred").delete}.should_not raise_error
229
+ end
230
+ end
231
+
232
+ context "(multiple classes using module)" do
233
+ it "should not cross-contaminate classes that include the module" do
234
+ store_1 = Hash.new
235
+ ResourceFoo.persist_to(store_1, "")
236
+ store_2 = Hash.new
237
+ ResourceFooWithState.persist_to(store_2, "prefix::")
238
+
239
+ store_1.should == Hash.new
240
+ store_2.should == Hash.new
241
+
242
+ resource_1 = ResourceFoo.new
243
+ resource_1.key = "1"
244
+ resource_1.save
245
+
246
+ store_1.should_not == Hash.new
247
+ store_2.should == Hash.new
248
+ store_1.should have_key("1")
249
+ store_1.should_not have_key("prefix::1")
250
+
251
+ resource_1.delete
252
+
253
+ store_1.should == Hash.new
254
+ store_2.should == Hash.new
255
+
256
+ resource_2 = ResourceFooWithState.new
257
+ resource_2.key = "2"
258
+ resource_2.save
259
+
260
+ store_1.should == Hash.new
261
+ store_2.should_not == Hash.new
262
+ store_2.should have_key("prefix::2")
263
+ store_2.should_not have_key("2")
264
+
265
+ resource_2.delete
266
+
267
+ store_1.should == Hash.new
268
+ store_2.should == Hash.new
269
+ end
270
+ end
271
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kissifer-hash-persistent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - kissifer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-22 00:00:00 -07:00
12
+ date: 2009-05-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -31,10 +31,10 @@ files:
31
31
  - VERSION
32
32
  - hash-persistent.gemspec
33
33
  - lib/hash-persistent.rb
34
- - lib/hash-persistent/basic.rb
35
- - lib/hash-persistent/counting.rb
36
- - spec/basic_spec.rb
37
- - spec/counting_spec.rb
34
+ - lib/hash-persistent/counter.rb
35
+ - lib/hash-persistent/resource.rb
36
+ - spec/counter_spec.rb
37
+ - spec/resource_spec.rb
38
38
  - spec/spec.opts
39
39
  - spec/spec_helper.rb
40
40
  has_rdoc: false
@@ -64,6 +64,6 @@ signing_key:
64
64
  specification_version: 3
65
65
  summary: Library of base classes to simplify persisting objects in a moneta store
66
66
  test_files:
67
- - spec/basic_spec.rb
68
- - spec/counting_spec.rb
67
+ - spec/counter_spec.rb
68
+ - spec/resource_spec.rb
69
69
  - spec/spec_helper.rb
@@ -1,36 +0,0 @@
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
@@ -1,40 +0,0 @@
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 DELETED
@@ -1,188 +0,0 @@
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
@@ -1,196 +0,0 @@
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