toystore 0.5

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.
Files changed (113) hide show
  1. data/.autotest +11 -0
  2. data/.bundle/config +2 -0
  3. data/.gitignore +6 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.lock +49 -0
  6. data/LICENSE +9 -0
  7. data/LOGGING.rdoc +16 -0
  8. data/README.rdoc +13 -0
  9. data/Rakefile +7 -0
  10. data/examples/memcached.rb +20 -0
  11. data/examples/memory.rb +20 -0
  12. data/examples/models.rb +51 -0
  13. data/examples/redis.rb +20 -0
  14. data/lib/toy.rb +81 -0
  15. data/lib/toy/attribute.rb +73 -0
  16. data/lib/toy/attributes.rb +137 -0
  17. data/lib/toy/caching.rb +20 -0
  18. data/lib/toy/callbacks.rb +48 -0
  19. data/lib/toy/collection.rb +55 -0
  20. data/lib/toy/connection.rb +28 -0
  21. data/lib/toy/dirty.rb +47 -0
  22. data/lib/toy/dolly.rb +30 -0
  23. data/lib/toy/embedded_list.rb +45 -0
  24. data/lib/toy/embedded_lists.rb +68 -0
  25. data/lib/toy/equality.rb +19 -0
  26. data/lib/toy/exceptions.rb +29 -0
  27. data/lib/toy/extensions/array.rb +22 -0
  28. data/lib/toy/extensions/boolean.rb +43 -0
  29. data/lib/toy/extensions/date.rb +24 -0
  30. data/lib/toy/extensions/float.rb +13 -0
  31. data/lib/toy/extensions/hash.rb +17 -0
  32. data/lib/toy/extensions/integer.rb +22 -0
  33. data/lib/toy/extensions/nil_class.rb +17 -0
  34. data/lib/toy/extensions/object.rb +26 -0
  35. data/lib/toy/extensions/set.rb +23 -0
  36. data/lib/toy/extensions/string.rb +17 -0
  37. data/lib/toy/extensions/time.rb +29 -0
  38. data/lib/toy/identity.rb +26 -0
  39. data/lib/toy/identity/abstract_key_factory.rb +10 -0
  40. data/lib/toy/identity/uuid_key_factory.rb +9 -0
  41. data/lib/toy/identity_map.rb +109 -0
  42. data/lib/toy/index.rb +74 -0
  43. data/lib/toy/indices.rb +56 -0
  44. data/lib/toy/inspect.rb +12 -0
  45. data/lib/toy/list.rb +46 -0
  46. data/lib/toy/lists.rb +37 -0
  47. data/lib/toy/logger.rb +26 -0
  48. data/lib/toy/mass_assignment_security.rb +16 -0
  49. data/lib/toy/persistence.rb +138 -0
  50. data/lib/toy/plugins.rb +23 -0
  51. data/lib/toy/proxies/embedded_list.rb +74 -0
  52. data/lib/toy/proxies/list.rb +97 -0
  53. data/lib/toy/proxies/proxy.rb +59 -0
  54. data/lib/toy/querying.rb +57 -0
  55. data/lib/toy/reference.rb +134 -0
  56. data/lib/toy/references.rb +19 -0
  57. data/lib/toy/serialization.rb +81 -0
  58. data/lib/toy/store.rb +36 -0
  59. data/lib/toy/timestamps.rb +22 -0
  60. data/lib/toy/validations.rb +45 -0
  61. data/lib/toy/version.rb +3 -0
  62. data/lib/toystore.rb +1 -0
  63. data/spec/helper.rb +35 -0
  64. data/spec/spec.opts +3 -0
  65. data/spec/support/constants.rb +41 -0
  66. data/spec/support/identity_map_matcher.rb +20 -0
  67. data/spec/support/name_and_number_key_factory.rb +5 -0
  68. data/spec/toy/attribute_spec.rb +176 -0
  69. data/spec/toy/attributes_spec.rb +394 -0
  70. data/spec/toy/caching_spec.rb +62 -0
  71. data/spec/toy/callbacks_spec.rb +97 -0
  72. data/spec/toy/connection_spec.rb +47 -0
  73. data/spec/toy/dirty_spec.rb +99 -0
  74. data/spec/toy/dolly_spec.rb +76 -0
  75. data/spec/toy/embedded_list_spec.rb +607 -0
  76. data/spec/toy/embedded_lists_spec.rb +172 -0
  77. data/spec/toy/equality_spec.rb +46 -0
  78. data/spec/toy/exceptions_spec.rb +18 -0
  79. data/spec/toy/extensions/array_spec.rb +25 -0
  80. data/spec/toy/extensions/boolean_spec.rb +41 -0
  81. data/spec/toy/extensions/date_spec.rb +48 -0
  82. data/spec/toy/extensions/float_spec.rb +14 -0
  83. data/spec/toy/extensions/hash_spec.rb +21 -0
  84. data/spec/toy/extensions/integer_spec.rb +29 -0
  85. data/spec/toy/extensions/nil_class_spec.rb +14 -0
  86. data/spec/toy/extensions/set_spec.rb +27 -0
  87. data/spec/toy/extensions/string_spec.rb +28 -0
  88. data/spec/toy/extensions/time_spec.rb +94 -0
  89. data/spec/toy/identity/abstract_key_factory_spec.rb +7 -0
  90. data/spec/toy/identity/uuid_key_factory_spec.rb +7 -0
  91. data/spec/toy/identity_map_spec.rb +150 -0
  92. data/spec/toy/identity_spec.rb +52 -0
  93. data/spec/toy/index_spec.rb +230 -0
  94. data/spec/toy/indices_spec.rb +141 -0
  95. data/spec/toy/inspect_spec.rb +15 -0
  96. data/spec/toy/list_spec.rb +576 -0
  97. data/spec/toy/lists_spec.rb +95 -0
  98. data/spec/toy/logger_spec.rb +33 -0
  99. data/spec/toy/mass_assignment_security_spec.rb +116 -0
  100. data/spec/toy/persistence_spec.rb +312 -0
  101. data/spec/toy/plugins_spec.rb +39 -0
  102. data/spec/toy/querying_spec.rb +162 -0
  103. data/spec/toy/reference_spec.rb +400 -0
  104. data/spec/toy/references_spec.rb +86 -0
  105. data/spec/toy/serialization_spec.rb +354 -0
  106. data/spec/toy/store_spec.rb +41 -0
  107. data/spec/toy/timestamps_spec.rb +63 -0
  108. data/spec/toy/validations_spec.rb +171 -0
  109. data/spec/toy_spec.rb +26 -0
  110. data/specs.watchr +52 -0
  111. data/test/lint_test.rb +40 -0
  112. data/toystore.gemspec +24 -0
  113. metadata +290 -0
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Plugins do
4
+ uses_constants('User', 'Game')
5
+
6
+ it "keeps track of class that include toy store" do
7
+ Toy.models.should == [User, Game].to_set
8
+ end
9
+
10
+ describe ".plugin" do
11
+ before do
12
+ class_methods_mod = Module.new { def foo; 'foo' end }
13
+ instance_methods_mod = Module.new { def bar; 'bar' end }
14
+
15
+ @mod = Module.new { extend ActiveSupport::Concern }
16
+ @mod.const_set(:ClassMethods, class_methods_mod)
17
+ @mod.const_set(:InstanceMethods, instance_methods_mod)
18
+
19
+ Toy.plugin(@mod)
20
+ end
21
+
22
+ it "includes module in all models" do
23
+ [User, Game].each do |model|
24
+ model.foo.should == 'foo'
25
+ model.new.bar.should == 'bar'
26
+ end
27
+ end
28
+
29
+ it "adds plugin to plugins" do
30
+ Toy.plugins.should == [@mod].to_set
31
+ end
32
+
33
+ it "adds plugins to classes declared after plugin was called" do
34
+ create_constant('Move')
35
+ Move.foo.should == 'foo'
36
+ Move.new.bar.should == 'bar'
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,162 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Querying do
4
+ uses_constants('User', 'Game')
5
+
6
+ before do
7
+ User.attribute :name, String
8
+ end
9
+
10
+ describe ".get" do
11
+ it "returns document if found" do
12
+ john = User.create(:name => 'John')
13
+ User.get(john.id).name.should == 'John'
14
+ end
15
+
16
+ it "returns nil if not found" do
17
+ User.get('1').should be_nil
18
+ end
19
+ end
20
+
21
+ describe ".get!" do
22
+ it "returns document if found" do
23
+ john = User.create(:name => 'John')
24
+ User.get!(john.id).name.should == 'John'
25
+ end
26
+
27
+ it "raises not found exception if not found" do
28
+ lambda {
29
+ User.get!('1')
30
+ }.should raise_error(Toy::NotFound, 'Could not find document with id: "1"')
31
+ end
32
+ end
33
+
34
+ describe ".get_multi" do
35
+ it "returns array of documents" do
36
+ john = User.create(:name => 'John')
37
+ steve = User.create(:name => 'Steve')
38
+ User.get_multi(john.id, steve.id).should == [john, steve]
39
+ end
40
+ end
41
+
42
+ describe ".get_or_new" do
43
+ it "returns found" do
44
+ user = User.create
45
+ User.get_or_new(user.id).should == user
46
+ end
47
+
48
+ it "creates new with id set if not found" do
49
+ user = User.get_or_new('foo')
50
+ user.should be_instance_of(User)
51
+ user.id.should == 'foo'
52
+ end
53
+ end
54
+
55
+ describe ".get_or_create" do
56
+ it "returns found" do
57
+ user = User.create
58
+ User.get_or_create(user.id).should == user
59
+ end
60
+
61
+ it "creates new with id set if not found" do
62
+ user = User.get_or_create('foo')
63
+ user.should be_instance_of(User)
64
+ user.id.should == 'foo'
65
+ end
66
+ end
67
+
68
+ describe ".key?" do
69
+ it "returns true if key exists" do
70
+ user = User.create(:name => 'John')
71
+ User.key?(user.id).should be_true
72
+ end
73
+
74
+ it "returns false if key does not exist" do
75
+ User.key?('taco:bell:tacos').should be_false
76
+ end
77
+ end
78
+
79
+ describe ".has_key?" do
80
+ it "returns true if key exists" do
81
+ user = User.create(:name => 'John')
82
+ User.has_key?(user.id).should be_true
83
+ end
84
+
85
+ it "returns false if key does not exist" do
86
+ User.has_key?('taco:bell:tacos').should be_false
87
+ end
88
+ end
89
+
90
+ describe ".load (with hash)" do
91
+ before { @doc = User.load(:id => '1', :name => 'John') }
92
+ let(:doc) { @doc }
93
+
94
+ it "returns instance" do
95
+ doc.should be_instance_of(User)
96
+ end
97
+
98
+ it "marks object as persisted" do
99
+ doc.should be_persisted
100
+ end
101
+
102
+ it "decodes the object" do
103
+ doc.name.should == 'John'
104
+ end
105
+ end
106
+
107
+ describe "with cache store" do
108
+ before do
109
+ @cache = User.cache(:memory, {})
110
+ @memory = User.store(:memory, {})
111
+ @user = User.create
112
+ Toy.identity_map.clear # ensure we are just working with database
113
+ end
114
+
115
+ let(:cache) { @cache }
116
+ let(:memory) { @memory }
117
+ let(:user) { @user }
118
+
119
+ describe "not found in cache or store" do
120
+ before do
121
+ cache.delete(user.store_key)
122
+ memory.delete(user.store_key)
123
+ end
124
+
125
+ it "returns nil" do
126
+ User.get('foo').should be_nil
127
+ end
128
+ end
129
+
130
+ describe "not found in cache" do
131
+ before do
132
+ cache.delete(user.store_key)
133
+ end
134
+
135
+ it "returns from store" do
136
+ User.get(user.id).should == user
137
+ end
138
+
139
+ it "populates cache" do
140
+ cache.key?(user.store_key).should be_false
141
+ User.get(user.id)
142
+ cache.key?(user.store_key).should be_true
143
+ end
144
+ end
145
+
146
+ describe "found in cache" do
147
+ before do
148
+ cache.key?(user.store_key).should be_true
149
+ end
150
+
151
+ it "returns from cache" do
152
+ cache.should_receive(:read).with(user.store_key).and_return(user.persisted_attributes)
153
+ User.get(user.id)
154
+ end
155
+
156
+ it "does not hit store" do
157
+ memory.should_not_receive(:read)
158
+ User.get(user.id)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,400 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Reference do
4
+ uses_constants('User', 'Game', 'Move')
5
+
6
+ before do
7
+ @reference = Game.reference(:user)
8
+ end
9
+
10
+ let(:reference) { @reference }
11
+
12
+ it "has model" do
13
+ reference.model.should == Game
14
+ end
15
+
16
+ it "has name" do
17
+ reference.name.should == :user
18
+ end
19
+
20
+ it "has type" do
21
+ reference.type.should == User
22
+ end
23
+
24
+ it "has key" do
25
+ reference.key.should == :user_id
26
+ end
27
+
28
+ it "has instance_variable" do
29
+ reference.instance_variable.should == :@_user
30
+ end
31
+
32
+ it "adds reference to model" do
33
+ Game.references.keys.should include(:user)
34
+ end
35
+
36
+ it "adds attribute to model" do
37
+ Game.attributes.keys.should include('user_id')
38
+ end
39
+
40
+ it "adds reader method" do
41
+ Game.new.should respond_to(:user)
42
+ end
43
+
44
+ it "adds writer method" do
45
+ Game.new.should respond_to(:user=)
46
+ end
47
+
48
+ describe "#eql?" do
49
+ it "returns true if same class, model, and name" do
50
+ reference.should eql(reference)
51
+ end
52
+
53
+ it "returns false if not same class" do
54
+ reference.should_not eql({})
55
+ end
56
+
57
+ it "returns false if not same model" do
58
+ reference.should_not eql(Toy::Reference.new(Move, :user))
59
+ end
60
+
61
+ it "returns false if not the same name" do
62
+ reference.should_not eql(Toy::Reference.new(Game, :move))
63
+ end
64
+ end
65
+
66
+ describe "setting reference type" do
67
+ before do
68
+ @reference = Game.reference(:creator, User)
69
+ end
70
+ let(:reference) { @reference }
71
+
72
+ it "uses type provided instead of inferring from name" do
73
+ reference.type.should be(User)
74
+ end
75
+
76
+ it "works properly when reading and writing" do
77
+ user = User.create
78
+ game = Game.create
79
+ game.creator = user
80
+ game.creator.should == user
81
+ end
82
+ end
83
+
84
+ describe "reference reader" do
85
+ before do
86
+ @user = User.create
87
+ @game = Game.create(:user_id => @user.id)
88
+ end
89
+
90
+ it "returns instance" do
91
+ @game.user.should == @user
92
+ end
93
+
94
+ it "memoizes result" do
95
+ @game.user.should == @user
96
+ User.should_not_receive(:get)
97
+ @game.user.should == @user
98
+ end
99
+
100
+ it "does not query if id attribute is blank" do
101
+ game = Game.create
102
+ User.should_not_receive(:get)
103
+ game.user
104
+ end
105
+ end
106
+
107
+ describe "reference writer" do
108
+ before do
109
+ @user1 = User.create
110
+ @user2 = User.create
111
+ @game = Game.create
112
+ @game.user = @user1
113
+ end
114
+
115
+ it "sets the attribute" do
116
+ @game.user_id.should == @user1.id
117
+ end
118
+
119
+ it "unmemoizes the reader" do
120
+ @game.user.should == @user1
121
+ @game.user = @user2
122
+ @game.user.should == @user2
123
+ end
124
+
125
+ it "raises error if wrong type assigned" do
126
+ lambda {
127
+ @game.user = Move.new
128
+ }.should raise_error(ArgumentError, "User expected, but was Move")
129
+ end
130
+
131
+ it "should not reload target when setting to an object" do
132
+ User.should_not_receive(:get)
133
+ user = User.new
134
+ @game.user = user
135
+ @game.user.should == user
136
+ end
137
+
138
+ describe "with nil value" do
139
+ before do
140
+ @game.user = nil
141
+ end
142
+
143
+ it "returns nil for reader" do
144
+ @game.user.should be_nil
145
+ end
146
+
147
+ it "returns nil for attribute" do
148
+ @game.user_id.should be_nil
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "reference boolean" do
154
+ before do
155
+ @user = User.create
156
+ @game = Game.create
157
+ end
158
+
159
+ it "returns false if not set" do
160
+ @game.user?.should be_false
161
+ end
162
+
163
+ it "returns true if set" do
164
+ @game.user = @user
165
+ @game.user?.should be_true
166
+ end
167
+ end
168
+
169
+ describe "reference#nil?" do
170
+ before do
171
+ @user = User.create
172
+ @game = Game.create
173
+ end
174
+
175
+ it "returns true if nil" do
176
+ @game.user.should be_nil
177
+ end
178
+
179
+ it "returns false if not nil" do
180
+ @game.user = @user
181
+ @game.user.should_not be_nil
182
+ end
183
+ end
184
+
185
+ describe "reference#blank?" do
186
+ before do
187
+ @user = User.create
188
+ @game = Game.create
189
+ end
190
+
191
+ it "returns true if nil" do
192
+ @game.user.should be_blank
193
+ end
194
+
195
+ it "returns false if not nil" do
196
+ @game.user = @user
197
+ @game.user.should_not be_blank
198
+ end
199
+ end
200
+
201
+ describe "reference#present?" do
202
+ before do
203
+ @user = User.create
204
+ @game = Game.create
205
+ end
206
+
207
+ it "returns true if present" do
208
+ @game.user = @user
209
+ @game.user.should be_present
210
+ end
211
+
212
+ it "returns false if not present" do
213
+ @game.user.should_not be_present
214
+ end
215
+ end
216
+
217
+ describe "reference#reset" do
218
+ before do
219
+ @user = User.create
220
+ @game = Game.create(:user => @user)
221
+ end
222
+
223
+ it "unmemoizes the list" do
224
+ @game.user.should == @user
225
+ @game.user.reset
226
+ User.should_receive(:get).and_return(@user)
227
+ @game.user.should == @user
228
+ end
229
+
230
+ it "should be reset when owner is reloaded" do
231
+ @game.reload
232
+ User.should_receive(:get).and_return(@user)
233
+ @game.user.should == @user
234
+ end
235
+ end
236
+
237
+ context "delegating" do
238
+ describe "when target is nil" do
239
+ before do
240
+ @game = Game.create
241
+ end
242
+
243
+ it "returns nil if nil" do
244
+ @game.user.inspect.should == 'nil'
245
+ end
246
+
247
+ it "delegates #kind_of?" do
248
+ @game.user.kind_of?(NilClass).should be_true
249
+ @game.user.kind_of?(User).should be_false
250
+ end
251
+
252
+ it "delegates #instance_of?" do
253
+ @game.user.instance_of?(NilClass).should be_true
254
+ @game.user.instance_of?(User).should be_false
255
+ end
256
+
257
+ it "delegates #is_a?" do
258
+ @game.user.is_a?(NilClass).should be_true
259
+ @game.user.is_a?(User).should be_false
260
+ end
261
+
262
+ it "delegates #eql?" do
263
+ @game.user.should eql(nil)
264
+ @game.user.should_not eql(User.create)
265
+ @game.user.should_not eql(@game)
266
+ end
267
+
268
+ it "delegates #equal?" do
269
+ @game.user.should equal(nil)
270
+ @game.user.should_not equal(User.create)
271
+ @game.user.should_not equal(@game)
272
+ end
273
+ end
274
+
275
+ describe "when target is not nil" do
276
+ before do
277
+ @user = User.create
278
+ @game = Game.create(:user => @user)
279
+ end
280
+
281
+ it "delegates #inspect" do
282
+ @game.user = @user
283
+ @game.user.inspect.should == %Q(#<User:#{@user.object_id} id: "#{@user.id}">)
284
+ end
285
+
286
+ it "delegates #==" do
287
+ (@game.user == @user).should be_true
288
+ (@user == @game.user).should be_true
289
+ end
290
+
291
+ it "delegates #is_a?" do
292
+ @game.user.is_a?(User).should be_true
293
+ @game.user.is_a?(Game).should be_false
294
+ end
295
+
296
+ it "delegates #kind_of?" do
297
+ @game.user.kind_of?(User).should be_true
298
+ @game.user.kind_of?(Game).should be_false
299
+ end
300
+
301
+ it "delegates #instance_of?" do
302
+ @game.user.instance_of?(User).should be_true
303
+ @game.user.instance_of?(Game).should be_false
304
+ end
305
+
306
+ it "delegates #eql?" do
307
+ @game.user.should eql(@user)
308
+ @game.user.should_not eql(User.create)
309
+ @game.user.should_not eql(@game)
310
+ end
311
+
312
+ it "delegates #equal?" do
313
+ @game.user.should equal(@user)
314
+ @user.should equal(@game.user)
315
+ @game.user.should equal(User.get(@user.id)) # identity map
316
+ @game.user.should_not equal(User.create)
317
+ @game.user.should_not equal(@game)
318
+ end
319
+ end
320
+ end
321
+
322
+ shared_examples_for 'reference#create' do
323
+ it "returns instance" do
324
+ @user.should be_instance_of(User)
325
+ end
326
+
327
+ it "creates instance" do
328
+ @user.should be_persisted
329
+ end
330
+
331
+ it "sets id attribute" do
332
+ @game.user_id.should == @user.id
333
+ end
334
+ end
335
+
336
+ describe "reference#create" do
337
+ before do
338
+ @game = Game.create
339
+ @user = @game.user.create
340
+ end
341
+
342
+ it_should_behave_like 'reference#create'
343
+ end
344
+
345
+ describe "reference#create (with attributes)" do
346
+ before do
347
+ User.attribute(:name, String)
348
+ @game = Game.create
349
+ @user = @game.user.create(:name => 'John')
350
+ end
351
+
352
+ it_should_behave_like 'reference#create'
353
+
354
+ it "sets attributes" do
355
+ @user.name.should == 'John'
356
+ end
357
+ end
358
+
359
+ shared_examples_for 'reference#build' do
360
+ it "returns instance" do
361
+ @user.should be_instance_of(User)
362
+ end
363
+
364
+ it "builds instance" do
365
+ @user.should_not be_persisted
366
+ end
367
+
368
+ it "sets id attribute" do
369
+ @game.user_id.should == @user.id
370
+ end
371
+
372
+ it "does not save owner" do
373
+ @game.should_not_receive(:save)
374
+ @game.user.build
375
+ end
376
+ end
377
+
378
+ describe "reference#build" do
379
+ before do
380
+ @game = Game.create
381
+ @user = @game.user.build
382
+ end
383
+
384
+ it_should_behave_like 'reference#build'
385
+ end
386
+
387
+ describe "reference#build (with attributes)" do
388
+ before do
389
+ User.attribute(:name, String)
390
+ @game = Game.create
391
+ @user = @game.user.build(:name => 'John')
392
+ end
393
+
394
+ it_should_behave_like 'reference#build'
395
+
396
+ it "sets attributes" do
397
+ @user.name.should == 'John'
398
+ end
399
+ end
400
+ end