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