ohm 0.1.0.rc5 → 0.1.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
5
+ require "json"
6
+
7
+ class Venue < Ohm::Model
8
+ attribute :name
9
+
10
+ def validate
11
+ assert_present :name
12
+ end
13
+ end
14
+
15
+ class Programmer < Ohm::Model
16
+ attribute :language
17
+
18
+ def validate
19
+ assert_present :language
20
+ end
21
+
22
+ def to_hash
23
+ super.merge(:language => language)
24
+ end
25
+ end
26
+
27
+ test "export an empty hash via to_hash" do
28
+ person = Venue.new
29
+ assert Hash.new == person.to_hash
30
+ end
31
+
32
+ test "export a hash with the errors" do
33
+ person = Venue.new
34
+ person.valid?
35
+
36
+ assert Hash[:errors => [[:name, :not_present]]] == person.to_hash
37
+ end
38
+
39
+ test "export a hash with the its id" do
40
+ person = Venue.create(:name => "John Doe")
41
+ assert Hash[:id => '1'] == person.to_hash
42
+ end
43
+
44
+ test "export a hash with its id and the errors" do
45
+ person = Venue.create(:name => "John Doe")
46
+ person.name = nil
47
+ person.valid?
48
+
49
+ expected_hash = { :id => '1', :errors => [[:name, :not_present]] }
50
+
51
+ assert expected_hash == person.to_hash
52
+ end
53
+
54
+ test "return the merged attributes" do
55
+ programmer = Programmer.create(:language => "Ruby")
56
+ expected_hash = { :id => '1', :language => 'Ruby' }
57
+
58
+ assert expected_hash == programmer.to_hash
59
+ end
60
+
61
+ test "just be the to_hash of a model" do
62
+ json = JSON.parse(Programmer.create(:language => "Ruby").to_json)
63
+
64
+ assert ["id", "language"] == json.keys.sort
65
+ assert "1" == json["id"]
66
+ assert "Ruby" == json["language"]
67
+ end
@@ -1,8 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
4
5
  require "ostruct"
5
- require "json"
6
6
 
7
7
  class Post < Ohm::Model
8
8
  attribute :body
@@ -46,1099 +46,906 @@ module SomeNamespace
46
46
  end
47
47
  end
48
48
 
49
- class ModelTest < Test::Unit::TestCase
50
- setup do
51
- Ohm.flush
52
- Logger.current.clear
53
- end
54
-
55
- context "An event initialized with a hash of attributes" do
56
- should "assign the passed attributes" do
57
- event = Event.new(:name => "Ruby Tuesday")
58
- assert_equal event.name, "Ruby Tuesday"
59
- end
60
- end
61
-
62
- context "An event created from a hash of attributes" do
63
- should "assign an id and save the object" do
64
- event1 = Event.create(:name => "Ruby Tuesday")
65
- event2 = Event.create(:name => "Ruby Meetup")
66
-
67
- assert_equal "1", event1.id
68
- assert_equal "2", event2.id
69
- end
49
+ class Meetup < Ohm::Model
50
+ attribute :name
51
+ attribute :location
70
52
 
71
- should "return the unsaved object if validation fails" do
72
- assert Person.create(:name => nil).kind_of?(Person)
73
- end
53
+ def validate
54
+ assert_present :name
74
55
  end
56
+ end
75
57
 
76
- context "An event updated from a hash of attributes" do
77
- class Meetup < Ohm::Model
78
- attribute :name
79
- attribute :location
80
-
81
- def validate
82
- assert_present :name
83
- end
84
- end
85
-
86
- should "assign an id and save the object" do
87
- event = Meetup.create(:name => "Ruby Tuesday")
88
- event.update(:name => "Ruby Meetup")
89
- assert_equal "Ruby Meetup", event.name
90
- end
91
-
92
- should "return false if the validation fails" do
93
- event = Meetup.create(:name => "Ruby Tuesday")
94
- assert !event.update(:name => nil)
95
- end
96
-
97
- should "save the attributes in UTF8" do
98
- event = Meetup.create(:name => "32° Kisei-sen")
99
- assert_equal "32° Kisei-sen", Meetup[event.id].name
100
- end
101
-
102
- should "delete the attribute if set to nil" do
103
- event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
104
- assert_equal "Los Angeles", Meetup[event.id].location
105
- assert event.update(:location => nil)
106
- assert_equal nil, Meetup[event.id].location
107
- end
108
-
109
- should "delete the attribute if set to an empty string" do
110
- event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
111
- assert_equal "Los Angeles", Meetup[event.id].location
112
- assert event.update(:location => "")
113
- assert_equal nil, Meetup[event.id].location
114
- end
115
- end
58
+ test "assign attributes from the hash" do
59
+ event = Event.new(:name => "Ruby Tuesday")
60
+ assert event.name == "Ruby Tuesday"
61
+ end
116
62
 
117
- context "Model definition" do
118
- should "not raise if an attribute is redefined" do
119
- assert_nothing_raised do
120
- class RedefinedModel < Ohm::Model
121
- attribute :name
122
-
123
- silence_warnings do
124
- attribute :name
125
- end
126
- end
127
- end
128
- end
63
+ test "assign an ID and save the object" do
64
+ event1 = Event.create(:name => "Ruby Tuesday")
65
+ event2 = Event.create(:name => "Ruby Meetup")
129
66
 
130
- should "not raise if a counter is redefined" do
131
- assert_nothing_raised do
132
- class RedefinedModel < Ohm::Model
133
- counter :age
67
+ assert "1" == event1.id
68
+ assert "2" == event2.id
69
+ end
134
70
 
135
- silence_warnings do
136
- counter :age
137
- end
138
- end
139
- end
140
- end
71
+ test "return the unsaved object if validation fails" do
72
+ assert Person.create(:name => nil).kind_of?(Person)
73
+ end
141
74
 
142
- should "not raise if a list is redefined" do
143
- assert_nothing_raised do
144
- class RedefinedModel < Ohm::Model
145
- list :todo, lambda { }
75
+ test "updates attributes" do
76
+ event = Meetup.create(:name => "Ruby Tuesday")
77
+ event.update(:name => "Ruby Meetup")
78
+ assert "Ruby Meetup" == event.name
79
+ end
146
80
 
147
- silence_warnings do
148
- list :todo, lambda { }
149
- end
150
- end
151
- end
152
- end
81
+ test "return false if the validation fails" do
82
+ event = Meetup.create(:name => "Ruby Tuesday")
83
+ assert !event.update(:name => nil)
84
+ end
153
85
 
154
- should "not raise if a set is redefined" do
155
- assert_nothing_raised do
156
- class RedefinedModel < Ohm::Model
157
- set :friends, lambda { }
86
+ test "save the attributes in UTF8" do
87
+ event = Meetup.create(:name => "32° Kisei-sen")
88
+ assert "32° Kisei-sen" == Meetup[event.id].name
89
+ end
158
90
 
159
- silence_warnings do
160
- set :friends, lambda { }
161
- end
162
- end
163
- end
164
- end
91
+ test "delete the attribute if set to nil" do
92
+ event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
93
+ assert "Los Angeles" == Meetup[event.id].location
94
+ assert event.update(:location => nil)
95
+ assert nil == Meetup[event.id].location
96
+ end
165
97
 
166
- should "not raise if a collection is redefined" do
167
- assert_nothing_raised do
168
- class RedefinedModel < Ohm::Model
169
- list :toys, lambda { }
98
+ test "delete the attribute if set to an empty string" do
99
+ event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
100
+ assert "Los Angeles" == Meetup[event.id].location
101
+ assert event.update(:location => "")
102
+ assert nil == Meetup[event.id].location
103
+ end
170
104
 
171
- silence_warnings do
172
- set :toys, lambda { }
173
- end
174
- end
175
- end
176
- end
105
+ test "not raise if an attribute is redefined" do
106
+ class RedefinedModel < Ohm::Model
107
+ attribute :name
177
108
 
178
- should "not raise if a index is redefined" do
179
- assert_nothing_raised do
180
- class RedefinedModel < Ohm::Model
181
- attribute :color
182
- index :color
183
- index :color
184
- end
185
- end
109
+ silence_warnings do
110
+ attribute :name
186
111
  end
187
112
  end
113
+ end
188
114
 
189
- context "Finding an event" do
190
- setup do
191
- Ohm.redis.sadd("Event:all", 1)
192
- Ohm.redis.hset("Event:1", "name", "Concert")
193
- end
115
+ test "not raise if a counter is redefined" do
116
+ class RedefinedModel < Ohm::Model
117
+ counter :age
194
118
 
195
- should "return an instance of Event" do
196
- assert Event[1].kind_of?(Event)
197
- assert_equal 1, Event[1].id
198
- assert_equal "Concert", Event[1].name
119
+ silence_warnings do
120
+ counter :age
199
121
  end
200
122
  end
123
+ end
201
124
 
202
- context "Finding a user" do
203
- setup do
204
- Ohm.redis.sadd("User:all", 1)
205
- Ohm.redis.hset("User:1", "email", "albert@example.com")
206
- end
207
-
208
- should "return an instance of User" do
209
- assert User[1].kind_of?(User)
210
- assert_equal 1, User[1].id
211
- assert_equal "albert@example.com", User[1].email
212
- end
125
+ test "not raise if a list is redefined" do
126
+ class RedefinedModel < Ohm::Model
127
+ list :todo, lambda { }
213
128
 
214
- should "allow to map key to models" do
215
- assert_equal [User[1]], [1].map(&User)
129
+ silence_warnings do
130
+ list :todo, lambda { }
216
131
  end
217
132
  end
133
+ end
218
134
 
219
- context "Updating a user" do
220
- setup do
221
- Ohm.redis.sadd("User:all", 1)
222
- Ohm.redis.set("User:1:email", "albert@example.com")
223
-
224
- @user = User[1]
225
- end
135
+ test "not raise if a set is redefined" do
136
+ class RedefinedModel < Ohm::Model
137
+ set :friends, lambda { }
226
138
 
227
- should "change its attributes" do
228
- @user.email = "maria@example.com"
229
- assert_equal "maria@example.com", @user.email
139
+ silence_warnings do
140
+ set :friends, lambda { }
230
141
  end
142
+ end
143
+ end
231
144
 
232
- should "save the new values" do
233
- @user.email = "maria@example.com"
234
- @user.save
235
-
236
- @user.email = "maria@example.com"
237
- @user.save
145
+ test "not raise if a collection is redefined" do
146
+ class RedefinedModel < Ohm::Model
147
+ list :toys, lambda { }
238
148
 
239
- assert_equal "maria@example.com", User[1].email
149
+ silence_warnings do
150
+ set :toys, lambda { }
240
151
  end
241
152
  end
153
+ end
242
154
 
243
- context "Creating a new model" do
244
- should "assign a new id to the event" do
245
- event1 = Event.new
246
- event1.create
247
-
248
- event2 = Event.new
249
- event2.create
250
-
251
- assert !event1.new?
252
- assert !event2.new?
253
-
254
- assert_equal "1", event1.id
255
- assert_equal "2", event2.id
256
- end
155
+ test "not raise if a index is redefined" do
156
+ class RedefinedModel < Ohm::Model
157
+ attribute :color
158
+ index :color
159
+ index :color
257
160
  end
161
+ end
258
162
 
259
- context "Saving a model" do
260
- should "create the model if it is new" do
261
- event = Event.new(:name => "Foo").save
262
- assert_equal "Foo", Event[event.id].name
263
- end
163
+ test "allow arbitrary IDs" do
164
+ Event.create(:id => "abc123", :name => "Concert")
264
165
 
265
- should "save it only if it was previously created" do
266
- event = Event.new
267
- event.name = "Lorem ipsum"
268
- event.create
166
+ assert Event.all.size == 1
167
+ assert Event["abc123"].name == "Concert"
168
+ end
269
169
 
270
- event.name = "Lorem"
271
- event.save
170
+ setup do
171
+ Ohm.redis.sadd("Event:all", 1)
172
+ Ohm.redis.hset("Event:1", "name", "Concert")
173
+ end
272
174
 
273
- assert_equal "Lorem", Event[event.id].name
274
- end
175
+ test "return an instance of Event" do
176
+ assert Event[1].kind_of?(Event)
177
+ assert 1 == Event[1].id
178
+ assert "Concert" == Event[1].name
179
+ end
275
180
 
276
- should "allow to hook into write" do
277
- event = Event.create(:name => "Foo")
181
+ setup do
182
+ Ohm.redis.sadd("User:all", 1)
183
+ Ohm.redis.hset("User:1", "email", "albert@example.com")
184
+ end
278
185
 
279
- assert_equal "foo", event.slug
280
- end
186
+ test "return an instance of User" do
187
+ assert User[1].kind_of?(User)
188
+ assert 1 == User[1].id
189
+ assert "albert@example.com" == User[1].email
190
+ end
281
191
 
282
- should "save counters" do
283
- event = Event.create(:name => "Foo")
192
+ test "allow to map key to models" do
193
+ assert [User[1]] == [1].map(&User)
194
+ end
284
195
 
285
- event.incr(:votes)
286
- event.save
196
+ setup do
197
+ Ohm.redis.sadd("User:all", 1)
198
+ Ohm.redis.set("User:1:email", "albert@example.com")
287
199
 
288
- assert_equal 1, Event[event.id].votes
289
- end
200
+ @user = User[1]
201
+ end
290
202
 
291
- end
203
+ test "change its attributes" do
204
+ @user.email = "maria@example.com"
205
+ assert "maria@example.com" == @user.email
206
+ end
292
207
 
293
- context "Delete" do
294
- should "delete an existing model" do
295
- class ModelToBeDeleted < Ohm::Model
296
- attribute :name
297
- set :foos, Post
298
- list :bars, Post
299
- end
208
+ test "save the new values" do
209
+ @user.email = "maria@example.com"
210
+ @user.save
300
211
 
301
- @model = ModelToBeDeleted.create(:name => "Lorem")
212
+ @user.email = "maria@example.com"
213
+ @user.save
302
214
 
303
- @model.foos << Post.create
304
- @model.bars << Post.create
215
+ assert "maria@example.com" == User[1].email
216
+ end
305
217
 
306
- id = @model.id
218
+ test "assign a new id to the event" do
219
+ event1 = Event.new
220
+ event1.create
307
221
 
308
- @model.delete
222
+ event2 = Event.new
223
+ event2.create
309
224
 
310
- assert_nil Ohm.redis.get(ModelToBeDeleted.key[id])
311
- assert_nil Ohm.redis.get(ModelToBeDeleted.key[id][:name])
312
- assert_equal Array.new, Ohm.redis.smembers(ModelToBeDeleted.key[id][:foos])
313
- assert_equal Array.new, Ohm.redis.lrange(ModelToBeDeleted.key[id][:bars], 0, -1)
225
+ assert !event1.new?
226
+ assert !event2.new?
314
227
 
315
- assert ModelToBeDeleted.all.empty?
316
- end
228
+ assert "1" == event1.id
229
+ assert "2" == event2.id
230
+ end
317
231
 
318
- should "be no leftover keys" do
319
- class ::Foo < Ohm::Model
320
- attribute :name
321
- index :name
322
- end
232
+ # Saving a model
233
+ test "create the model if it is new" do
234
+ event = Event.new(:name => "Foo").save
235
+ assert "Foo" == Event[event.id].name
236
+ end
323
237
 
324
- assert_equal [], Ohm.redis.keys("*")
238
+ test "save it only if it was previously created" do
239
+ event = Event.new
240
+ event.name = "Lorem ipsum"
241
+ event.create
325
242
 
326
- Foo.create(:name => "Bar")
243
+ event.name = "Lorem"
244
+ event.save
327
245
 
328
- assert_equal ["Foo:1:_indices", "Foo:1", "Foo:all", "Foo:id", "Foo:name:QmFy"].sort, Ohm.redis.keys("*").sort
246
+ assert "Lorem" == Event[event.id].name
247
+ end
329
248
 
330
- Foo[1].delete
249
+ test "allow to hook into write" do
250
+ event = Event.create(:name => "Foo")
331
251
 
332
- assert_equal ["Foo:id"], Ohm.redis.keys("*")
333
- end
334
- end
252
+ assert "foo" == event.slug
253
+ end
335
254
 
336
- context "Listing" do
337
- should "find all" do
338
- event1 = Event.new
339
- event1.name = "Ruby Meetup"
340
- event1.create
255
+ test "save counters" do
256
+ event = Event.create(:name => "Foo")
341
257
 
342
- event2 = Event.new
343
- event2.name = "Ruby Tuesday"
344
- event2.create
258
+ event.incr(:votes)
259
+ event.save
345
260
 
346
- all = Event.all
261
+ assert 1 == Event[event.id].votes
262
+ end
347
263
 
348
- assert all.detect {|e| e.name == "Ruby Meetup" }
349
- assert all.detect {|e| e.name == "Ruby Tuesday" }
350
- end
264
+ # Delete
265
+ test "delete an existing model" do
266
+ class ModelToBeDeleted < Ohm::Model
267
+ attribute :name
268
+ set :foos, Post
269
+ list :bars, Post
351
270
  end
352
271
 
353
- context "Sorting" do
354
- should "sort all" do
355
- Person.create :name => "D"
356
- Person.create :name => "C"
357
- Person.create :name => "B"
358
- Person.create :name => "A"
359
-
360
- assert_equal %w[A B C D], Person.all.sort_by(:name, :order => "ALPHA").map { |person| person.name }
361
- end
362
-
363
- should "return an empty array if there are no elements to sort" do
364
- assert_equal [], Person.all.sort_by(:name)
365
- end
366
-
367
- should "return the first element sorted by id when using first" do
368
- Person.create :name => "A"
369
- Person.create :name => "B"
370
- assert_equal "A", Person.all.first.name
371
- end
372
-
373
- should "return the first element sorted by name if first receives a sorting option" do
374
- Person.create :name => "B"
375
- Person.create :name => "A"
376
- assert_equal "A", Person.all.first(:by => :name, :order => "ALPHA").name
377
- end
378
-
379
- should "return attribute values when the get parameter is specified" do
380
- Person.create :name => "B"
381
- Person.create :name => "A"
382
-
383
- assert_equal "A", Person.all.sort_by(:name, :get => :name, :order => "ALPHA").first
384
- end
385
- end
272
+ @model = ModelToBeDeleted.create(:name => "Lorem")
386
273
 
387
- context "Loading attributes" do
388
- setup do
389
- event = Event.new
390
- event.name = "Ruby Tuesday"
391
- @id = event.create.id
392
- end
274
+ @model.foos << Post.create
275
+ @model.bars << Post.create
393
276
 
394
- should "load attributes lazily" do
395
- event = Event[@id]
277
+ id = @model.id
396
278
 
397
- Logger.current.clear
279
+ @model.delete
398
280
 
399
- assert Logger.current.commands.empty?
400
- assert_equal "Ruby Tuesday", event.name
401
- assert !Logger.current.commands.empty?
281
+ assert Ohm.redis.get(ModelToBeDeleted.key[id]).nil?
282
+ assert Ohm.redis.get(ModelToBeDeleted.key[id][:name]).nil?
283
+ assert Array.new == Ohm.redis.smembers(ModelToBeDeleted.key[id][:foos])
284
+ assert Array.new == Ohm.redis.lrange(ModelToBeDeleted.key[id][:bars], 0, -1)
402
285
 
403
- Logger.current.clear
404
- assert_equal "Ruby Tuesday", event.name
405
- assert Logger.current.commands.empty?
406
- end
286
+ assert ModelToBeDeleted.all.empty?
287
+ end
407
288
 
408
- should "load attributes as a strings" do
409
- event = Event.create(:name => 1)
289
+ setup do
290
+ end
410
291
 
411
- assert_equal "1", Event[event.id].name
412
- end
292
+ test "be no leftover keys" do
293
+ class ::Foo < Ohm::Model
294
+ attribute :name
295
+ index :name
413
296
  end
414
297
 
415
- context "Attributes of type Set" do
416
- setup do
417
- @person1 = Person.create(:name => "Albert")
418
- @person2 = Person.create(:name => "Bertrand")
419
- @person3 = Person.create(:name => "Charles")
298
+ assert [] == Ohm.redis.keys("*")
420
299
 
421
- @event = Event.new
422
- @event.name = "Ruby Tuesday"
423
- end
300
+ Foo.create(:name => "Bar")
424
301
 
425
- should "not be available if the model is new" do
426
- assert_raise Ohm::Model::MissingID do
427
- @event.attendees << Person.new
428
- end
429
- end
302
+ assert ["Foo:1:_indices", "Foo:1", "Foo:all", "Foo:id", "Foo:name:QmFy"].sort == Ohm.redis.keys("*").sort
430
303
 
431
- should "remove an element if sent delete" do
432
- @event.create
433
- @event.attendees << @person1
434
- @event.attendees << @person2
435
- @event.attendees << @person3
436
- assert_equal ["1", "2", "3"], @event.attendees.key.sort
437
- @event.attendees.delete(@person2)
438
- assert_equal ["1", "3"], Event[@event.id].attendees.key.sort
439
- end
440
-
441
- should "return true if the set includes some member" do
442
- @event.create
443
- @event.attendees << @person1
444
- @event.attendees << @person2
445
- assert @event.attendees.include?(@person2)
446
- assert !@event.attendees.include?(@person3)
447
- end
304
+ Foo[1].delete
448
305
 
449
- should "return instances of the passed model" do
450
- @event.create
451
- @event.attendees << @person1
452
-
453
- assert_equal [@person1], @event.attendees.all
454
- assert_equal @person1, @event.attendees[@person1.id]
455
- end
306
+ assert ["Foo:id"] == Ohm.redis.keys("*")
307
+ end
456
308
 
457
- should "return the size of the set" do
458
- @event.create
459
- @event.attendees << @person1
460
- @event.attendees << @person2
461
- @event.attendees << @person3
462
- assert_equal 3, @event.attendees.size
463
- end
309
+ # Listing
310
+ test "find all" do
311
+ event1 = Event.new
312
+ event1.name = "Ruby Meetup"
313
+ event1.create
464
314
 
465
- should "empty the set" do
466
- @event.create
467
- @event.attendees << @person1
315
+ event2 = Event.new
316
+ event2.name = "Ruby Tuesday"
317
+ event2.create
468
318
 
469
- @event.attendees.clear
319
+ all = Event.all
470
320
 
471
- assert @event.attendees.empty?
472
- end
321
+ assert all.detect {|e| e.name == "Ruby Meetup" }
322
+ assert all.detect {|e| e.name == "Ruby Tuesday" }
323
+ end
473
324
 
474
- should "replace the values in the set" do
475
- @event.create
476
- @event.attendees << @person1
325
+ # Sorting
326
+ test "sort all" do
327
+ Person.create :name => "D"
328
+ Person.create :name => "C"
329
+ Person.create :name => "B"
330
+ Person.create :name => "A"
477
331
 
478
- assert_equal [@person1], @event.attendees.all
332
+ assert %w[A B C D] == Person.all.sort_by(:name, :order => "ALPHA").map { |person| person.name }
333
+ end
479
334
 
480
- @event.attendees.replace([@person2, @person3])
335
+ test "return an empty array if there are no elements to sort" do
336
+ assert [] == Person.all.sort_by(:name)
337
+ end
481
338
 
482
- assert_equal [@person2, @person3], @event.attendees.all.sort_by(&:id)
483
- end
339
+ test "return the first element sorted by id when using first" do
340
+ Person.create :name => "A"
341
+ Person.create :name => "B"
342
+ assert "A" == Person.all.first.name
343
+ end
484
344
 
485
- should "filter elements" do
486
- @event.create
487
- @event.attendees.add(@person1)
488
- @event.attendees.add(@person2)
345
+ test "return the first element sorted by name if first receives a sorting option" do
346
+ Person.create :name => "B"
347
+ Person.create :name => "A"
348
+ assert "A" == Person.all.first(:by => :name, :order => "ALPHA").name
349
+ end
489
350
 
490
- assert_equal [@person1], @event.attendees.find(:initial => "A").all
491
- assert_equal [@person2], @event.attendees.find(:initial => "B").all
492
- assert_equal [], @event.attendees.find(:initial => "Z").all
493
- end
494
- end
351
+ test "return attribute values when the get parameter is specified" do
352
+ Person.create :name => "B"
353
+ Person.create :name => "A"
495
354
 
496
- context "Attributes of type List" do
497
- setup do
498
- @post = Post.new
499
- @post.body = "Hello world!"
500
- @post.create
501
- end
355
+ assert "A" == Person.all.sort_by(:name, :get => :name, :order => "ALPHA").first
356
+ end
502
357
 
503
- should "return an array" do
504
- assert @post.related.all.kind_of?(Array)
505
- end
358
+ test "work on lists" do
359
+ @post = Post.create :body => "Hello world!"
360
+ @post.related << Post.create(:body => "C")
361
+ @post.related << Post.create(:body => "B")
362
+ @post.related << Post.create(:body => "A")
506
363
 
507
- should "append elements with push" do
508
- @post.related.push Post.create
509
- @post.related << Post.create
364
+ assert ["A", "B", "C"] == @post.related.sort_by(:body, :order => "ALPHA ASC").map { |model| model.body }
365
+ end
510
366
 
511
- assert_equal ["2", "3"], @post.related.all.map { |model| model.id }
512
- end
367
+ # Loading attributes
368
+ setup do
369
+ event = Event.new
370
+ event.name = "Ruby Tuesday"
371
+ @id = event.create.id
372
+ end
513
373
 
514
- should "keep the inserting order" do
515
- @post.related << Post.create
516
- @post.related << Post.create
517
- @post.related << Post.create
518
- assert_equal ["2", "3", "4"], @post.related.all.map { |model| model.id }
519
- end
374
+ def monitor
375
+ log = []
520
376
 
521
- should "keep the inserting order after saving" do
522
- @post.related << Post.create
523
- @post.related << Post.create
524
- @post.related << Post.create
525
- @post.save
526
- assert_equal ["2", "3", "4"], Post[@post.id].related.map { |model| model.id }
377
+ monitor = Thread.new do
378
+ Redis.connect.monitor do |line|
379
+ break if line =~ /ping/
380
+ log << line
527
381
  end
382
+ end
528
383
 
529
- should "allow slicing the list" do
530
- post1 = Post.create
531
- post2 = Post.create
532
- post3 = Post.create
533
-
534
- @post.related << post1
535
- @post.related << post2
536
- @post.related << post3
384
+ sleep 0.01
537
385
 
538
- assert_equal post1, @post.related[0]
539
- assert_equal post2, @post.related[1]
540
- assert_equal post3, @post.related[-1]
386
+ log.clear.tap do
387
+ yield
388
+ Ohm.redis.ping
389
+ monitor.join
390
+ end
391
+ end
541
392
 
542
- assert_equal nil, @post.related[3]
393
+ test "load attributes lazily" do
394
+ event = Event[@id]
543
395
 
544
- assert_equal [post2, post3], @post.related[1, 2]
545
- assert_equal [post2, post3], @post.related[1, -1]
396
+ log = monitor { event.name }
546
397
 
547
- assert_equal [], @post.related[4, 5]
398
+ assert !log.empty?
548
399
 
549
- assert_equal [post2, post3], @post.related[1..2]
550
- assert_equal [post2, post3], @post.related[1..5]
400
+ log = monitor { event.name }
551
401
 
552
- assert_equal [], @post.related[4..5]
553
- end
402
+ assert log.empty?
403
+ end
554
404
 
555
- should "respond to each" do
556
- @post.related << Post.create
557
- @post.related << Post.create
558
- @post.related << Post.create
405
+ test "load attributes as a strings" do
406
+ event = Event.create(:name => 1)
559
407
 
560
- i = 2
561
- @post.related.each do |c|
562
- assert_equal i, c.id.to_i
563
- i += 1
564
- end
565
- end
408
+ assert "1" == Event[event.id].name
409
+ end
566
410
 
567
- should "return the size of the list" do
568
- @post.related << Post.create
569
- @post.related << Post.create
570
- @post.related << Post.create
571
- assert_equal 3, @post.related.size
572
- end
411
+ # Attributes of type Set
412
+ setup do
413
+ @person1 = Person.create(:name => "Albert")
414
+ @person2 = Person.create(:name => "Bertrand")
415
+ @person3 = Person.create(:name => "Charles")
573
416
 
574
- should "return the last element with pop" do
575
- @post.related << Post.create
576
- @post.related << Post.create
577
- assert_equal "3", @post.related.pop.id
578
- assert_equal "2", @post.related.pop.id
579
- assert @post.related.empty?
580
- end
417
+ @event = Event.new
418
+ @event.name = "Ruby Tuesday"
419
+ end
581
420
 
582
- should "return the first element with shift" do
583
- @post.related << Post.create
584
- @post.related << Post.create
585
- assert_equal "2", @post.related.shift.id
586
- assert_equal "3", @post.related.shift.id
587
- assert @post.related.empty?
588
- end
421
+ test "not be available if the model is new" do
422
+ assert_raise Ohm::Model::MissingID do
423
+ @event.attendees << Person.new
424
+ end
425
+ end
589
426
 
590
- should "push to the head of the list with unshift" do
591
- @post.related.unshift Post.create
592
- @post.related.unshift Post.create
593
- assert_equal "2", @post.related.pop.id
594
- assert_equal "3", @post.related.pop.id
595
- assert @post.related.empty?
596
- end
427
+ test "remove an element if sent delete" do
428
+ @event.create
429
+ @event.attendees << @person1
430
+ @event.attendees << @person2
431
+ @event.attendees << @person3
432
+ assert ["1", "2", "3"] == @event.attendees.key.sort
433
+ @event.attendees.delete(@person2)
434
+ assert ["1", "3"] == Event[@event.id].attendees.key.sort
435
+ end
597
436
 
598
- should "empty the list" do
599
- @post.related.unshift Post.create
600
- @post.related.clear
437
+ test "return true if the set includes some member" do
438
+ @event.create
439
+ @event.attendees << @person1
440
+ @event.attendees << @person2
441
+ assert @event.attendees.include?(@person2)
442
+ assert !@event.attendees.include?(@person3)
443
+ end
601
444
 
602
- assert @post.related.empty?
603
- end
445
+ test "return instances of the passed model" do
446
+ @event.create
447
+ @event.attendees << @person1
604
448
 
605
- should "replace the values in the list" do
606
- @post.related.replace([Post.create, Post.create])
449
+ assert [@person1] == @event.attendees.all
450
+ assert @person1 == @event.attendees[@person1.id]
451
+ end
607
452
 
608
- assert_equal ["2", "3"], @post.related.map { |model| model.id }
609
- end
453
+ test "return the size of the set" do
454
+ @event.create
455
+ @event.attendees << @person1
456
+ @event.attendees << @person2
457
+ @event.attendees << @person3
458
+ assert 3 == @event.attendees.size
459
+ end
610
460
 
611
- should "add models" do
612
- @post.related.add(Post.create(:body => "Hello"))
613
- assert_equal ["2"], @post.related.map { |model| model.id }
614
- end
461
+ test "empty the set" do
462
+ @event.create
463
+ @event.attendees << @person1
615
464
 
616
- should "find elements in the list" do
617
- another_post = Post.create
465
+ @event.attendees.clear
618
466
 
619
- @post.related.add(another_post)
467
+ assert @event.attendees.empty?
468
+ end
620
469
 
621
- assert @post.related.include?(another_post)
622
- assert !@post.related.include?(Post.create)
623
- end
470
+ test "replace the values in the set" do
471
+ @event.create
472
+ @event.attendees << @person1
624
473
 
625
- should "unshift models" do
626
- @post.related.unshift(Post.create(:body => "Hello"))
627
- @post.related.unshift(Post.create(:body => "Goodbye"))
474
+ assert [@person1] == @event.attendees.all
628
475
 
629
- assert_equal ["3", "2"], @post.related.map { |model| model.id }
476
+ @event.attendees.replace([@person2, @person3])
630
477
 
631
- assert_equal "3", @post.related.shift.id
478
+ assert [@person2, @person3] == @event.attendees.all.sort_by(&:id)
479
+ end
632
480
 
633
- assert_equal "2", @post.related.pop.id
481
+ test "filter elements" do
482
+ @event.create
483
+ @event.attendees.add(@person1)
484
+ @event.attendees.add(@person2)
634
485
 
635
- assert_nil @post.related.pop
636
- end
637
- end
486
+ assert [@person1] == @event.attendees.find(:initial => "A").all
487
+ assert [@person2] == @event.attendees.find(:initial => "B").all
488
+ assert [] == @event.attendees.find(:initial => "Z").all
489
+ end
638
490
 
639
- context "Applying arbitrary transformations" do
640
- require "date"
491
+ # Attributes of type List
492
+ setup do
493
+ @post = Post.new
494
+ @post.body = "Hello world!"
495
+ @post.create
496
+ end
641
497
 
642
- class MyActiveRecordModel
643
- def self.find(id)
644
- return new if id.to_i == 1
645
- end
498
+ test "return an array" do
499
+ assert @post.related.all.kind_of?(Array)
500
+ end
646
501
 
647
- def id
648
- 1
649
- end
502
+ test "append elements with push" do
503
+ @post.related.push Post.create
504
+ @post.related << Post.create
650
505
 
651
- def ==(other)
652
- id == other.id
653
- end
654
- end
506
+ assert ["2", "3"] == @post.related.all.map { |model| model.id }
507
+ end
655
508
 
656
- class ::Calendar < Ohm::Model
657
- list :holidays, lambda { |v| Date.parse(v) }
658
- list :subscribers, lambda { |id| MyActiveRecordModel.find(id) }
659
- list :appointments, Appointment
660
- end
509
+ test "keep the inserting order" do
510
+ @post.related << Post.create
511
+ @post.related << Post.create
512
+ @post.related << Post.create
513
+ assert ["2", "3", "4"] == @post.related.all.map { |model| model.id }
514
+ end
661
515
 
662
- class ::Appointment < Ohm::Model
663
- attribute :text
664
- reference :subscriber, lambda { |id| MyActiveRecordModel.find(id) }
665
- end
516
+ test "keep the inserting order after saving" do
517
+ @post.related << Post.create
518
+ @post.related << Post.create
519
+ @post.related << Post.create
520
+ @post.save
521
+ assert ["2", "3", "4"] == Post[@post.id].related.map { |model| model.id }
522
+ end
666
523
 
667
- setup do
668
- @calendar = Calendar.create
524
+ test "allow slicing the list" do
525
+ post1 = Post.create
526
+ post2 = Post.create
527
+ post3 = Post.create
669
528
 
670
- @calendar.holidays.key.rpush "2009-05-25"
671
- @calendar.holidays.key.rpush "2009-07-09"
529
+ @post.related << post1
530
+ @post.related << post2
531
+ @post.related << post3
672
532
 
673
- @calendar.subscribers << MyActiveRecordModel.find(1)
674
- end
533
+ assert post1 == @post.related[0]
534
+ assert post2 == @post.related[1]
535
+ assert post3 == @post.related[-1]
675
536
 
676
- should "apply a transformation" do
677
- assert_equal [Date.new(2009, 5, 25), Date.new(2009, 7, 9)], @calendar.holidays.all
537
+ assert nil == @post.related[3]
678
538
 
679
- assert_equal [1], @calendar.subscribers.all.map { |model| model.id }
680
- assert_equal [MyActiveRecordModel.find(1)], @calendar.subscribers.all
681
- end
539
+ assert [post2, post3] == @post.related[1, 2]
540
+ assert [post2, post3] == @post.related[1, -1]
682
541
 
683
- should "allow lambdas in references" do
684
- appointment = Appointment.create(:subscriber => MyActiveRecordModel.find(1))
685
- assert_equal MyActiveRecordModel.find(1), appointment.subscriber
686
- end
542
+ assert [] == @post.related[4, 5]
687
543
 
688
- should "work with models too" do
689
- @calendar.appointments.add(Appointment.create(:text => "Meet with Bertrand"))
544
+ assert [post2, post3] == @post.related[1..2]
545
+ assert [post2, post3] == @post.related[1..5]
690
546
 
691
- assert_equal [Appointment[1]], Calendar[1].appointments.sort
692
- end
693
- end
547
+ assert [] == @post.related[4..5]
548
+ end
694
549
 
695
- context "Sorting lists and sets" do
696
- setup do
697
- @post = Post.create(:body => "Lorem")
698
- @post.related << Post.create
699
- @post.related << Post.create
700
- @post.related << Post.create
701
- end
550
+ test "respond to each" do
551
+ @post.related << Post.create
552
+ @post.related << Post.create
553
+ @post.related << Post.create
702
554
 
703
- should "sort values" do
704
- assert_equal %w{2 3 4}, @post.related.sort.map { |model| model.id }
705
- end
555
+ i = 2
556
+ @post.related.each do |c|
557
+ assert i == c.id.to_i
558
+ i += 1
706
559
  end
560
+ end
707
561
 
708
- context "Sorting lists and sets by model attributes" do
709
- setup do
710
- @event = Event.create(:name => "Ruby Tuesday")
711
- @event.attendees << Person.create(:name => "D")
712
- @event.attendees << Person.create(:name => "C")
713
- @event.attendees << Person.create(:name => "B")
714
- @event.attendees << Person.create(:name => "A")
715
- end
562
+ test "return the size of the list" do
563
+ @post.related << Post.create
564
+ @post.related << Post.create
565
+ @post.related << Post.create
566
+ assert 3 == @post.related.size
567
+ end
716
568
 
717
- should "sort the model instances by the values provided" do
718
- people = @event.attendees.sort_by(:name, :order => "ALPHA")
719
- assert_equal %w[A B C D], people.map { |person| person.name }
720
- end
569
+ test "return the last element with pop" do
570
+ @post.related << Post.create
571
+ @post.related << Post.create
572
+ assert "3" == @post.related.pop.id
573
+ assert "2" == @post.related.pop.id
574
+ assert @post.related.empty?
575
+ end
721
576
 
722
- should "accept a number in the limit parameter" do
723
- people = @event.attendees.sort_by(:name, :limit => 2, :order => "ALPHA")
724
- assert_equal %w[A B], people.map { |person| person.name }
725
- end
577
+ test "return the first element with shift" do
578
+ @post.related << Post.create
579
+ @post.related << Post.create
580
+ assert "2" == @post.related.shift.id
581
+ assert "3" == @post.related.shift.id
582
+ assert @post.related.empty?
583
+ end
726
584
 
727
- should "use the start parameter as an offset if the limit is provided" do
728
- people = @event.attendees.sort_by(:name, :limit => 2, :start => 1, :order => "ALPHA")
729
- assert_equal %w[B C], people.map { |person| person.name }
730
- end
731
- end
585
+ test "push to the head of the list with unshift" do
586
+ @post.related.unshift Post.create
587
+ @post.related.unshift Post.create
588
+ assert "2" == @post.related.pop.id
589
+ assert "3" == @post.related.pop.id
590
+ assert @post.related.empty?
591
+ end
732
592
 
733
- context "Collections initialized with a Model parameter" do
734
- setup do
735
- @user = User.create(:email => "albert@example.com")
736
- @user.posts.add Post.create(:body => "D")
737
- @user.posts.add Post.create(:body => "C")
738
- @user.posts.add Post.create(:body => "B")
739
- @user.posts.add Post.create(:body => "A")
740
- end
593
+ test "empty the list" do
594
+ @post.related.unshift Post.create
595
+ @post.related.clear
741
596
 
742
- should "return instances of the passed model" do
743
- assert_equal Post, @user.posts.first.class
744
- end
745
- end
597
+ assert @post.related.empty?
598
+ end
746
599
 
747
- context "Counters" do
748
- setup do
749
- @event = Event.create(:name => "Ruby Tuesday")
750
- end
600
+ test "replace the values in the list" do
601
+ @post.related.replace([Post.create, Post.create])
751
602
 
752
- should "raise ArgumentError if the attribute is not a counter" do
753
- assert_raise ArgumentError do
754
- @event.incr(:name)
755
- end
756
- end
603
+ assert ["2", "3"] == @post.related.map { |model| model.id }
604
+ end
757
605
 
758
- should "be zero if not initialized" do
759
- assert_equal 0, @event.votes
760
- end
606
+ test "add models" do
607
+ @post.related.add(Post.create(:body => "Hello"))
608
+ assert ["2"] == @post.related.map { |model| model.id }
609
+ end
761
610
 
762
- should "be able to increment a counter" do
763
- @event.incr(:votes)
764
- assert_equal 1, @event.votes
611
+ test "find elements in the list" do
612
+ another_post = Post.create
765
613
 
766
- @event.incr(:votes, 2)
767
- assert_equal 3, @event.votes
768
- end
614
+ @post.related.add(another_post)
769
615
 
770
- should "be able to decrement a counter" do
771
- @event.decr(:votes)
772
- assert_equal(-1, @event.votes)
616
+ assert @post.related.include?(another_post)
617
+ assert !@post.related.include?(Post.create)
618
+ end
773
619
 
774
- @event.decr(:votes, 2)
775
- assert_equal(-3, @event.votes)
776
- end
777
- end
620
+ test "unshift models" do
621
+ @post.related.unshift(Post.create(:body => "Hello"))
622
+ @post.related.unshift(Post.create(:body => "Goodbye"))
778
623
 
779
- context "Comparison" do
780
- setup do
781
- @user = User.create(:email => "foo")
782
- end
624
+ assert ["3", "2"] == @post.related.map { |model| model.id }
783
625
 
784
- should "be comparable to other instances" do
785
- assert_equal @user, User[@user.id]
626
+ assert "3" == @post.related.shift.id
786
627
 
787
- assert_not_equal @user, User.create
788
- assert_not_equal User.new, User.new
789
- end
628
+ assert "2" == @post.related.pop.id
790
629
 
791
- should "not be comparable to instances of other models" do
792
- assert_not_equal @user, Event.create(:name => "Ruby Tuesday")
793
- end
630
+ assert @post.related.pop.nil?
631
+ end
794
632
 
795
- should "be comparable to non-models" do
796
- assert_not_equal @user, 1
797
- assert_not_equal @user, true
633
+ # Applying arbitrary transformations
634
+ require "date"
798
635
 
799
- # Not equal although the other object responds to #key.
800
- assert_not_equal @user, OpenStruct.new(:key => @user.send(:key))
801
- end
636
+ class MyActiveRecordModel
637
+ def self.find(id)
638
+ return new if id.to_i == 1
802
639
  end
803
640
 
804
- context "Debugging" do
805
- class ::Bar < Ohm::Model
806
- attribute :name
807
- counter :visits
808
- set :friends, self
809
- list :comments, self
810
-
811
- def foo
812
- bar.foo
813
- end
814
-
815
- def baz
816
- bar.new.foo
817
- end
641
+ def id
642
+ 1
643
+ end
818
644
 
819
- def bar
820
- SomeMissingConstant
821
- end
822
- end
645
+ def ==(other)
646
+ id == other.id
647
+ end
648
+ end
823
649
 
824
- should "provide a meaningful inspect" do
825
- bar = Bar.new
650
+ class ::Calendar < Ohm::Model
651
+ list :holidays, lambda { |v| Date.parse(v) }
652
+ list :subscribers, lambda { |id| MyActiveRecordModel.find(id) }
653
+ list :appointments, Appointment
654
+ end
826
655
 
827
- assert_equal "#<Bar:? name=nil friends=nil comments=nil visits=0>", bar.inspect
656
+ class ::Appointment < Ohm::Model
657
+ attribute :text
658
+ reference :subscriber, lambda { |id| MyActiveRecordModel.find(id) }
659
+ end
828
660
 
829
- bar.update(:name => "Albert")
830
- bar.friends << Bar.create
831
- bar.friends << Bar.create
832
- bar.comments << Bar.create
833
- bar.incr(:visits)
661
+ setup do
662
+ @calendar = Calendar.create
834
663
 
835
- assert_equal %Q{#<Bar:#{bar.id} name="Albert" friends=#<Set (Bar): ["3", "2"]> comments=#<List (Bar): ["4"]> visits=1>}, Bar[bar.id].inspect
836
- end
664
+ @calendar.holidays.key.rpush "2009-05-25"
665
+ @calendar.holidays.key.rpush "2009-07-09"
837
666
 
838
- def assert_wrapper_exception(&block)
839
- begin
840
- block.call
841
- rescue NoMethodError => exception_raised
842
- end
667
+ @calendar.subscribers << MyActiveRecordModel.find(1)
668
+ end
843
669
 
844
- assert_match(/You tried to call SomeMissingConstant#\w+, but SomeMissingConstant is not defined on #{__FILE__}:\d+:in `bar'/, exception_raised.message)
845
- end
670
+ test "apply a transformation" do
671
+ assert [Date.new(2009, 5, 25), Date.new(2009, 7, 9)] == @calendar.holidays.all
846
672
 
847
- should "inform about a miscatch by Wrapper when calling class methods" do
848
- assert_wrapper_exception { Bar.new.baz }
849
- end
673
+ assert [1] == @calendar.subscribers.all.map { |model| model.id }
674
+ assert [MyActiveRecordModel.find(1)] == @calendar.subscribers.all
675
+ end
850
676
 
851
- should "inform about a miscatch by Wrapper when calling instance methods" do
852
- assert_wrapper_exception { Bar.new.foo }
853
- end
854
- end
677
+ test "allow lambdas in references" do
678
+ appointment = Appointment.create(:subscriber => MyActiveRecordModel.find(1))
679
+ assert MyActiveRecordModel.find(1) == appointment.subscriber
680
+ end
855
681
 
856
- context "Overwriting write" do
857
- class ::Baz < Ohm::Model
858
- attribute :name
682
+ test "work with models too" do
683
+ @calendar.appointments.add(Appointment.create(:text => "Meet with Bertrand"))
859
684
 
860
- def write
861
- self.name = "Foobar"
862
- super
863
- end
864
- end
685
+ assert [Appointment[1]] == Calendar[1].appointments.sort
686
+ end
865
687
 
866
- should "work properly" do
867
- baz = Baz.new
868
- baz.name = "Foo"
869
- baz.save
870
- baz.name = "Foo"
871
- baz.save
872
- assert_equal "Foobar", Baz[baz.id].name
873
- end
874
- end
688
+ # Sorting lists and sets
689
+ setup do
690
+ @post = Post.create(:body => "Lorem")
691
+ @post.related << Post.create
692
+ @post.related << Post.create
693
+ @post.related << Post.create
694
+ end
875
695
 
876
- context "References to other objects" do
877
- class ::Note < Ohm::Model
878
- attribute :content
879
- reference :source, Post
880
- collection :comments, Comment
881
- list :ratings, Rating
882
- end
696
+ test "sort values" do
697
+ assert %w{2 3 4} == @post.related.sort.map { |model| model.id }
698
+ end
883
699
 
884
- class ::Comment < Ohm::Model
885
- reference :note, Note
886
- end
700
+ # Sorting lists and sets by model attributes
701
+ setup do
702
+ @event = Event.create(:name => "Ruby Tuesday")
703
+ @event.attendees << Person.create(:name => "D")
704
+ @event.attendees << Person.create(:name => "C")
705
+ @event.attendees << Person.create(:name => "B")
706
+ @event.attendees << Person.create(:name => "A")
707
+ end
887
708
 
888
- class ::Rating < Ohm::Model
889
- attribute :value
890
- end
709
+ test "sort the model instances by the values provided" do
710
+ people = @event.attendees.sort_by(:name, :order => "ALPHA")
711
+ assert %w[A B C D] == people.map { |person| person.name }
712
+ end
891
713
 
892
- class ::Editor < Ohm::Model
893
- attribute :name
894
- reference :post, Post
895
- end
714
+ test "accept a number in the limit parameter" do
715
+ people = @event.attendees.sort_by(:name, :limit => 2, :order => "ALPHA")
716
+ assert %w[A B] == people.map { |person| person.name }
717
+ end
896
718
 
897
- class ::Post < Ohm::Model
898
- reference :author, Person
899
- collection :notes, Note, :source
900
- collection :editors, Editor
901
- end
719
+ test "use the start parameter as an offset if the limit is provided" do
720
+ people = @event.attendees.sort_by(:name, :limit => 2, :start => 1, :order => "ALPHA")
721
+ assert %w[B C] == people.map { |person| person.name }
722
+ end
902
723
 
903
- setup do
904
- @post = Post.create
905
- end
724
+ # Collections initialized with a Model parameter
725
+ setup do
726
+ @user = User.create(:email => "albert@example.com")
727
+ @user.posts.add Post.create(:body => "D")
728
+ @user.posts.add Post.create(:body => "C")
729
+ @user.posts.add Post.create(:body => "B")
730
+ @user.posts.add Post.create(:body => "A")
731
+ end
906
732
 
907
- context "a reference to another object" do
908
- should "return an instance of Person if author_id has a valid id" do
909
- @post.author_id = Person.create(:name => "Albert").id
910
- @post.save
911
- assert_equal "Albert", Post[@post.id].author.name
912
- end
733
+ test "return instances of the passed model" do
734
+ assert Post == @user.posts.first.class
735
+ end
913
736
 
914
- should "assign author_id if author is sent a valid instance" do
915
- @post.author = Person.create(:name => "Albert")
916
- @post.save
917
- assert_equal "Albert", Post[@post.id].author.name
918
- end
737
+ # Counters
738
+ setup do
739
+ @event = Event.create(:name => "Ruby Tuesday")
740
+ end
919
741
 
920
- should "assign nil if nil is passed to author" do
921
- @post.author = nil
922
- @post.save
923
- assert_nil Post[@post.id].author
924
- end
742
+ test "raise ArgumentError if the attribute is not a counter" do
743
+ assert_raise ArgumentError do
744
+ @event.incr(:name)
745
+ end
746
+ end
925
747
 
926
- should "be cached in an instance variable" do
927
- @author = Person.create(:name => "Albert")
928
- @post.update(:author => @author)
748
+ test "be zero if not initialized" do
749
+ assert 0 == @event.votes
750
+ end
929
751
 
930
- assert_equal @author, @post.author
931
- assert @post.author.object_id == @post.author.object_id
752
+ test "be able to increment a counter" do
753
+ @event.incr(:votes)
754
+ assert 1 == @event.votes
932
755
 
933
- @post.update(:author => Person.create(:name => "Bertrand"))
756
+ @event.incr(:votes, 2)
757
+ assert 3 == @event.votes
758
+ end
934
759
 
935
- assert_equal "Bertrand", @post.author.name
936
- assert @post.author.object_id == @post.author.object_id
760
+ test "be able to decrement a counter" do
761
+ @event.decr(:votes)
762
+ assert @event.votes == -1
937
763
 
938
- @post.update(:author_id => Person.create(:name => "Charles").id)
764
+ @event.decr(:votes, 2)
765
+ assert @event.votes == -3
766
+ end
939
767
 
940
- assert_equal "Charles", @post.author.name
941
- end
942
- end
768
+ # Comparison
769
+ setup do
770
+ @user = User.create(:email => "foo")
771
+ end
943
772
 
944
- context "a collection of other objects" do
945
- setup do
946
- @note = Note.create(:content => "Interesting stuff", :source => @post)
947
- @comment = Comment.create(:note => @note)
948
- end
773
+ test "be comparable to other instances" do
774
+ assert @user == User[@user.id]
949
775
 
950
- should "return a set of notes" do
951
- assert_equal @note.source, @post
952
- assert_equal @note, @post.notes.first
953
- end
776
+ assert @user != User.create
777
+ assert User.new != User.new
778
+ end
954
779
 
955
- should "return a set of comments" do
956
- assert_equal @comment, @note.comments.first
957
- end
780
+ test "not be comparable to instances of other models" do
781
+ assert @user != Event.create(:name => "Ruby Tuesday")
782
+ end
958
783
 
959
- should "return a list of ratings" do
960
- @rating = Rating.create(:value => 5)
961
- @note.ratings << @rating
784
+ test "be comparable to non-models" do
785
+ assert @user != 1
786
+ assert @user != true
962
787
 
963
- assert_equal @rating, @note.ratings.first
964
- end
788
+ # Not equal although the other object responds to #key.
789
+ assert @user != OpenStruct.new(:key => @user.send(:key))
790
+ end
965
791
 
966
- should "default to the current class name" do
967
- @editor = Editor.create(:name => "Albert", :post => @post)
792
+ # Debugging
793
+ class ::Bar < Ohm::Model
794
+ attribute :name
795
+ counter :visits
796
+ set :friends, self
797
+ list :comments, self
968
798
 
969
- assert_equal @editor, @post.editors.first
970
- end
971
- end
799
+ def foo
800
+ bar.foo
972
801
  end
973
802
 
974
- context "Models connected to different databases" do
975
- class ::Car < Ohm::Model
976
- attribute :name
977
- end
978
-
979
- class ::Make < Ohm::Model
980
- attribute :name
981
- end
803
+ def baz
804
+ bar.new.foo
805
+ end
982
806
 
983
- setup do
984
- Car.connect(:db => 15)
985
- Car.db.flushdb
986
- end
807
+ def bar
808
+ SomeMissingConstant
809
+ end
810
+ end
987
811
 
988
- should "save to the selected database" do
989
- car = Car.create(:name => "Twingo")
990
- make = Make.create(:name => "Renault")
812
+ test "provide a meaningful inspect" do
813
+ bar = Bar.new
991
814
 
992
- assert_equal ["1"], Redis.connect.smembers("Make:all")
993
- assert_equal [], Redis.connect.smembers("Car:all")
815
+ assert "#<Bar:? name=nil friends=nil comments=nil visits=0>" == bar.inspect
994
816
 
995
- assert_equal ["1"], Car.db.smembers("Car:all")
996
- assert_equal [], Car.db.smembers("Make:all")
817
+ bar.update(:name => "Albert")
818
+ bar.friends << Bar.create
819
+ bar.comments << Bar.create
820
+ bar.incr(:visits)
997
821
 
998
- assert_equal car, Car[1]
999
- assert_equal make, Make[1]
822
+ assert %Q{#<Bar:#{bar.id} name="Albert" friends=#<Set (Bar): ["2"]> comments=#<List (Bar): ["3"]> visits=1>} == Bar[bar.id].inspect
823
+ end
1000
824
 
1001
- Make.db.flushdb
825
+ def assert_wrapper_exception(&block)
826
+ begin
827
+ block.call
828
+ rescue NoMethodError => exception_raised
829
+ end
1002
830
 
1003
- assert_equal car, Car[1]
1004
- assert_nil Make[1]
1005
- end
831
+ assert exception_raised.message =~
832
+ /You tried to call SomeMissingConstant#\w+, but SomeMissingConstant is not defined on #{__FILE__}:\d+:in `bar'/
833
+ end
1006
834
 
1007
- should "allow changing the database" do
1008
- Car.create(:name => "Twingo")
835
+ test "inform about a miscatch by Wrapper when calling class methods" do
836
+ assert_wrapper_exception { Bar.new.baz }
837
+ end
1009
838
 
1010
- assert_equal ["1"], Car.all.key.smembers
839
+ test "inform about a miscatch by Wrapper when calling instance methods" do
840
+ assert_wrapper_exception { Bar.new.foo }
841
+ end
1011
842
 
1012
- Car.connect
1013
- assert_equal [], Car.all.key.smembers
843
+ # Overwriting write
844
+ class ::Baz < Ohm::Model
845
+ attribute :name
1014
846
 
1015
- Car.connect :db => 15
1016
- assert_equal ["1"], Car.all.key.smembers
1017
- end
847
+ def write
848
+ self.name = "Foobar"
849
+ super
1018
850
  end
851
+ end
1019
852
 
1020
- context "Persistence" do
1021
- should "persist attributes to a hash" do
1022
- event = Event.create(:name => "Redis Meetup")
1023
- event.incr(:votes)
853
+ test "work properly" do
854
+ baz = Baz.new
855
+ baz.name = "Foo"
856
+ baz.save
857
+ baz.name = "Foo"
858
+ baz.save
859
+ assert "Foobar" == Baz[baz.id].name
860
+ end
1024
861
 
1025
- assert_equal "hash", Ohm.redis.type("Event:1")
862
+ # Models connected to different databases
863
+ class ::Car < Ohm::Model
864
+ attribute :name
865
+ end
1026
866
 
1027
- assert_equal [
1028
- "Event:1", "Event:all", "Event:id"
1029
- ].sort, Ohm.redis.keys("Event:*").sort
867
+ class ::Make < Ohm::Model
868
+ attribute :name
869
+ end
1030
870
 
1031
- assert_equal "Redis Meetup", Event[1].name
1032
- assert_equal 1, Event[1].votes
1033
- end
1034
- end
871
+ setup do
872
+ Car.connect(:db => 15)
873
+ Car.db.flushdb
874
+ end
1035
875
 
1036
- context "Exporting" do
1037
- class Venue < Ohm::Model
1038
- attribute :name
876
+ test "save to the selected database" do
877
+ car = Car.create(:name => "Twingo")
878
+ make = Make.create(:name => "Renault")
1039
879
 
1040
- def validate
1041
- assert_present :name
1042
- end
1043
- end
880
+ assert ["1"] == Redis.connect.smembers("Make:all")
881
+ assert [] == Redis.connect.smembers("Car:all")
1044
882
 
1045
- context "a new model without errors" do
1046
- should "export an empty hash via to_hash" do
1047
- person = Venue.new
1048
- assert_equal({}, person.to_hash)
1049
- end
1050
- end
883
+ assert ["1"] == Car.db.smembers("Car:all")
884
+ assert [] == Car.db.smembers("Make:all")
1051
885
 
1052
- context "a new model with some errors" do
1053
- should "export a hash with the errors" do
1054
- person = Venue.new
1055
- person.valid?
886
+ assert car == Car[1]
887
+ assert make == Make[1]
1056
888
 
1057
- assert_equal({ :errors => [[:name, :not_present]] }, person.to_hash)
1058
- end
1059
- end
889
+ Make.db.flushdb
1060
890
 
1061
- context "an existing model" do
1062
- should "export a hash with the its id" do
1063
- person = Venue.create(:name => "John Doe")
1064
- assert_equal({ :id => '1' }, person.to_hash)
1065
- end
1066
- end
891
+ assert car == Car[1]
892
+ assert Make[1].nil?
893
+ end
1067
894
 
1068
- context "an existing model with validation errors" do
1069
- should "export a hash with its id and the errors" do
1070
- person = Venue.create(:name => "John Doe")
1071
- person.name = nil
1072
- person.valid?
895
+ test "allow changing the database" do
896
+ Car.create(:name => "Twingo")
1073
897
 
1074
- expected_hash = { :id => '1', :errors => [[:name, :not_present]] }
898
+ assert ["1"] == Car.all.key.smembers
1075
899
 
1076
- assert_equal expected_hash, person.to_hash
1077
- end
1078
- end
900
+ Car.connect
901
+ assert [] == Car.all.key.smembers
1079
902
 
1080
- class Programmer < Ohm::Model
1081
- attribute :language
903
+ Car.connect :db => 15
904
+ assert ["1"] == Car.all.key.smembers
905
+ end
1082
906
 
1083
- def validate
1084
- assert_present :language
1085
- end
907
+ # Persistence
908
+ test "persist attributes to a hash" do
909
+ event = Event.create(:name => "Redis Meetup")
910
+ event.incr(:votes)
1086
911
 
1087
- def to_hash
1088
- super.merge(:language => language)
1089
- end
1090
- end
912
+ assert "hash" == Ohm.redis.type("Event:1")
1091
913
 
1092
- context "a subclassed to_hash" do
1093
- should "return the merged attributes" do
1094
- programmer = Programmer.create(:language => "Ruby")
1095
- expected_hash = { :id => '1', :language => 'Ruby' }
914
+ assert [
915
+ "Event:1", "Event:all", "Event:id"
916
+ ].sort == Ohm.redis.keys("Event:*").sort
1096
917
 
1097
- assert_equal expected_hash, programmer.to_hash
1098
- end
1099
- end
918
+ assert "Redis Meetup" == Event[1].name
919
+ assert 1 == Event[1].votes
920
+ end
1100
921
 
1101
- context "the JSON representation of an object" do
1102
- should "just be the to_hash of a model" do
1103
- json = JSON.parse(Programmer.create(:language => "Ruby").to_json)
922
+ # a Model with individual attribute writing needs
923
+ class Order < Ohm::Model
924
+ attribute :state
1104
925
 
1105
- assert_equal ["id", "language"], json.keys.sort
1106
- assert_equal "1", json["id"]
1107
- assert_equal "Ruby", json["language"]
1108
- end
1109
- end
926
+ def authorize!
927
+ write_remote :state, 'authorized'
1110
928
  end
929
+ end
1111
930
 
1112
- describe "a Model with individual attribute writing needs" do
1113
- class Order < Ohm::Model
1114
- attribute :state
1115
-
1116
- def authorize!
1117
- write_remote :state, 'authorized'
1118
- end
1119
- end
1120
-
1121
- test "writes locally" do
1122
- order = Order.create(:state => "pending")
1123
- order.authorize!
1124
- assert_equal 'authorized', order.state
1125
- end
931
+ test "writes locally" do
932
+ order = Order.create(:state => "pending")
933
+ order.authorize!
934
+ assert 'authorized' == order.state
935
+ end
1126
936
 
1127
- test "writes remotely" do
1128
- order = Order.create(:state => "pending")
1129
- order.authorize!
1130
- order = Order[order.id]
1131
- assert_equal 'authorized', order.state
1132
- end
1133
- end
937
+ test "writes remotely" do
938
+ order = Order.create(:state => "pending")
939
+ order.authorize!
940
+ order = Order[order.id]
941
+ assert 'authorized' == order.state
942
+ end
1134
943
 
1135
- context "namespaced models" do
1136
- should "be persisted" do
1137
- SomeNamespace::Foo.create(:name => "foo")
944
+ # namespaced models
945
+ test "be persisted" do
946
+ SomeNamespace::Foo.create(:name => "foo")
1138
947
 
1139
- assert_equal "hash", Ohm.redis.type("SomeNamespace::Foo:1")
948
+ assert "hash" == Ohm.redis.type("SomeNamespace::Foo:1")
1140
949
 
1141
- assert_equal "foo", SomeNamespace::Foo[1].name
1142
- end
1143
- end
950
+ assert "foo" == SomeNamespace::Foo[1].name
1144
951
  end