kissifer-hash-persistent 0.2.2 → 0.3.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/Rakefile +1 -1
- data/VERSION +1 -1
- data/hash-persistent.gemspec +4 -4
- data/lib/hash-persistent/collection.rb +19 -10
- data/lib/hash-persistent/resource.rb +35 -30
- data/spec/collection_spec.rb +93 -69
- data/spec/resource_spec.rb +158 -128
- metadata +3 -3
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 and collections to 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.
|
1
|
+
0.3.1
|
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.
|
5
|
+
s.version = "0.3.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-06-
|
9
|
+
s.date = %q{2009-06-04}
|
10
10
|
s.email = %q{tierneydrchris@gmail.com}
|
11
11
|
s.extra_rdoc_files = [
|
12
12
|
"LICENSE",
|
@@ -33,8 +33,8 @@ Gem::Specification.new do |s|
|
|
33
33
|
s.homepage = %q{http://github.com/kissifer/hash-persistent}
|
34
34
|
s.rdoc_options = ["--charset=UTF-8"]
|
35
35
|
s.require_paths = ["lib"]
|
36
|
-
s.rubygems_version = %q{1.3.
|
37
|
-
s.summary = %q{Library of base classes to simplify persisting objects
|
36
|
+
s.rubygems_version = %q{1.3.4}
|
37
|
+
s.summary = %q{Library of base classes to simplify persisting objects and collections to a moneta store}
|
38
38
|
s.test_files = [
|
39
39
|
"spec/collection_spec.rb",
|
40
40
|
"spec/counter_spec.rb",
|
@@ -2,18 +2,21 @@ module HashPersistent
|
|
2
2
|
module Collection
|
3
3
|
|
4
4
|
def self.included(base)
|
5
|
-
base.extend
|
5
|
+
base.extend ClassMethods_Initial
|
6
6
|
base.module_eval do
|
7
7
|
include HashPersistent::Resource
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
module
|
12
|
-
attr_reader :resource_class
|
13
|
-
|
11
|
+
module ClassMethods_Initial
|
14
12
|
def attach(resource_class, collection_basis)
|
15
|
-
raise
|
16
|
-
raise
|
13
|
+
raise "You must create a persistent subclass before attaching this collection class. Use HashPersistent::persist_to()" unless included_modules.include?(HashPersistent::Resource::InstanceMethods)
|
14
|
+
raise "You can attach this collection class only to a class that has been created with HashPersistent::Resource.persist_to()" unless resource_class.included_modules.include?(HashPersistent::Resource::InstanceMethods)
|
15
|
+
raise "Did not find the specified basis attribute (#{collection_basis}) in the given resource class" unless resource_class.instance_methods.include?(collection_basis.to_s)
|
16
|
+
|
17
|
+
extend ClassMethods
|
18
|
+
include InstanceMethods
|
19
|
+
|
17
20
|
@collection_basis = collection_basis
|
18
21
|
@resource_class = resource_class
|
19
22
|
resource_class.on_save do |resource|
|
@@ -24,6 +27,10 @@ module HashPersistent
|
|
24
27
|
collected_resource_deleted(resource)
|
25
28
|
end
|
26
29
|
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
attr_reader :resource_class
|
27
34
|
|
28
35
|
def collected_resource_saved(resource)
|
29
36
|
collection = find(resource.send(@collection_basis))
|
@@ -48,11 +55,13 @@ module HashPersistent
|
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
51
|
-
|
58
|
+
module InstanceMethods
|
59
|
+
attr_accessor :collected_keys
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
def collected_resources
|
62
|
+
collected_keys.collect do |key|
|
63
|
+
self.class.resource_class.send(:find, key)
|
64
|
+
end
|
56
65
|
end
|
57
66
|
end
|
58
67
|
end
|
@@ -1,24 +1,29 @@
|
|
1
1
|
module HashPersistent
|
2
2
|
module Resource
|
3
3
|
def self.included(base)
|
4
|
-
base.extend
|
5
|
-
base.module_eval do
|
6
|
-
@store = {}
|
7
|
-
@prefix = ""
|
8
|
-
end
|
4
|
+
base.extend ClassMethods_Initial
|
9
5
|
end
|
10
|
-
|
11
|
-
module
|
6
|
+
|
7
|
+
module ClassMethods_Initial
|
12
8
|
def persist_to(store, prefix)
|
13
9
|
raise ArgumentError unless store.respond_to?(:has_key?) and prefix.respond_to?(:to_s)
|
14
|
-
|
15
|
-
|
10
|
+
Class.new(self) do
|
11
|
+
extend ClassMethods
|
12
|
+
include InstanceMethods
|
13
|
+
|
14
|
+
@store = store
|
15
|
+
@prefix = prefix
|
16
|
+
end
|
16
17
|
end
|
18
|
+
end
|
17
19
|
|
20
|
+
module ClassMethods
|
21
|
+
attr_reader :store, :prefix
|
22
|
+
|
18
23
|
def find(key)
|
19
24
|
@store[@prefix + key]
|
20
25
|
end
|
21
|
-
|
26
|
+
|
22
27
|
def on_save(&block)
|
23
28
|
if block
|
24
29
|
@on_save = block
|
@@ -33,30 +38,30 @@ module HashPersistent
|
|
33
38
|
else
|
34
39
|
@on_delete
|
35
40
|
end
|
36
|
-
end
|
37
|
-
|
38
|
-
attr_reader :store, :prefix
|
41
|
+
end
|
39
42
|
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
attr_accessor :key
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
self.class.prefix + key
|
45
|
-
end
|
47
|
+
def prefix_key
|
48
|
+
self.class.prefix + key
|
49
|
+
end
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
51
|
+
def save
|
52
|
+
raise RuntimeError unless key
|
53
|
+
self.class.store[prefix_key] = self
|
54
|
+
self.class.on_save.call(self) if self.class.on_save
|
55
|
+
end
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
def delete
|
58
|
+
raise RuntimeError unless key
|
59
|
+
return unless self.class.store.has_key?(prefix_key)
|
60
|
+
# TODO concurrency here, the store's delete call should cope, but we don't want the callback if something else got in first?
|
61
|
+
# Alternative: ensure that callback handles this case, which is true of HashPersistent::Collection
|
62
|
+
self.class.store.delete(prefix_key)
|
63
|
+
self.class.on_delete.call(self) if self.class.on_delete
|
64
|
+
end
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
data/spec/collection_spec.rb
CHANGED
@@ -13,130 +13,154 @@ class NotAResource
|
|
13
13
|
end
|
14
14
|
|
15
15
|
describe "A class that includes HashPersistent::Collection" do
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
context "(before made persistent)" do
|
17
|
+
it "should include the HashPersistent::Resource module" do
|
18
|
+
CollectionFoo.included_modules.should include (HashPersistent::Resource)
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
it "should not allow itself to be attached to a persistent HashPersistent::Resource until it has been made persistent" do
|
22
|
+
lambda{CollectionFoo.attach(CollectedResource.persist_to({}, ""), :basis)}.should raise_error
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
context "(once made persistent via the persist_to method)" do
|
27
|
+
it "should not add methods, except attach(), before attached to another persisted resource" do
|
28
|
+
# Grey-box here...
|
29
|
+
CollectionFoo.persist_to({}, "").respond_to?(:resource_class).should be_false
|
30
|
+
CollectionFoo.persist_to({}, "").respond_to?(:collected_resource_saved).should be_false
|
31
|
+
CollectionFoo.persist_to({}, "").respond_to?(:collected_resource_deleted).should be_false
|
32
|
+
|
33
|
+
CollectionFoo.persist_to({}, "").new.respond_to?(:collected_keys).should be_false
|
34
|
+
CollectionFoo.persist_to({}, "").new.respond_to?(:collected_resources).should be_false
|
35
|
+
CollectionFoo.persist_to({}, "").new.respond_to?(:collected_resources).should be_false
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not attach to the wrong class type" do
|
39
|
+
lambda{CollectionFoo.attach(NotAResource, :basis)}.should raise_error
|
40
|
+
lambda{CollectionFoo.attach(1, :basis)}.should raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not allow itself to be attached to an un-persisted HashPersistent::Resource" do
|
44
|
+
lambda{CollectionFoo.attach(CollectedResource, :basis)}.should raise_error
|
45
|
+
end
|
46
|
+
|
28
47
|
|
29
|
-
|
30
|
-
|
31
|
-
|
48
|
+
it "should allow itself to be attached to a persisted HashPersistent::Resource, specifying an attribute/method for the collection basis" do
|
49
|
+
lambda{CollectionFoo.persist_to({}, "").attach(CollectedResource.persist_to({}, ""), :basis)}.should_not raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should verify a valid collection basis" do
|
53
|
+
lambda{CollectionFoo.persist_to({}, "").attach(CollectedResource.persist_to({}, ""))}.should raise_error
|
54
|
+
lambda{CollectionFoo.persist_to({}, "").attach(CollectedResource.persist_to({}, ""), :not_a_valid_attr)}.should raise_error
|
55
|
+
end
|
32
56
|
end
|
33
57
|
|
34
58
|
context "(when attached resources are saved/deleted)" do
|
35
59
|
it "should create a collection for a new basis" do
|
36
|
-
CollectionFoo.persist_to({}, "")
|
37
|
-
CollectedResource.persist_to({}, "")
|
60
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
61
|
+
resource_class = CollectedResource.persist_to({}, "")
|
38
62
|
|
39
|
-
|
40
|
-
|
63
|
+
collection_class.attach(resource_class, :basis)
|
64
|
+
collection_class.find("the_basis").should == nil
|
41
65
|
|
42
|
-
resource =
|
66
|
+
resource = resource_class.new
|
43
67
|
resource.basis = "the_basis"
|
44
68
|
resource.key = "fred"
|
45
69
|
resource.save
|
46
70
|
|
47
|
-
|
71
|
+
collection_class.find("the_basis").should_not == nil
|
48
72
|
end
|
49
73
|
|
50
74
|
it "should report keys saved/added to the collection" do
|
51
|
-
CollectionFoo.persist_to({}, "")
|
52
|
-
CollectedResource.persist_to({}, "")
|
75
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
76
|
+
resource_class = CollectedResource.persist_to({}, "")
|
53
77
|
|
54
|
-
|
78
|
+
collection_class.attach(resource_class, :basis)
|
55
79
|
|
56
|
-
resource =
|
80
|
+
resource = resource_class.new
|
57
81
|
resource.basis = "the_basis"
|
58
82
|
resource.key = "fred"
|
59
83
|
resource.save
|
60
84
|
|
61
|
-
|
85
|
+
collection_class.find("the_basis").collected_keys.should == ["fred"]
|
62
86
|
|
63
|
-
resource =
|
87
|
+
resource = resource_class.new
|
64
88
|
resource.basis = "the_basis"
|
65
89
|
resource.key = "barney"
|
66
90
|
resource.save
|
67
91
|
|
68
|
-
|
92
|
+
collection_class.find("the_basis").collected_keys.should == ["fred", "barney"]
|
69
93
|
end
|
70
94
|
|
71
95
|
it "should not duplicate keys when a resource is saved multiple times" do
|
72
|
-
CollectionFoo.persist_to({}, "")
|
73
|
-
CollectedResource.persist_to({}, "")
|
96
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
97
|
+
resource_class = CollectedResource.persist_to({}, "")
|
74
98
|
|
75
|
-
|
99
|
+
collection_class.attach(resource_class, :basis)
|
76
100
|
|
77
|
-
resource =
|
101
|
+
resource = resource_class.new
|
78
102
|
resource.basis = "the_basis"
|
79
103
|
resource.key = "fred"
|
80
104
|
resource.save
|
81
105
|
resource.save
|
82
106
|
|
83
|
-
|
107
|
+
collection_class.find("the_basis").collected_keys.should == ["fred"]
|
84
108
|
end
|
85
109
|
|
86
110
|
it "should not report keys with the wrong basis" do
|
87
|
-
CollectionFoo.persist_to({}, "")
|
88
|
-
CollectedResource.persist_to({}, "")
|
111
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
112
|
+
resource_class = CollectedResource.persist_to({}, "")
|
89
113
|
|
90
|
-
|
114
|
+
collection_class.attach(resource_class, :basis)
|
91
115
|
|
92
|
-
resource =
|
116
|
+
resource = resource_class.new
|
93
117
|
resource.basis = "one_basis"
|
94
118
|
resource.key = "fred"
|
95
119
|
resource.save
|
96
120
|
|
97
|
-
|
121
|
+
collection_class.find("another_basis").should == nil
|
98
122
|
|
99
|
-
resource =
|
123
|
+
resource = resource_class.new
|
100
124
|
resource.basis = "another_basis"
|
101
125
|
resource.key = "barney"
|
102
126
|
resource.save
|
103
127
|
|
104
|
-
|
105
|
-
|
128
|
+
collection_class.find("one_basis").collected_keys.should == ["fred"]
|
129
|
+
collection_class.find("another_basis").collected_keys.should == ["barney"]
|
106
130
|
end
|
107
131
|
|
108
132
|
it "should remove the key when a resource is deleted" do
|
109
|
-
CollectionFoo.persist_to({}, "")
|
110
|
-
CollectedResource.persist_to({}, "")
|
133
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
134
|
+
resource_class = CollectedResource.persist_to({}, "")
|
111
135
|
|
112
|
-
|
136
|
+
collection_class.attach(resource_class, :basis)
|
113
137
|
|
114
|
-
resource =
|
138
|
+
resource = resource_class.new
|
115
139
|
resource.basis = "the_basis"
|
116
140
|
resource.key = "fred"
|
117
141
|
resource.save
|
118
142
|
|
119
|
-
resource =
|
143
|
+
resource = resource_class.new
|
120
144
|
resource.basis = "the_basis"
|
121
145
|
resource.key = "barney"
|
122
146
|
resource.save
|
123
147
|
resource.delete
|
124
148
|
|
125
|
-
|
149
|
+
collection_class.find("the_basis").collected_keys.should == ["fred"]
|
126
150
|
end
|
127
151
|
|
128
152
|
it "should not complain when a not-present key is removed (either not added, or deleted twice)" do
|
129
|
-
CollectionFoo.persist_to({}, "")
|
130
|
-
CollectedResource.persist_to({}, "")
|
153
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
154
|
+
resource_class = CollectedResource.persist_to({}, "")
|
131
155
|
|
132
|
-
|
156
|
+
collection_class.attach(resource_class, :basis)
|
133
157
|
|
134
|
-
resource =
|
158
|
+
resource = resource_class.new
|
135
159
|
resource.basis = "the_basis"
|
136
160
|
resource.key = "fred"
|
137
161
|
resource.save
|
138
162
|
|
139
|
-
resource =
|
163
|
+
resource = resource_class.new
|
140
164
|
resource.basis = "the_basis"
|
141
165
|
resource.key = "barney"
|
142
166
|
|
@@ -146,16 +170,16 @@ describe "A class that includes HashPersistent::Collection" do
|
|
146
170
|
resource.delete
|
147
171
|
lambda{resource.delete}.should_not raise_error
|
148
172
|
|
149
|
-
|
173
|
+
collection_class.find("the_basis").collected_keys.should == ["fred"]
|
150
174
|
end
|
151
175
|
|
152
176
|
it "should not complain when a resource with an unknown basis is removed" do
|
153
|
-
CollectionFoo.persist_to({}, "")
|
154
|
-
CollectedResource.persist_to({}, "")
|
177
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
178
|
+
resource_class = CollectedResource.persist_to({}, "")
|
155
179
|
|
156
|
-
|
180
|
+
collection_class.attach(resource_class, :basis)
|
157
181
|
|
158
|
-
resource =
|
182
|
+
resource = resource_class.new
|
159
183
|
resource.basis = "the_basis"
|
160
184
|
resource.key = "fred"
|
161
185
|
|
@@ -163,46 +187,46 @@ describe "A class that includes HashPersistent::Collection" do
|
|
163
187
|
end
|
164
188
|
|
165
189
|
it "should remove the collection when its final key is removed" do
|
166
|
-
CollectionFoo.persist_to({}, "")
|
167
|
-
CollectedResource.persist_to({}, "")
|
190
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
191
|
+
resource_class = CollectedResource.persist_to({}, "")
|
168
192
|
|
169
|
-
|
193
|
+
collection_class.attach(resource_class, :basis)
|
170
194
|
|
171
|
-
resource =
|
195
|
+
resource = resource_class.new
|
172
196
|
resource.basis = "the_basis"
|
173
197
|
resource.key = "fred"
|
174
198
|
resource.save
|
175
199
|
|
176
|
-
resource =
|
200
|
+
resource = resource_class.new
|
177
201
|
resource.basis = "the_basis"
|
178
202
|
resource.key = "barney"
|
179
203
|
resource.save
|
180
204
|
|
181
|
-
|
182
|
-
|
205
|
+
resource_class.find("fred").delete
|
206
|
+
resource_class.find("barney").delete
|
183
207
|
|
184
|
-
|
208
|
+
collection_class.find("the_basis").should == nil
|
185
209
|
end
|
186
210
|
|
187
211
|
it "should be helpful and derefence its keys when asked" do
|
188
|
-
CollectionFoo.persist_to({}, "")
|
189
|
-
CollectedResource.persist_to({}, "")
|
212
|
+
collection_class = CollectionFoo.persist_to({}, "")
|
213
|
+
resource_class = CollectedResource.persist_to({}, "")
|
190
214
|
|
191
|
-
|
215
|
+
collection_class.attach(resource_class, :basis)
|
192
216
|
|
193
|
-
resource_1 =
|
217
|
+
resource_1 = resource_class.new
|
194
218
|
resource_1.basis = "the_basis"
|
195
219
|
resource_1.key = "fred"
|
196
220
|
resource_1.save
|
197
221
|
|
198
|
-
|
222
|
+
collection_class.find("the_basis").collected_resources.should == [resource_1]
|
199
223
|
|
200
|
-
resource_2 =
|
224
|
+
resource_2 = resource_class.new
|
201
225
|
resource_2.basis = "the_basis"
|
202
226
|
resource_2.key = "barney"
|
203
227
|
resource_2.save
|
204
228
|
|
205
|
-
|
229
|
+
collection_class.find("the_basis").collected_resources.should == [resource_1, resource_2]
|
206
230
|
|
207
231
|
end
|
208
232
|
end
|
data/spec/resource_spec.rb
CHANGED
@@ -25,7 +25,20 @@ class ResourceFooOnlyUsedOnce
|
|
25
25
|
end
|
26
26
|
|
27
27
|
describe "A class that includes HashPersistent::Resource" do
|
28
|
-
context "(
|
28
|
+
context "(not initially useful)" do
|
29
|
+
it "not gain much from the module" do
|
30
|
+
# Grey-box here...
|
31
|
+
lambda{ResourceFoo.store}.should raise_error
|
32
|
+
lambda{ResourceFoo.prefix}.should raise_error
|
33
|
+
lambda{ResourceFoo.on_save}.should raise_error
|
34
|
+
lambda{ResourceFoo.on_delete}.should raise_error
|
35
|
+
lambda{ResourceFoo.find}.should raise_error
|
36
|
+
|
37
|
+
ResourceFoo.new.respond_to?(:key=).should be_false
|
38
|
+
ResourceFoo.new.respond_to?(:save).should be_false
|
39
|
+
ResourceFoo.new.respond_to?(:delete).should be_false
|
40
|
+
end
|
41
|
+
|
29
42
|
it "should acquire a persist_to class method" do
|
30
43
|
ResourceFoo.respond_to?(:persist_to).should be_true
|
31
44
|
end
|
@@ -43,76 +56,127 @@ describe "A class that includes HashPersistent::Resource" do
|
|
43
56
|
it "should reject a non-string-like prefix" do
|
44
57
|
lambda {ResourceFoo.persist_to({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError)
|
45
58
|
end
|
46
|
-
|
47
|
-
|
59
|
+
|
60
|
+
it "should return a sub-class in response to persist_to" do
|
61
|
+
resource_class = ResourceFoo.persist_to({}, "")
|
62
|
+
resource_class.should_not == ResourceFoo
|
63
|
+
resource_class.superclass.should == ResourceFoo
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return a different sub-class each time" do
|
67
|
+
resource_class_1 = ResourceFoo.persist_to({}, "")
|
68
|
+
resource_class_2 = ResourceFoo.persist_to({}, "")
|
69
|
+
resource_class_1.should_not == resource_class_2
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return a sub-class that references the correct store and prefix" do
|
73
|
+
store = Hash.new
|
74
|
+
store["foo"] = "bar"
|
75
|
+
prefix = "baz"
|
76
|
+
resource_class = ResourceFoo.persist_to(store, prefix)
|
77
|
+
resource_class.store.should == store
|
78
|
+
resource_class.prefix.should == prefix
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return not cross-contaminate the store and prefix of subclasses" do
|
82
|
+
store_1 = Hash.new
|
83
|
+
store_1["foo"] = "bar"
|
84
|
+
prefix_1 = "baz"
|
85
|
+
resource_class_1 = ResourceFoo.persist_to(store_1, prefix_1)
|
86
|
+
resource_class_2 = ResourceFoo.persist_to(store_1, prefix_1)
|
87
|
+
|
88
|
+
store_3 = Hash.new
|
89
|
+
store_3["fred"] = "barney"
|
90
|
+
prefix_3 = "wilma"
|
91
|
+
resource_class_3 = ResourceFoo.persist_to(store_3, prefix_3)
|
92
|
+
|
93
|
+
resource_class_1.store.should == resource_class_2.store
|
94
|
+
resource_class_1.prefix.should == resource_class_2.prefix
|
95
|
+
|
96
|
+
resource_class_1.store.should_not == resource_class_3.store
|
97
|
+
resource_class_1.prefix.should_not == resource_class_3.prefix
|
98
|
+
|
99
|
+
resource_class_1.store.should == store_1
|
100
|
+
resource_class_2.store.should == store_1
|
101
|
+
resource_class_3.store.should == store_3
|
102
|
+
|
103
|
+
resource_class_1.prefix.should == prefix_1
|
104
|
+
resource_class_2.prefix.should == prefix_1
|
105
|
+
resource_class_3.prefix.should == prefix_3
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
48
109
|
context "(an instance that has not been saved)" do
|
110
|
+
before(:each) do
|
111
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
112
|
+
end
|
113
|
+
|
49
114
|
it "should maintain a key attribute" do
|
50
|
-
|
51
|
-
|
115
|
+
@resource_class.new.respond_to?(:key).should be_true
|
116
|
+
@resource_class.new.respond_to?(:key=).should be_true
|
52
117
|
end
|
53
118
|
|
54
119
|
it "should respond to a save method" do
|
55
|
-
|
120
|
+
@resource_class.new.respond_to?(:save).should be_true
|
56
121
|
end
|
57
122
|
|
58
123
|
it "should respond to a delete method" do
|
59
|
-
|
124
|
+
@resource_class.new.respond_to?(:delete).should be_true
|
60
125
|
end
|
61
126
|
|
62
127
|
it "should not save unless the key has been explictly set" do
|
63
|
-
lambda{
|
128
|
+
lambda{@resource_class.new.save}.should raise_error
|
64
129
|
end
|
65
130
|
|
66
131
|
it "should not delete unless the key has been explictly set" do
|
67
|
-
lambda{
|
132
|
+
lambda{@resource_class.new.delete}.should raise_error
|
68
133
|
end
|
69
134
|
|
70
135
|
it "should not complain when deleted, even after a key is set" do
|
71
|
-
|
72
|
-
resource = ResourceFoo.new
|
136
|
+
resource = @resource_class.new
|
73
137
|
resource.key = "fred"
|
74
138
|
lambda{resource.delete}.should_not raise_error
|
75
139
|
end
|
76
140
|
|
77
141
|
it "should not be findable via its key" do
|
78
|
-
|
79
|
-
resource = ResourceFoo.new
|
142
|
+
resource = @resource_class.new
|
80
143
|
resource.key = "fred"
|
81
|
-
|
82
|
-
|
144
|
+
@resource_class.find("fred").should == nil
|
145
|
+
@resource_class.find("barney").should == nil
|
83
146
|
end
|
84
147
|
end
|
85
148
|
|
86
149
|
context "(an instance that has been saved)" do
|
150
|
+
before(:each) do
|
151
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
152
|
+
@resource_class_with_state = ResourceFooWithState.persist_to({}, "")
|
153
|
+
end
|
154
|
+
|
87
155
|
it "should be findable via its key" do
|
88
|
-
|
89
|
-
resource = ResourceFoo.new
|
156
|
+
resource = @resource_class.new
|
90
157
|
resource.key = "fred"
|
91
158
|
resource.save
|
92
|
-
|
159
|
+
@resource_class.find("fred").should_not be_nil
|
93
160
|
end
|
94
161
|
|
95
162
|
it "should correctly recover all of its state" do
|
96
|
-
|
97
|
-
resource = ResourceFooWithState.new
|
163
|
+
resource = @resource_class_with_state.new
|
98
164
|
resource.key = "fred"
|
99
165
|
resource.dummy = ["something random", {}]
|
100
166
|
resource.save
|
101
167
|
resource_dup = resource.dup
|
102
|
-
|
168
|
+
@resource_class_with_state.find("fred").should == resource_dup
|
103
169
|
end
|
104
170
|
|
105
171
|
it "should be deletable" do
|
106
|
-
|
107
|
-
resource = ResourceFoo.new
|
172
|
+
resource = @resource_class.new
|
108
173
|
resource.key = "fred"
|
109
174
|
resource.save
|
110
175
|
lambda{resource.delete}.should_not raise_error
|
111
176
|
end
|
112
177
|
|
113
178
|
it "should save a new state when asked" do
|
114
|
-
|
115
|
-
resource = ResourceFooWithState.new
|
179
|
+
resource = @resource_class_with_state.new
|
116
180
|
resource.key = "fred"
|
117
181
|
|
118
182
|
resource.dummy = ["something random", {}]
|
@@ -123,24 +187,26 @@ describe "A class that includes HashPersistent::Resource" do
|
|
123
187
|
resource.save
|
124
188
|
resource_dup_2 = resource.dup
|
125
189
|
|
126
|
-
|
127
|
-
|
190
|
+
@resource_class_with_state.find("fred").should_not == resource_dup_1
|
191
|
+
@resource_class_with_state.find("fred").should == resource_dup_2
|
128
192
|
end
|
129
193
|
end
|
130
194
|
|
131
195
|
context "(an instance that has been saved and then deleted)" do
|
196
|
+
before(:each) do
|
197
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
198
|
+
end
|
199
|
+
|
132
200
|
it "should not be findable via its key" do
|
133
|
-
|
134
|
-
resource = ResourceFoo.new
|
201
|
+
resource = @resource_class.new
|
135
202
|
resource.key = "fred"
|
136
203
|
resource.save
|
137
204
|
resource.delete
|
138
|
-
|
205
|
+
@resource_class.find("fred").should == nil
|
139
206
|
end
|
140
207
|
|
141
208
|
it "should not complain when deleted" do
|
142
|
-
|
143
|
-
resource = ResourceFoo.new
|
209
|
+
resource = @resource_class.new
|
144
210
|
resource.key = "fred"
|
145
211
|
resource.save
|
146
212
|
resource.delete
|
@@ -149,157 +215,104 @@ describe "A class that includes HashPersistent::Resource" do
|
|
149
215
|
end
|
150
216
|
|
151
217
|
context "(use of prefix to namespace keys)" do
|
218
|
+
before(:each) do
|
219
|
+
@resource_class = ResourceFoo.persist_to({}, "a_random_namespace::")
|
220
|
+
end
|
221
|
+
|
152
222
|
it "should (transparently) prepend the supplied prefix to the key of the saved instance" do
|
153
|
-
|
154
|
-
ResourceFoo.persist_to(store, "a_random_namespace::")
|
155
|
-
resource = ResourceFoo.new
|
223
|
+
resource = @resource_class.new
|
156
224
|
resource.key = "fred"
|
157
225
|
resource.save
|
158
|
-
store.should_not have_key("fred")
|
159
|
-
store.should have_key("a_random_namespace::fred")
|
226
|
+
@resource_class.store.should_not have_key("fred")
|
227
|
+
@resource_class.store.should have_key("a_random_namespace::fred")
|
160
228
|
end
|
161
229
|
|
162
230
|
it "should find instances when using a namespace, using only the key" do
|
163
|
-
|
164
|
-
ResourceFoo.persist_to(store, "a_random_namespace::")
|
165
|
-
resource = ResourceFoo.new
|
231
|
+
resource = @resource_class.new
|
166
232
|
resource.key = "fred"
|
167
233
|
resource.save
|
168
|
-
|
234
|
+
@resource_class.find("fred").should_not == nil
|
169
235
|
end
|
170
236
|
|
171
237
|
it "should not find instances when mistakenly given a namespaced key" do
|
172
|
-
|
173
|
-
ResourceFoo.persist_to(store, "a_random_namespace::")
|
174
|
-
resource = ResourceFoo.new
|
238
|
+
resource = @resource_class.new
|
175
239
|
resource.key = "fred"
|
176
240
|
resource.save
|
177
|
-
|
241
|
+
@resource_class.find("a_random_namespace::fred").should == nil
|
178
242
|
end
|
179
243
|
|
180
244
|
it "should correctly delete an instance from the store when using a prefix" do
|
181
|
-
|
182
|
-
ResourceFoo.persist_to(store, "a_random_namespace::")
|
183
|
-
resource = ResourceFoo.new
|
245
|
+
resource = @resource_class.new
|
184
246
|
resource.key = "fred"
|
185
247
|
resource.save
|
186
248
|
resource.delete
|
187
|
-
|
249
|
+
@resource_class.find("fred").should == nil
|
250
|
+
@resource_class.store.should == {}
|
188
251
|
end
|
189
252
|
end
|
190
253
|
|
191
254
|
context "(use of store)" do
|
192
255
|
it "should correctly delete items from the store" do
|
193
|
-
|
194
|
-
|
195
|
-
resource_1 = ResourceFoo.new
|
256
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
257
|
+
resource_1 = @resource_class.new
|
196
258
|
resource_1.key = "fred"
|
197
259
|
resource_1.save
|
198
260
|
|
199
|
-
resource_2 =
|
261
|
+
resource_2 = @resource_class.new
|
200
262
|
resource_2.key = "barney"
|
201
263
|
resource_2.save
|
202
|
-
store.should_not ==
|
264
|
+
@resource_class.store.should_not == {}
|
203
265
|
|
204
266
|
resource_1.delete
|
267
|
+
@resource_class.store.should_not == {}
|
268
|
+
|
205
269
|
resource_2.delete
|
206
|
-
store.should ==
|
270
|
+
@resource_class.store.should == {}
|
207
271
|
end
|
208
272
|
end
|
209
|
-
|
273
|
+
|
210
274
|
context "(use of restricted hash api)" do
|
211
275
|
it "should use only the restricted hash api provided by moneta" do
|
212
276
|
lambda {
|
213
|
-
ResourceFooWithState.persist_to(Dummy_RestrictedHash.new, "prefix::")
|
214
|
-
resource_1 =
|
277
|
+
@resource_class = ResourceFooWithState.persist_to(Dummy_RestrictedHash.new, "prefix::")
|
278
|
+
resource_1 = @resource_class.new
|
215
279
|
resource_1.key = "fred"
|
216
280
|
resource_1.dummy = ["barney"]
|
217
281
|
resource_1.save
|
218
|
-
|
282
|
+
@resource_class.find("fred").delete
|
219
283
|
}.should_not raise_error
|
220
284
|
end
|
221
285
|
end
|
222
|
-
|
223
|
-
context "(default store)" do
|
224
|
-
it "should function with a vdefault store/prefix if none is supplied" do
|
225
|
-
# This is implicitly tested elsewhere. Which makes this test documentation, I guess
|
226
|
-
resource_1 = ResourceFooOnlyUsedOnce.new
|
227
|
-
resource_1.key = "fred"
|
228
|
-
resource_1.dummy = ["barney"]
|
229
|
-
resource_1.save
|
230
|
-
ResourceFooOnlyUsedOnce.find("fred").should == resource_1.dup
|
231
|
-
lambda {ResourceFooOnlyUsedOnce.find("fred").delete}.should_not raise_error
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
context "(multiple classes using module)" do
|
236
|
-
# TODO: should check the callbacks here? Seems over the top...
|
237
|
-
it "should not cross-contaminate classes that include the module" do
|
238
|
-
store_1 = Hash.new
|
239
|
-
ResourceFoo.persist_to(store_1, "")
|
240
|
-
store_2 = Hash.new
|
241
|
-
ResourceFooWithState.persist_to(store_2, "prefix::")
|
242
|
-
|
243
|
-
store_1.should == Hash.new
|
244
|
-
store_2.should == Hash.new
|
245
|
-
|
246
|
-
resource_1 = ResourceFoo.new
|
247
|
-
resource_1.key = "1"
|
248
|
-
resource_1.save
|
249
|
-
|
250
|
-
store_1.should_not == Hash.new
|
251
|
-
store_2.should == Hash.new
|
252
|
-
store_1.should have_key("1")
|
253
|
-
store_1.should_not have_key("prefix::1")
|
254
|
-
|
255
|
-
resource_1.delete
|
256
|
-
|
257
|
-
store_1.should == Hash.new
|
258
|
-
store_2.should == Hash.new
|
259
|
-
|
260
|
-
resource_2 = ResourceFooWithState.new
|
261
|
-
resource_2.key = "2"
|
262
|
-
resource_2.save
|
263
|
-
|
264
|
-
store_1.should == Hash.new
|
265
|
-
store_2.should_not == Hash.new
|
266
|
-
store_2.should have_key("prefix::2")
|
267
|
-
store_2.should_not have_key("2")
|
268
|
-
|
269
|
-
resource_2.delete
|
270
|
-
|
271
|
-
store_1.should == Hash.new
|
272
|
-
store_2.should == Hash.new
|
273
|
-
end
|
274
|
-
end
|
275
286
|
|
276
287
|
context "(callbacks)" do
|
277
288
|
it "should allow a class level callback to be set and retrieved for save events" do
|
278
|
-
ResourceFoo.
|
279
|
-
|
289
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
290
|
+
@resource_class.on_save.should == nil
|
291
|
+
|
292
|
+
@resource_class.on_save do
|
280
293
|
"thing"
|
281
|
-
end
|
282
|
-
|
283
|
-
lambda{ResourceFoo.on_save(1)}.should raise_error
|
294
|
+
end
|
295
|
+
@resource_class.on_save.call.should == "thing"
|
284
296
|
end
|
285
297
|
|
286
298
|
it "should allow a class level callback to be set and retrieved for delete events" do
|
287
|
-
ResourceFoo.
|
288
|
-
|
299
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
300
|
+
@resource_class.on_delete.should == nil
|
301
|
+
@resource_class.on_delete do
|
289
302
|
"thing"
|
290
|
-
end
|
291
|
-
|
292
|
-
lambda{ResourceFoo.on_delete(1)}.should raise_error
|
303
|
+
end
|
304
|
+
@resource_class.on_delete.call.should == "thing"
|
293
305
|
end
|
294
306
|
|
295
307
|
it "should yield an instance to the save callback when the instance is saved" do
|
308
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
296
309
|
yielded_instance = nil
|
297
|
-
|
310
|
+
@resource_class.on_save do |yielded|
|
298
311
|
yielded_instance = yielded
|
299
312
|
end
|
300
313
|
|
301
|
-
instance =
|
302
|
-
instance.key = "
|
314
|
+
instance = @resource_class.new
|
315
|
+
instance.key = "fah"
|
303
316
|
instance.save
|
304
317
|
|
305
318
|
yielded_instance.should_not == nil
|
@@ -307,13 +320,14 @@ describe "A class that includes HashPersistent::Resource" do
|
|
307
320
|
end
|
308
321
|
|
309
322
|
it "should yield an instance to the delete callback when the instance is deleted" do
|
323
|
+
@resource_class = ResourceFoo.persist_to({}, "")
|
310
324
|
yielded_instance = nil
|
311
|
-
|
325
|
+
@resource_class.on_delete do |yielded|
|
312
326
|
yielded_instance = yielded
|
313
327
|
end
|
314
328
|
|
315
|
-
instance =
|
316
|
-
instance.key = "
|
329
|
+
instance = @resource_class.new
|
330
|
+
instance.key = "bah"
|
317
331
|
instance.save
|
318
332
|
instance.delete
|
319
333
|
|
@@ -321,5 +335,21 @@ describe "A class that includes HashPersistent::Resource" do
|
|
321
335
|
yielded_instance.should == instance
|
322
336
|
end
|
323
337
|
|
338
|
+
it "should maintain separate callbacks for each created subclass" do
|
339
|
+
@resource_class_1 = ResourceFoo.persist_to({}, "")
|
340
|
+
@resource_class_2 = ResourceFoo.persist_to({}, "")
|
341
|
+
|
342
|
+
@resource_class_1.on_save do "on_save_1" end
|
343
|
+
@resource_class_1.on_delete do "on_delete_1" end
|
344
|
+
|
345
|
+
@resource_class_2.on_save do "on_save_2" end
|
346
|
+
@resource_class_2.on_delete do "on_delete_2" end
|
347
|
+
|
348
|
+
@resource_class_1.on_delete.call.should == "on_delete_1"
|
349
|
+
@resource_class_1.on_save.call.should == "on_save_1"
|
350
|
+
|
351
|
+
@resource_class_2.on_delete.call.should == "on_delete_2"
|
352
|
+
@resource_class_2.on_save.call.should == "on_save_2"
|
353
|
+
end
|
324
354
|
end
|
325
355
|
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.
|
4
|
+
version: 0.3.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-06-
|
12
|
+
date: 2009-06-04 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -64,7 +64,7 @@ rubyforge_project:
|
|
64
64
|
rubygems_version: 1.2.0
|
65
65
|
signing_key:
|
66
66
|
specification_version: 3
|
67
|
-
summary: Library of base classes to simplify persisting objects
|
67
|
+
summary: Library of base classes to simplify persisting objects and collections to a moneta store
|
68
68
|
test_files:
|
69
69
|
- spec/collection_spec.rb
|
70
70
|
- spec/counter_spec.rb
|