kissifer-hash-persistent 0.0.3 → 0.1.1

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/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