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,86 @@
1
+ require 'helper'
2
+
3
+ describe Toy::References do
4
+ uses_constants('User', 'Game')
5
+
6
+ it "defaults references to empty hash" do
7
+ User.references.should == {}
8
+ end
9
+
10
+ describe ".reference?" do
11
+ before do
12
+ Game.reference(:user)
13
+ end
14
+
15
+ it "returns true if attribute (symbol)" do
16
+ Game.reference?(:user).should be_true
17
+ end
18
+
19
+ it "returns true if attribute (string)" do
20
+ Game.reference?('user').should be_true
21
+ end
22
+
23
+ it "returns false if not attribute" do
24
+ Game.reference?(:foobar).should be_false
25
+ end
26
+ end
27
+
28
+ describe "declaring a reference" do
29
+ before do
30
+ @reference = Game.reference(:user)
31
+ end
32
+
33
+ it "knows about its references" do
34
+ Game.references[:user].should == Toy::Reference.new(Game, :user)
35
+ end
36
+
37
+ it "returns reference" do
38
+ @reference.should == Toy::Reference.new(Game, :user)
39
+ end
40
+ end
41
+
42
+ describe "declaring a reference with options" do
43
+ before do
44
+ @reference = Game.reference(:user, :some_option => true)
45
+ end
46
+ let(:reference) { @reference }
47
+
48
+ it "sets type" do
49
+ reference.type.should be(User)
50
+ end
51
+
52
+ it "sets options" do
53
+ reference.options.should == {:some_option => true}
54
+ end
55
+ end
56
+
57
+ describe "declaring a reference with type" do
58
+ before do
59
+ @reference = Game.reference(:creator, User)
60
+ end
61
+ let(:reference) { @reference }
62
+
63
+ it "sets type" do
64
+ reference.type.should be(User)
65
+ end
66
+
67
+ it "sets options" do
68
+ reference.options.should == {}
69
+ end
70
+ end
71
+
72
+ describe "declaring a reference with type and options" do
73
+ before do
74
+ @reference = Game.reference(:creator, User, :some_option => true)
75
+ end
76
+ let(:reference) { @reference }
77
+
78
+ it "sets type" do
79
+ reference.type.should be(User)
80
+ end
81
+
82
+ it "sets options" do
83
+ reference.options.should == {:some_option => true}
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,354 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Serialization do
4
+ uses_constants('User', 'Game', 'Move', 'Tile')
5
+
6
+ before do
7
+ User.attribute :name, String
8
+ User.attribute :age, Integer
9
+ end
10
+
11
+ it "serializes to json" do
12
+ doc = User.new(:name => 'John', :age => 28)
13
+ ActiveSupport::JSON.decode(doc.to_json).should == {
14
+ 'user' => {
15
+ 'name' => 'John',
16
+ 'id' => doc.id,
17
+ 'age' => 28
18
+ }
19
+ }
20
+ end
21
+
22
+ it "serializes to xml" do
23
+ doc = User.new(:name => 'John', :age => 28)
24
+ Hash.from_xml(doc.to_xml).should == {
25
+ 'user' => {
26
+ 'name' => 'John',
27
+ 'id' => doc.id,
28
+ 'age' => 28
29
+ }
30
+ }
31
+
32
+ end
33
+
34
+ it "correctly serializes methods" do
35
+ User.class_eval do
36
+ def foo
37
+ {'foo' => 'bar'}
38
+ end
39
+ end
40
+ json = User.new.to_json(:methods => [:foo])
41
+ ActiveSupport::JSON.decode(json)['user']['foo'].should == {'foo' => 'bar'}
42
+ end
43
+
44
+ it "allows using :only" do
45
+ user = User.new
46
+ json = user.to_json(:only => :id)
47
+ ActiveSupport::JSON.decode(json).should == {'user' => {'id' => user.id}}
48
+ end
49
+
50
+ it "allows using :only with strings" do
51
+ user = User.new
52
+ json = user.to_json(:only => 'id')
53
+ ActiveSupport::JSON.decode(json).should == {'user' => {'id' => user.id}}
54
+ end
55
+
56
+ it "allows using :except" do
57
+ user = User.new
58
+ json = user.to_json(:except => :id)
59
+ ActiveSupport::JSON.decode(json)['user'].should_not have_key('id')
60
+ end
61
+
62
+ it "allows using :except with strings" do
63
+ user = User.new
64
+ json = user.to_json(:except => 'id')
65
+ ActiveSupport::JSON.decode(json)['user'].should_not have_key('id')
66
+ end
67
+
68
+ describe "serializing with embedded documents" do
69
+ before do
70
+ Game.reference(:creator, User)
71
+
72
+ Move.attribute(:index, Integer)
73
+ Move.attribute(:points, Integer)
74
+ Move.attribute(:words, Array)
75
+
76
+ Tile.attribute(:row, Integer)
77
+ Tile.attribute(:column, Integer)
78
+ Tile.attribute(:index, Integer)
79
+
80
+ Game.embedded_list(:moves)
81
+ Move.embedded_list(:tiles)
82
+
83
+ @user = User.create
84
+ @game = Game.create!(:creator => @user, :move_attributes => [
85
+ :index => 0,
86
+ :points => 15,
87
+ :tile_attributes => [
88
+ {:column => 7, :row => 7, :index => 23},
89
+ {:column => 8, :row => 7, :index => 24},
90
+ ],
91
+ ])
92
+ end
93
+
94
+ it "includes all embedded attributes by default" do
95
+ move = @game.moves.first
96
+ tile1 = move.tiles[0]
97
+ tile2 = move.tiles[1]
98
+ ActiveSupport::JSON.decode(@game.to_json).should == {
99
+ 'game' => {
100
+ 'id' => @game.id,
101
+ 'creator_id' => @user.id,
102
+ 'moves' => [
103
+ {
104
+ 'id' => move.id,
105
+ 'index' => 0,
106
+ 'points' => 15,
107
+ 'words' => [],
108
+ 'tiles' => [
109
+ {'id' => tile1.id, 'column' => 7, 'row' => 7, 'index' => 23},
110
+ {'id' => tile2.id, 'column' => 8, 'row' => 7, 'index' => 24},
111
+ ]
112
+ },
113
+ ],
114
+ }
115
+ }
116
+ end
117
+ end
118
+
119
+ describe "serializing relationships" do
120
+ before do
121
+ User.list :games, :inverse_of => :user
122
+ Game.reference :user
123
+ end
124
+
125
+ it "should include references" do
126
+ user = User.create(:name => 'John', :age => 28)
127
+ game = user.games.create
128
+
129
+ ActiveSupport::JSON.decode(game.to_json(:include => [:user])).should == {
130
+ 'game' => {
131
+ 'id' => game.id,
132
+ 'user_id' => user.id,
133
+ 'user' => {
134
+ 'name' => 'John',
135
+ 'game_ids' => [game.id],
136
+ 'id' => user.id,
137
+ 'age' => 28,
138
+ }
139
+ }
140
+ }
141
+ end
142
+
143
+ it "should include lists" do
144
+ user = User.create(:name => 'John', :age => 28)
145
+ game = user.games.create
146
+ ActiveSupport::JSON.decode(user.to_json(:include => [:games])).should == {
147
+ 'user' => {
148
+ 'name' => 'John',
149
+ 'game_ids' => [game.id],
150
+ 'id' => user.id,
151
+ 'age' => 28,
152
+ 'games' => [{'id' => game.id, 'user_id' => user.id}],
153
+ }
154
+ }
155
+ end
156
+
157
+ it "should not cause circular reference JSON errors for references" do
158
+ user = User.create(:name => 'John', :age => 28)
159
+ game = user.games.create
160
+
161
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(game.user)).should == {
162
+ 'user' => {
163
+ 'name' => 'John',
164
+ 'game_ids' => [game.id],
165
+ 'id' => user.id,
166
+ 'age' => 28
167
+ }
168
+ }
169
+ end
170
+
171
+ it "should not cause circular reference JSON errors for references when called indirectly" do
172
+ user = User.create(:name => 'John', :age => 28)
173
+ game = user.games.create
174
+
175
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode([game.user])).should == [
176
+ 'user' => {
177
+ 'name' => 'John',
178
+ 'game_ids' => [game.id],
179
+ 'id' => user.id,
180
+ 'age' => 28
181
+ }
182
+ ]
183
+ end
184
+
185
+ it "should not cause circular reference JSON errors for lists" do
186
+ user = User.create(:name => 'John', :age => 28)
187
+ game = user.games.create
188
+
189
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(user.games)).should == [{
190
+ 'game' => {
191
+ 'id' => game.id,
192
+ 'user_id' => user.id
193
+ }
194
+ }]
195
+ end
196
+
197
+ it "should not cause circular reference JSON errors for lists when called indirectly" do
198
+ user = User.create(:name => 'John', :age => 28)
199
+ game = user.games.create
200
+
201
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode({:games => user.games})).should == {
202
+ 'games' => [{
203
+ 'game' => {
204
+ 'id' => game.id,
205
+ 'user_id' => user.id
206
+ }
207
+ }]
208
+ }
209
+ end
210
+ end
211
+
212
+ describe "serializing parent relationships" do
213
+ before do
214
+ Game.embedded_list :moves
215
+ Move.parent_reference :game
216
+ end
217
+
218
+ it "should include references" do
219
+ game = Game.create
220
+ move = game.moves.create
221
+
222
+ ActiveSupport::JSON.decode(move.to_json(:include => [:game])).should == {
223
+ 'move' => {
224
+ 'id' => move.id,
225
+ 'game' => {
226
+ 'id' => game.id,
227
+ 'moves' => [{
228
+ 'id' => move.id
229
+ }]
230
+ }
231
+ }
232
+ }
233
+ end
234
+ end
235
+
236
+ describe "serializing specific attributes" do
237
+ before do
238
+ Move.attribute(:index, Integer)
239
+ Move.attribute(:points, Integer)
240
+ Move.attribute(:words, Array)
241
+ end
242
+
243
+ it "should default to all attributes" do
244
+ move = Move.new(:index => 0, :points => 15, :words => ['QI', 'XI'])
245
+ move.serializable_attributes.should == [:id, :index, :points, :words]
246
+ end
247
+
248
+ it "should be set per model" do
249
+ Move.class_eval do
250
+ def serializable_attributes
251
+ attribute_names = super - [:index]
252
+ attribute_names
253
+ end
254
+ end
255
+
256
+ move = Move.new(:index => 0, :points => 15, :words => ['QI', 'XI'])
257
+ move.serializable_attributes.should == [:id, :points, :words]
258
+ end
259
+
260
+ it "should only serialize specified attributes" do
261
+ Move.class_eval do
262
+ def serializable_attributes
263
+ attribute_names = super - [:index]
264
+ attribute_names
265
+ end
266
+ end
267
+
268
+ move = Move.new(:index => 0, :points => 15, :words => ['QI', 'XI'])
269
+ ActiveSupport::JSON.decode(move.to_json).should == {
270
+ 'move' => {
271
+ 'id' => move.id,
272
+ 'points' => 15,
273
+ 'words' => ["QI", "XI"]
274
+ }
275
+ }
276
+ end
277
+
278
+ it "should serialize additional methods along with attributes" do
279
+ Move.class_eval do
280
+ def serializable_attributes
281
+ attribute_names = super + [:calculated_attribute]
282
+ attribute_names
283
+ end
284
+
285
+ def calculated_attribute
286
+ 'some value'
287
+ end
288
+ end
289
+
290
+ move = Move.new(:index => 0, :points => 15, :words => ['QI', 'XI'])
291
+ ActiveSupport::JSON.decode(move.to_json).should == {
292
+ 'move' => {
293
+ 'id' => move.id,
294
+ 'index' => 0,
295
+ 'points' => 15,
296
+ 'words' => ["QI", "XI"],
297
+ 'calculated_attribute' => 'some value'
298
+ }
299
+ }
300
+ end
301
+ end
302
+
303
+ describe "#serializable_hash" do
304
+ context "with embedded list" do
305
+ before do
306
+ Game.embedded_list :moves
307
+ Move.parent_reference :game
308
+
309
+ @game = Game.create
310
+ @move = game.moves.create
311
+ end
312
+ let(:game) { @game }
313
+
314
+ it "returns a hash the whole way through" do
315
+ game.serializable_hash.should == {
316
+ 'id' => game.id,
317
+ 'moves' => [
318
+ {'id' => game.moves.first.id}
319
+ ]
320
+ }
321
+ end
322
+
323
+ it "allows using only with embedded" do
324
+ game.serializable_hash(:only => :moves).should == {
325
+ 'moves' => [
326
+ {'id' => game.moves.first.id}
327
+ ]
328
+ }
329
+ end
330
+
331
+ it "allows using except to not include embedded" do
332
+ game.serializable_hash(:except => :moves).should == {
333
+ 'id' => game.id,
334
+ }
335
+ end
336
+ end
337
+
338
+ context "with method that is another toystore object" do
339
+ before do
340
+ Game.reference(:creator, User)
341
+ @game = Game.create(:creator => User.create)
342
+ end
343
+ let(:game) { @game }
344
+
345
+ it "returns serializable hash of object" do
346
+ game.serializable_hash(:methods => [:creator]).should == {
347
+ 'id' => game.id,
348
+ 'creator_id' => game.creator_id,
349
+ 'creator' => {'id' => game.creator.id}
350
+ }
351
+ end
352
+ end
353
+ end
354
+ end
@@ -0,0 +1,41 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Store do
4
+ uses_constants('User')
5
+
6
+ describe "including" do
7
+ it "adds model naming" do
8
+ model_name = User.model_name
9
+ model_name.should == 'User'
10
+ model_name.singular.should == 'user'
11
+ model_name.plural.should == 'users'
12
+ end
13
+
14
+ it "adds to_model" do
15
+ user = User.new
16
+ user.to_model.should == user
17
+ end
18
+
19
+ describe "#to_key" do
20
+ it "returns [id] if persisted" do
21
+ user = User.create
22
+ user.to_key.should == [user.id]
23
+ end
24
+
25
+ it "returns nil if not persisted" do
26
+ User.new.to_key.should be_nil
27
+ end
28
+ end
29
+
30
+ describe "#to_param" do
31
+ it "returns key joined by - if to_key present" do
32
+ user = User.create
33
+ user.to_param.should == user.to_key.join('-')
34
+ end
35
+
36
+ it "returns nil if to_key nil" do
37
+ User.new.to_param.should be_nil
38
+ end
39
+ end
40
+ end
41
+ end