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,141 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Indices do
4
+ uses_constants('User')
5
+
6
+ it "defaults lists to empty hash" do
7
+ User.indices.should == {}
8
+ end
9
+
10
+ describe "declaring a list" do
11
+ before do
12
+ User.attribute :ssn, String
13
+ @index = User.index(:ssn)
14
+ end
15
+
16
+ it "knows about its lists" do
17
+ User.indices[:ssn].should == Toy::Index.new(User, :ssn)
18
+ end
19
+
20
+ it "returns list" do
21
+ @index.should == Toy::Index.new(User, :ssn)
22
+ end
23
+
24
+ it "adds indices instance method" do
25
+ User.new.indices.should == User.indices
26
+ end
27
+ end
28
+
29
+ describe ".index_key" do
30
+ it "returns key if index exists" do
31
+ sha = Digest::SHA1.hexdigest('taco@bell.com')
32
+ User.attribute(:email, String)
33
+ User.index(:email)
34
+ User.index_key(:email, 'taco@bell.com').should == "User:email:#{sha}"
35
+ end
36
+
37
+ it "works with string name" do
38
+ sha = Digest::SHA1.hexdigest('taco@bell.com')
39
+ User.attribute(:email, String)
40
+ User.index(:email)
41
+ User.index_key('email', 'taco@bell.com').should == "User:email:#{sha}"
42
+ end
43
+
44
+ it "raises error if index does not exist" do
45
+ lambda {
46
+ User.index_key(:email, 'taco@bell.com')
47
+ }.should raise_error(ArgumentError, 'Index for email does not exist')
48
+ end
49
+ end
50
+
51
+ describe ".get_index (existing)" do
52
+ before do
53
+ User.attribute(:email, String)
54
+ User.index(:email)
55
+ User.create_index(:email, 'taco@bell.com', 1)
56
+ User.create_index(:email, 'taco@bell.com', 2)
57
+ @index = User.get_index(:email, 'taco@bell.com')
58
+ end
59
+
60
+ it "returns decoded array" do
61
+ @index.should == [1, 2]
62
+ end
63
+ end
64
+
65
+ describe ".get_index (missing)" do
66
+ before do
67
+ User.attribute(:email, String)
68
+ User.index(:email)
69
+ @index = User.get_index(:email, 'taco@bell.com')
70
+ end
71
+
72
+ it "returns empty array" do
73
+ @index.should == []
74
+ end
75
+ end
76
+
77
+ describe ".create_index (single value)" do
78
+ before do
79
+ User.attribute(:email, String)
80
+ User.index(:email)
81
+ User.create_index(:email, 'taco@bell.com', 1)
82
+ end
83
+
84
+ it "stores id in array" do
85
+ User.get_index(:email, 'taco@bell.com').should == [1]
86
+ end
87
+ end
88
+
89
+ describe ".create_index (multiple values)" do
90
+ before do
91
+ User.attribute(:email, String)
92
+ User.index(:email)
93
+ User.create_index(:email, 'taco@bell.com', 1)
94
+ User.create_index(:email, 'taco@bell.com', 2)
95
+ User.create_index(:email, 'taco@bell.com', 3)
96
+ end
97
+
98
+ it "stores each value in array" do
99
+ User.get_index(:email, 'taco@bell.com').should == [1, 2, 3]
100
+ end
101
+ end
102
+
103
+ describe ".create_index (same value multiple times)" do
104
+ before do
105
+ User.attribute(:email, String)
106
+ User.index(:email)
107
+ User.create_index(:email, 'taco@bell.com', 1)
108
+ User.create_index(:email, 'taco@bell.com', 2)
109
+ User.create_index(:email, 'taco@bell.com', 1)
110
+ end
111
+
112
+ it "stores value only once and doesn't change order" do
113
+ User.get_index(:email, 'taco@bell.com').should == [1, 2]
114
+ end
115
+ end
116
+
117
+ describe ".destroy_index (for missing index)" do
118
+ before do
119
+ User.attribute(:email, String)
120
+ User.index(:email)
121
+ User.destroy_index(:email, 'taco@bell.com', 1)
122
+ end
123
+
124
+ it "sets index to empty array" do
125
+ User.get_index(:email, 'taco@bell.com').should == []
126
+ end
127
+ end
128
+
129
+ describe ".destroy_index (for indexed id)" do
130
+ before do
131
+ User.attribute(:email, String)
132
+ User.index(:email)
133
+ User.create_index(:email, 'taco@bell.com', 1)
134
+ User.destroy_index(:email, 'taco@bell.com', 1)
135
+ end
136
+
137
+ it "removes the value from the index" do
138
+ User.get_index(:email, 'taco@bell.com').should == []
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,15 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Attributes do
4
+ uses_constants('User')
5
+
6
+ before do
7
+ User.attribute(:name, String)
8
+ User.attribute(:age, Integer)
9
+ end
10
+
11
+ it "prints out object id and attributes sorted with values" do
12
+ user = User.new(:age => 28, :name => 'John')
13
+ user.inspect.should == %Q(#<User:#{user.object_id} age: 28, id: "#{user.id}", name: "John">)
14
+ end
15
+ end
@@ -0,0 +1,576 @@
1
+ require 'helper'
2
+
3
+ describe Toy::List do
4
+ uses_constants('User', 'Game', 'Move', 'Chat', 'Contact')
5
+
6
+ before do
7
+ @list = User.list(:games)
8
+ end
9
+
10
+ let(:list) { @list }
11
+
12
+ it "has model" do
13
+ list.model.should == User
14
+ end
15
+
16
+ it "has name" do
17
+ list.name.should == :games
18
+ end
19
+
20
+ it "has type" do
21
+ list.type.should == Game
22
+ end
23
+
24
+ it "has key" do
25
+ list.key.should == :game_ids
26
+ end
27
+
28
+ it "has instance_variable" do
29
+ list.instance_variable.should == :@_games
30
+ end
31
+
32
+ it "adds list to model" do
33
+ User.lists.keys.should include(:games)
34
+ end
35
+
36
+ it "adds attribute to model" do
37
+ User.attributes.keys.should include('game_ids')
38
+ end
39
+
40
+ it "adds reader method" do
41
+ User.new.should respond_to(:games)
42
+ end
43
+
44
+ it "adds writer method" do
45
+ User.new.should respond_to(:games=)
46
+ end
47
+
48
+ describe "#eql?" do
49
+ it "returns true if same class, model, and name" do
50
+ list.should eql(list)
51
+ end
52
+
53
+ it "returns false if not same class" do
54
+ list.should_not eql({})
55
+ end
56
+
57
+ it "returns false if not same model" do
58
+ list.should_not eql(Toy::List.new(Game, :users))
59
+ end
60
+
61
+ it "returns false if not the same name" do
62
+ list.should_not eql(Toy::List.new(User, :moves))
63
+ end
64
+ end
65
+
66
+ describe "dependent" do
67
+ before do
68
+ User.list :games, :dependent => true
69
+ @game = Game.create
70
+ @user = User.create(:game_ids => [@game.id])
71
+ end
72
+
73
+ it "should create a method to destroy games" do
74
+ User.new.should respond_to(:destroy_games)
75
+ end
76
+
77
+ it "should remove the games" do
78
+ user_id = @user.id
79
+ game_id = @game.id
80
+ @user.destroy
81
+ User.get(user_id).should be_nil
82
+ Game.get(game_id).should be_nil
83
+ end
84
+ end
85
+
86
+ describe "setting list type" do
87
+ before do
88
+ @list = User.list(:active_games, Game)
89
+ end
90
+ let(:list) { @list }
91
+
92
+ it "uses type provided instead of inferring from name" do
93
+ list.type.should be(Game)
94
+ end
95
+
96
+ it "works properly when reading and writing" do
97
+ user = User.create
98
+ game = Game.create
99
+ user.active_games = [game]
100
+ user.active_games.should == [game]
101
+ end
102
+ end
103
+
104
+ describe "list reader" do
105
+ before do
106
+ @game = Game.create
107
+ @user = User.create(:game_ids => [@game.id])
108
+ end
109
+
110
+ it "returns instances" do
111
+ @user.games.should == [@game]
112
+ end
113
+
114
+ it "memoizes result" do
115
+ @user.games.should == [@game]
116
+ Game.should_not_receive(:get_multi)
117
+ Game.should_not_receive(:get)
118
+ @user.games.should == [@game]
119
+ end
120
+
121
+ it "does not query if ids attribute is blank" do
122
+ user = User.create
123
+ Game.should_not_receive(:get_multi)
124
+ Game.should_not_receive(:get)
125
+ user.games.should == []
126
+ end
127
+ end
128
+
129
+ describe "list writer (with instances)" do
130
+ before do
131
+ @game1 = Game.create
132
+ @game2 = Game.create
133
+ @user = User.create(:game_ids => [@game1.id])
134
+ @user.games = [@game2]
135
+ end
136
+
137
+ it "set attribute" do
138
+ @user.game_ids.should == [@game2.id]
139
+ end
140
+
141
+ it "unmemoizes reader" do
142
+ @user.games.should == [@game2]
143
+ @user.games = [@game1]
144
+ @user.games.should == [@game1]
145
+ end
146
+ end
147
+
148
+ describe "list#reset" do
149
+ before do
150
+ @game = Game.create
151
+ @user = User.create(:game_ids => [@game.id])
152
+ end
153
+
154
+ it "unmemoizes the list" do
155
+ games = [@game]
156
+ @user.games.should == games
157
+ @user.games.reset
158
+ Game.should_receive(:get_multi).and_return(games)
159
+ @user.games.should == games
160
+ end
161
+
162
+ it "should be reset when owner is reloaded" do
163
+ games = [@game]
164
+ @user.games.should == games
165
+ @user.reload
166
+ Game.should_receive(:get_multi).and_return(games)
167
+ @user.games.should == games
168
+ end
169
+ end
170
+
171
+ describe "list#push" do
172
+ before do
173
+ @game = Game.create
174
+ @user = User.create
175
+ @user.games.push(@game)
176
+ end
177
+
178
+ it "adds id to attribute" do
179
+ @user.game_ids.should == [@game.id]
180
+ end
181
+
182
+ it "resets association" do
183
+ @user.games.should == [@game]
184
+ end
185
+
186
+ it "raises error if wrong type assigned" do
187
+ lambda {
188
+ @user.games.push(Move.new)
189
+ }.should raise_error(ArgumentError, "Game expected, but was Move")
190
+ end
191
+ end
192
+
193
+ describe "list#<<" do
194
+ before do
195
+ @game = Game.create
196
+ @user = User.create
197
+ @user.games << @game
198
+ end
199
+
200
+ it "adds id to attribute" do
201
+ @user.game_ids.should == [@game.id]
202
+ end
203
+
204
+ it "raises error if wrong type assigned" do
205
+ lambda {
206
+ @user.games << Move.new
207
+ }.should raise_error(ArgumentError, "Game expected, but was Move")
208
+ end
209
+ end
210
+
211
+ describe "list#concat" do
212
+ before do
213
+ @game1 = Game.create
214
+ @game2 = Game.create
215
+ @user = User.create
216
+ @user.games.concat(@game1, @game2)
217
+ end
218
+
219
+ it "adds id to attribute" do
220
+ @user.game_ids.should == [@game1.id, @game2.id]
221
+ end
222
+
223
+ it "raises error if wrong type assigned" do
224
+ lambda {
225
+ @user.games.concat(Move.new)
226
+ }.should raise_error(ArgumentError, "Game expected, but was Move")
227
+ end
228
+ end
229
+
230
+ describe "list#concat (with array)" do
231
+ before do
232
+ @game1 = Game.create
233
+ @game2 = Game.create
234
+ @user = User.create
235
+ @user.games.concat([@game1, @game2])
236
+ end
237
+
238
+ it "adds id to attribute" do
239
+ @user.game_ids.should == [@game1.id, @game2.id]
240
+ end
241
+
242
+ it "raises error if wrong type assigned" do
243
+ lambda {
244
+ @user.games.concat([Move.new])
245
+ }.should raise_error(ArgumentError, "Game expected, but was Move")
246
+ end
247
+ end
248
+
249
+ shared_examples_for("list#create") do
250
+ it "creates instance" do
251
+ @game.should be_persisted
252
+ end
253
+
254
+ it "adds id to attribute" do
255
+ @user.game_ids.should == [@game.id]
256
+ end
257
+
258
+ it "adds instance to reader" do
259
+ @user.games.should == [@game]
260
+ end
261
+ end
262
+
263
+ describe "list#create" do
264
+ before do
265
+ @user = User.create
266
+ @game = @user.games.create
267
+ end
268
+
269
+ it_should_behave_like "list#create"
270
+ end
271
+
272
+ describe "list#create (with attributes)" do
273
+ before do
274
+ Game.attribute(:move_count, Integer)
275
+ @user = User.create
276
+ @game = @user.games.create(:move_count => 10)
277
+ end
278
+
279
+ it_should_behave_like "list#create"
280
+
281
+ it "sets attributes on instance" do
282
+ @game.move_count.should == 10
283
+ end
284
+ end
285
+
286
+ describe "list#create (invalid)" do
287
+ before do
288
+ @user = User.create
289
+ @user.games.should_not_receive(:push)
290
+ @user.games.should_not_receive(:reset)
291
+ @user.should_not_receive(:reload)
292
+ @user.should_not_receive(:save)
293
+
294
+ Game.attribute(:move_count, Integer)
295
+ Game.validates_presence_of(:move_count)
296
+
297
+ @game = @user.games.create
298
+ end
299
+
300
+ it "returns instance" do
301
+ @game.should be_instance_of(Game)
302
+ end
303
+
304
+ it "is not persisted" do
305
+ @game.should_not be_persisted
306
+ end
307
+ end
308
+
309
+ describe "list#create (with :inverse_of)" do
310
+ before do
311
+ Chat.reference(:game, Game)
312
+ Game.list(:chats, Chat, :inverse_of => :game)
313
+ @game = Game.create
314
+ @chat = @game.chats.create
315
+ end
316
+
317
+ it "sets the inverse association" do
318
+ # @game.chats.should include(@chat)
319
+ @chat.game.should == @game
320
+ end
321
+ end
322
+
323
+ describe "list#create (with callbacks)" do
324
+ it "should not overwrite changes made in callbacks of list item" do
325
+ User.attribute :chat_count, Integer, :default => 0
326
+ User.list :chats, :inverse_of => :user
327
+ Chat.reference(:user)
328
+ Chat.class_eval do
329
+ after_create :increment_user_chat_count
330
+ def increment_user_chat_count
331
+ self.user.update_attributes(:chat_count => 1)
332
+ end
333
+ end
334
+
335
+ @user = User.create
336
+ @user.chat_count.should == 0
337
+
338
+ chat = @user.chats.create
339
+
340
+ chat.user.should == @user
341
+ @user.chats.count.should == 1
342
+ @user.chat_count.should == 1
343
+ end
344
+
345
+ it "should be able to create list item in a callback" do
346
+ Contact.reference(:user)
347
+ User.list(:contacts, :inverse_of => :user)
348
+ User.class_eval do
349
+ after_create :create_initial_contact
350
+ def create_initial_contact
351
+ contacts.create
352
+ end
353
+ end
354
+
355
+ user = User.create
356
+ user.contacts.count.should == 1
357
+ end
358
+ end
359
+
360
+ describe "list#destroy" do
361
+ before do
362
+ @user = User.create
363
+ @game1 = @user.games.create
364
+ @game2 = @user.games.create
365
+ User.get(@user.id).games.should == [@game1, @game2]
366
+ end
367
+
368
+ it "should take multiple ids" do
369
+ @user.games.destroy(@game1.id, @game2.id)
370
+
371
+ User.get(@user.id).games.should be_empty
372
+ Game.get(@game1.id).should be_nil
373
+ Game.get(@game2.id).should be_nil
374
+ end
375
+
376
+ it "should take an array of ids" do
377
+ @user.games.destroy([@game1.id, @game2.id])
378
+
379
+ User.get(@user.id).games.should be_empty
380
+ Game.get(@game1.id).should be_nil
381
+ Game.get(@game2.id).should be_nil
382
+ end
383
+
384
+ it "should take a block to filter on" do
385
+ Game.attribute :active, Boolean
386
+ @game1.update_attributes(:active => true)
387
+ @game2.update_attributes(:active => false)
388
+
389
+ @user.games.destroy { |g| g.active == true }
390
+
391
+ User.get(@user.id).games.should == [@game2]
392
+ Game.get(@game1.id).should be_nil
393
+ end
394
+
395
+ it "should not override changes make in callbacks" do
396
+ User.attribute :chat_count, Integer, :default => 1
397
+ User.list :chats, :inverse_of => :user
398
+
399
+ Chat.reference :user
400
+ Chat.class_eval do
401
+ after_destroy :decrement_user_chat_count
402
+ def decrement_user_chat_count
403
+ user.update_attributes(:chat_count => 0)
404
+ end
405
+ end
406
+
407
+ user = User.create
408
+ user.chat_count.should == 1
409
+ chat = user.chats.create
410
+ user.chats.destroy(chat.id)
411
+ user.chat_count.should == 0
412
+ end
413
+ end
414
+
415
+ describe "list#destroy_all" do
416
+ before do
417
+ @user = User.create
418
+ @game1 = @user.games.create
419
+ @game2 = @user.games.create
420
+ User.get(@user.id).games.should == [@game1, @game2]
421
+ end
422
+
423
+ it "should destroy all" do
424
+ @user.games.destroy_all
425
+
426
+ User.get(@user.id).games.should be_empty
427
+ Game.get(@game1.id).should be_nil
428
+ Game.get(@game2.id).should be_nil
429
+ end
430
+ end
431
+
432
+ describe "list#each" do
433
+ before do
434
+ @game1 = Game.create
435
+ @game2 = Game.create
436
+ @user = User.create(:game_ids => [@game1.id, @game2.id])
437
+ end
438
+
439
+ it "iterates through each instance" do
440
+ games = []
441
+ @user.games.each do |game|
442
+ games << game
443
+ end
444
+ games.should == [@game1, @game2]
445
+ end
446
+ end
447
+
448
+ describe "enumerating" do
449
+ before do
450
+ Game.attribute(:moves, Integer)
451
+ @game1 = Game.create(:moves => 1)
452
+ @game2 = Game.create(:moves => 2)
453
+ @user = User.create(:game_ids => [@game1.id, @game2.id])
454
+ end
455
+
456
+ it "works" do
457
+ @user.games.select { |g| g.moves > 1 }.should == [@game2]
458
+ @user.games.reject { |g| g.moves > 1 }.should == [@game1]
459
+ end
460
+ end
461
+
462
+ describe "list#include?" do
463
+ before do
464
+ @game1 = Game.create
465
+ @game2 = Game.create
466
+ @user = User.create(:game_ids => [@game1.id])
467
+ end
468
+
469
+ it "returns true if instance in association" do
470
+ @user.games.should include(@game1)
471
+ end
472
+
473
+ it "returns false if instance not in association" do
474
+ @user.games.should_not include(@game2)
475
+ end
476
+
477
+ it "returns false for nil" do
478
+ @user.games.should_not include(nil)
479
+ end
480
+ end
481
+
482
+ describe "list with block" do
483
+ before do
484
+ Move.attribute(:old, Boolean)
485
+ User.list(:moves) do
486
+ def old
487
+ target.select { |m| m.old? }
488
+ end
489
+ end
490
+
491
+ @move_new = Move.create(:old => false)
492
+ @move_old = Move.create(:old => true)
493
+ @user = User.create(:moves => [@move_new, @move_old])
494
+ end
495
+
496
+ it "extends block methods onto proxy" do
497
+ @user.moves.respond_to?(:old).should be_true
498
+ @user.moves.old.should == [@move_old]
499
+ end
500
+ end
501
+
502
+ describe "list extension with :extensions option" do
503
+ before do
504
+ old_module = Module.new do
505
+ def old
506
+ target.select { |m| m.old? }
507
+ end
508
+ end
509
+
510
+ recent_proc = Proc.new do
511
+ def recent
512
+ target.select { |m| !m.old? }
513
+ end
514
+ end
515
+
516
+ Move.attribute(:old, Boolean)
517
+ User.list(:moves, :extensions => [old_module, recent_proc])
518
+
519
+ @move_new = Move.create(:old => false)
520
+ @move_old = Move.create(:old => true)
521
+ @user = User.create(:moves => [@move_new, @move_old])
522
+ end
523
+
524
+ it "extends modules" do
525
+ @user.moves.respond_to?(:old).should be_true
526
+ @user.moves.old.should == [@move_old]
527
+ end
528
+
529
+ it "extends procs" do
530
+ @user.moves.respond_to?(:recent).should be_true
531
+ @user.moves.recent.should == [@move_new]
532
+ end
533
+ end
534
+
535
+ describe "list#get" do
536
+ before do
537
+ @user = User.create
538
+ @game = @user.games.create
539
+ end
540
+
541
+ it "should not find items that don't exist" do
542
+ @user.games.get('does-not-exist').should be_nil
543
+ end
544
+
545
+ it "should not find items that exist but are not in list" do
546
+ user = User.create
547
+ user.games.get(@game.id).should be_nil
548
+ end
549
+
550
+ it "should find items that are in list" do
551
+ @user.games.get(@game.id).should == @game
552
+ end
553
+
554
+ it "should only perform one get to find the item if present" do
555
+ Game.should_receive(:get).once
556
+ @user.games.get(@game.id)
557
+ end
558
+ end
559
+
560
+ describe "list#get!" do
561
+ before do
562
+ @user = User.create
563
+ @game = @user.games.create
564
+ end
565
+
566
+ it "returns game if found" do
567
+ lambda {
568
+ @user.games.get!('does-not-exist')
569
+ }.should raise_error(Toy::NotFound, 'Could not find document with id: "does-not-exist"')
570
+ end
571
+
572
+ it "raises exception if not found" do
573
+ @user.games.get!(@game.id).should == @game
574
+ end
575
+ end
576
+ end