ohm 0.1.0.rc5 → 0.1.0.rc6

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.
@@ -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