sohm 0.0.1

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/test/model.rb ADDED
@@ -0,0 +1,789 @@
1
+ require_relative "helper"
2
+ require "ostruct"
3
+
4
+ class Post < Ohm::Model
5
+ attribute :body
6
+ attribute :published
7
+ set :related, :Post
8
+ end
9
+
10
+ class User < Ohm::Model
11
+ attribute :email
12
+ set :posts, :Post
13
+ end
14
+
15
+ class Person < Ohm::Model
16
+ attribute :name
17
+ counter :logins
18
+ index :initial
19
+
20
+ def initial
21
+ name[0, 1].upcase if name
22
+ end
23
+ end
24
+
25
+ class Event < Ohm::Model
26
+ attribute :name
27
+ counter :votes
28
+ set :attendees, :Person
29
+
30
+ attribute :slug
31
+
32
+ def save
33
+ self.slug = name.to_s.downcase
34
+ super
35
+ end
36
+ end
37
+
38
+ module SomeNamespace
39
+ class Foo < Ohm::Model
40
+ attribute :name
41
+ end
42
+
43
+ class Bar < Ohm::Model
44
+ reference :foo, 'SomeNamespace::Foo'
45
+ end
46
+ end
47
+
48
+ class Meetup < Ohm::Model
49
+ attribute :name
50
+ attribute :location
51
+ end
52
+
53
+ test "booleans" do
54
+ post = Post.new(body: true, published: false)
55
+
56
+ post.save
57
+
58
+ assert_equal true, post.body
59
+ assert_equal false, post.published
60
+
61
+ post = Post[post.id]
62
+
63
+ assert_equal "true", post.body
64
+ assert_equal nil, post.published
65
+ end
66
+
67
+ test "empty model is ok" do
68
+ class Foo < Ohm::Model
69
+ end
70
+
71
+ Foo.create
72
+ end
73
+
74
+ test "counters are cleaned up during deletion" do
75
+ e = Event.create(:name => "Foo")
76
+ e.incr :votes, 10
77
+
78
+ assert_equal 10, e.votes
79
+
80
+ e.delete
81
+ assert_equal 0, Event.redis.call("EXISTS", e.key[:counters])
82
+ end
83
+
84
+ test "get" do
85
+ m = Meetup.create(:name => "Foo")
86
+ m.name = "Bar"
87
+
88
+ assert_equal "Foo", m.get(:name)
89
+ assert_equal "Foo", m.name
90
+ end
91
+
92
+ test "set" do
93
+ m = Meetup.create(:name => "Foo")
94
+
95
+ m.set :name, "Bar"
96
+ assert_equal "Bar", m.name
97
+
98
+ m = Meetup[m.id]
99
+ assert_equal "Bar", m.name
100
+
101
+ # Deletes when value is nil.
102
+ m.set :name, nil
103
+ m = Meetup[m.id]
104
+ assert_equal 0, Meetup.redis.call("HEXISTS", m.key, :name)
105
+ end
106
+
107
+ test "assign attributes from the hash" do
108
+ event = Event.new(:name => "Ruby Tuesday")
109
+ assert event.name == "Ruby Tuesday"
110
+ end
111
+
112
+ test "assign an ID and save the object" do
113
+ event1 = Event.create(name: "Ruby Tuesday")
114
+ event2 = Event.create(name: "Ruby Meetup")
115
+
116
+ assert_equal "1", event1.id
117
+ assert_equal "2", event2.id
118
+ end
119
+
120
+ test "updates attributes" do
121
+ event = Meetup.create(:name => "Ruby Tuesday")
122
+ event.update(:name => "Ruby Meetup")
123
+ assert "Ruby Meetup" == event.name
124
+ end
125
+
126
+ test "save the attributes in UTF8" do
127
+ event = Meetup.create(:name => "32° Kisei-sen")
128
+ assert "32° Kisei-sen" == Meetup[event.id].name
129
+ end
130
+
131
+ test "delete the attribute if set to nil" do
132
+ event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
133
+ assert "Los Angeles" == Meetup[event.id].location
134
+ assert event.update(:location => nil)
135
+ assert_equal nil, Meetup[event.id].location
136
+ end
137
+
138
+ test "not raise if an attribute is redefined" do
139
+ class RedefinedModel < Ohm::Model
140
+ attribute :name
141
+
142
+ silence_warnings do
143
+ attribute :name
144
+ end
145
+ end
146
+ end
147
+
148
+ test "not raise if a counter is redefined" do
149
+ class RedefinedModel < Ohm::Model
150
+ counter :age
151
+
152
+ silence_warnings do
153
+ counter :age
154
+ end
155
+ end
156
+ end
157
+
158
+ test "not raise if a set is redefined" do
159
+ class RedefinedModel < Ohm::Model
160
+ set :friends, lambda { }
161
+
162
+ silence_warnings do
163
+ set :friends, lambda { }
164
+ end
165
+ end
166
+ end
167
+
168
+ test "not raise if a collection is redefined" do
169
+ class RedefinedModel < Ohm::Model
170
+ set :toys, lambda { }
171
+
172
+ silence_warnings do
173
+ set :toys, lambda { }
174
+ end
175
+ end
176
+ end
177
+
178
+ test "not raise if a index is redefined" do
179
+ class RedefinedModel < Ohm::Model
180
+ attribute :color
181
+ index :color
182
+ index :color
183
+ end
184
+ end
185
+
186
+ test "allow arbitrary IDs" do
187
+ Event.create(:id => "abc123", :name => "Concert")
188
+
189
+ assert Event.all.size == 1
190
+ assert Event["abc123"].name == "Concert"
191
+ end
192
+
193
+ test "forbid assignment of IDs on a new object" do
194
+ event = Event.new(:name => "Concert")
195
+
196
+ assert_raise(NoMethodError) do
197
+ event.id = "abc123"
198
+ end
199
+ end
200
+
201
+ setup do
202
+ Ohm.redis.call("SADD", "Event:all", 1)
203
+ Ohm.redis.call("HSET", "Event:1", "name", "Concert")
204
+ end
205
+
206
+ test "return an instance of Event" do
207
+ assert Event[1].kind_of?(Event)
208
+ assert 1 == Event[1].id
209
+ assert "Concert" == Event[1].name
210
+ end
211
+
212
+ setup do
213
+ Ohm.redis.call("SADD", "User:all", 1)
214
+ Ohm.redis.call("HSET", "User:1", "email", "albert@example.com")
215
+ end
216
+
217
+ test "return an instance of User" do
218
+ assert User[1].kind_of?(User)
219
+ assert 1 == User[1].id
220
+ assert "albert@example.com" == User[1].email
221
+ end
222
+
223
+ test "allow to map key to models" do
224
+ assert [User[1]] == [1].map(&User)
225
+ end
226
+
227
+ setup do
228
+ Ohm.redis.call("SADD", "User:all", 1)
229
+ Ohm.redis.call("SET", "User:1:email", "albert@example.com")
230
+
231
+ @user = User[1]
232
+ end
233
+
234
+ test "change its attributes" do
235
+ @user.email = "maria@example.com"
236
+ assert "maria@example.com" == @user.email
237
+ end
238
+
239
+ test "save the new values" do
240
+ @user.email = "maria@example.com"
241
+ @user.save
242
+
243
+ @user.email = "maria@example.com"
244
+ @user.save
245
+
246
+ assert "maria@example.com" == User[1].email
247
+ end
248
+
249
+ test "assign a new id to the event" do
250
+ event1 = Event.new
251
+ event1.save
252
+
253
+ event2 = Event.new
254
+ event2.save
255
+
256
+ assert !event1.new?
257
+ assert !event2.new?
258
+
259
+ assert_equal "1", event1.id
260
+ assert_equal "2", event2.id
261
+ end
262
+
263
+ # Saving a model
264
+ test "create the model if it is new" do
265
+ event = Event.new(:name => "Foo").save
266
+ assert "Foo" == Event[event.id].name
267
+ end
268
+
269
+ test "save it only if it was previously created" do
270
+ event = Event.new
271
+ event.name = "Lorem ipsum"
272
+ event.save
273
+
274
+ event.name = "Lorem"
275
+ event.save
276
+
277
+ assert "Lorem" == Event[event.id].name
278
+ end
279
+
280
+ test "allow to hook into save" do
281
+ event = Event.create(:name => "Foo")
282
+
283
+ assert "foo" == event.slug
284
+ end
285
+
286
+ test "save counters" do
287
+ event = Event.create(:name => "Foo")
288
+
289
+ event.incr(:votes)
290
+ event.save
291
+
292
+ assert_equal 1, Event[event.id].votes
293
+ end
294
+
295
+ # Delete
296
+ test "delete an existing model" do
297
+ class ModelToBeDeleted < Ohm::Model
298
+ attribute :name
299
+ set :foos, :Post
300
+ set :bars, :Post
301
+ end
302
+
303
+ @model = ModelToBeDeleted.create(:name => "Lorem")
304
+
305
+ @model.foos.add(Post.create)
306
+ @model.bars.add(Post.create)
307
+
308
+ id = @model.id
309
+
310
+ @model.delete
311
+
312
+ assert Ohm.redis.call("GET", ModelToBeDeleted.key[id]).nil?
313
+ assert Ohm.redis.call("GET", ModelToBeDeleted.key[id][:name]).nil?
314
+ assert Array.new == Ohm.redis.call("SMEMBERS", ModelToBeDeleted.key[id][:foos])
315
+ assert Array.new == Ohm.redis.call("LRANGE", ModelToBeDeleted.key[id][:bars], 0, -1)
316
+
317
+ assert ModelToBeDeleted.all.empty?
318
+ end
319
+
320
+ setup do
321
+ end
322
+
323
+ test "no leftover keys" do
324
+ class ::Foo < Ohm::Model
325
+ attribute :name
326
+ index :name
327
+ track :notes
328
+ end
329
+
330
+ assert_equal [], Ohm.redis.call("KEYS", "*")
331
+
332
+ Foo.create(:name => "Bar")
333
+ expected = %w[Foo:1:_indices Foo:1 Foo:all Foo:id Foo:indices:name:Bar]
334
+
335
+ assert_equal expected.sort, Ohm.redis.call("KEYS", "*").sort
336
+
337
+ Foo[1].delete
338
+ assert ["Foo:id"] == Ohm.redis.call("KEYS", "*")
339
+
340
+ Foo.create(:name => "Baz")
341
+
342
+ Ohm.redis.call("SET", Foo[2].key[:notes], "something")
343
+
344
+ expected = %w[Foo:2:_indices Foo:2 Foo:all Foo:id
345
+ Foo:indices:name:Baz Foo:2:notes]
346
+
347
+ assert_equal expected.sort, Ohm.redis.call("KEYS", "*").sort
348
+
349
+ Foo[2].delete
350
+ assert ["Foo:id"] == Ohm.redis.call("KEYS", "*")
351
+ end
352
+
353
+ # Listing
354
+ test "find all" do
355
+ event1 = Event.new
356
+ event1.name = "Ruby Meetup"
357
+ event1.save
358
+
359
+ event2 = Event.new
360
+ event2.name = "Ruby Tuesday"
361
+ event2.save
362
+
363
+ all = Event.all
364
+ assert all.detect {|e| e.name == "Ruby Meetup" }
365
+ assert all.detect {|e| e.name == "Ruby Tuesday" }
366
+ end
367
+
368
+ # Fetching
369
+ test "fetch ids" do
370
+ event1 = Event.create(:name => "A")
371
+ event2 = Event.create(:name => "B")
372
+
373
+ assert_equal [event1, event2], Event.fetch([event1.id, event2.id])
374
+ end
375
+
376
+ # Sorting
377
+ test "sort all" do
378
+ Person.create :name => "D"
379
+ Person.create :name => "C"
380
+ Person.create :name => "B"
381
+ Person.create :name => "A"
382
+
383
+ names = Person.all.sort_by(:name, :order => "ALPHA").map { |p| p.name }
384
+ assert %w[A B C D] == names
385
+ end
386
+
387
+ test "return an empty array if there are no elements to sort" do
388
+ assert [] == Person.all.sort_by(:name)
389
+ end
390
+
391
+ test "return the first element sorted by id when using first" do
392
+ Person.create :name => "A"
393
+ Person.create :name => "B"
394
+ assert "A" == Person.all.first.name
395
+ end
396
+
397
+ test "return the first element sorted by name if first receives a sorting option" do
398
+ Person.create :name => "B"
399
+ Person.create :name => "A"
400
+ assert "A" == Person.all.first(:by => :name, :order => "ALPHA").name
401
+ end
402
+
403
+ test "return attribute values when the get parameter is specified" do
404
+ Person.create :name => "B"
405
+ Person.create :name => "A"
406
+
407
+ res = Person.all.sort_by(:name, :get => :name, :order => "ALPHA")
408
+
409
+ assert_equal ["A", "B"], res
410
+ end
411
+
412
+ test "work on lists" do
413
+ post = Post.create :body => "Hello world!"
414
+
415
+ redis = Post.redis
416
+
417
+ redis.call("RPUSH", post.related.key, Post.create(:body => "C").id)
418
+ redis.call("RPUSH", post.related.key, Post.create(:body => "B").id)
419
+ redis.call("RPUSH", post.related.key, Post.create(:body => "A").id)
420
+
421
+ res = post.related.sort_by(:body, :order => "ALPHA ASC").map { |r| r.body }
422
+ assert_equal ["A", "B", "C"], res
423
+ end
424
+
425
+ # Loading attributes
426
+ setup do
427
+ event = Event.new
428
+ event.name = "Ruby Tuesday"
429
+ event.save.id
430
+ end
431
+
432
+ test "load attributes as a strings" do
433
+ event = Event.create(:name => 1)
434
+
435
+ assert "1" == Event[event.id].name
436
+ end
437
+
438
+ # Enumerable indices
439
+ class Entry < Ohm::Model
440
+ attribute :tags
441
+ index :tag
442
+
443
+ def tag
444
+ tags.split(/\s+/)
445
+ end
446
+ end
447
+
448
+ setup do
449
+ Entry.create(:tags => "foo bar baz")
450
+ end
451
+
452
+ test "finding by one entry in the enumerable" do |entry|
453
+ assert Entry.find(:tag => "foo").include?(entry)
454
+ assert Entry.find(:tag => "bar").include?(entry)
455
+ assert Entry.find(:tag => "baz").include?(entry)
456
+ end
457
+
458
+ test "finding by multiple entries in the enumerable" do |entry|
459
+ assert Entry.find(:tag => ["foo", "bar"]).include?(entry)
460
+ assert Entry.find(:tag => ["bar", "baz"]).include?(entry)
461
+ assert Entry.find(:tag => ["baz", "oof"]).empty?
462
+ end
463
+
464
+ # Attributes of type Set
465
+ setup do
466
+ @person1 = Person.create(:name => "Albert")
467
+ @person2 = Person.create(:name => "Bertrand")
468
+ @person3 = Person.create(:name => "Charles")
469
+
470
+ @event = Event.new
471
+ @event.name = "Ruby Tuesday"
472
+ end
473
+
474
+ test "filter elements" do
475
+ @event.save
476
+ @event.attendees.add(@person1)
477
+ @event.attendees.add(@person2)
478
+
479
+ assert [@person1] == @event.attendees.find(:initial => "A").to_a
480
+ assert [@person2] == @event.attendees.find(:initial => "B").to_a
481
+ assert [] == @event.attendees.find(:initial => "Z").to_a
482
+ end
483
+
484
+ test "delete elements" do
485
+ @event.save
486
+ @event.attendees.add(@person1)
487
+ @event.attendees.add(@person2)
488
+
489
+ assert_equal 2, @event.attendees.size
490
+
491
+ @event.attendees.delete(@person2)
492
+ assert_equal 1, @event.attendees.size
493
+ end
494
+
495
+ test "not be available if the model is new" do
496
+ assert_raise Ohm::MissingID do
497
+ @event.attendees
498
+ end
499
+ end
500
+
501
+ test "remove an element if sent delete" do
502
+ @event.save
503
+ @event.attendees.add(@person1)
504
+ @event.attendees.add(@person2)
505
+ @event.attendees.add(@person3)
506
+
507
+ assert_equal ["1", "2", "3"], Event.redis.call("SORT", @event.attendees.key)
508
+
509
+ Event.redis.call("SREM", @event.attendees.key, @person2.id)
510
+ assert_equal ["1", "3"], Event.redis.call("SORT", Event[@event.id].attendees.key)
511
+ end
512
+
513
+ test "return true if the set includes some member" do
514
+ @event.save
515
+ @event.attendees.add(@person1)
516
+ @event.attendees.add(@person2)
517
+ assert @event.attendees.include?(@person2)
518
+
519
+ @event.attendees.include?(@person3)
520
+ assert !@event.attendees.include?(@person3)
521
+ end
522
+
523
+ test "return instances of the passed model" do
524
+ @event.save
525
+ @event.attendees.add(@person1)
526
+
527
+ assert [@person1] == @event.attendees.to_a
528
+ assert @person1 == @event.attendees[@person1.id]
529
+ end
530
+
531
+ test "return the size of the set" do
532
+ @event.save
533
+ @event.attendees.add(@person1)
534
+ @event.attendees.add(@person2)
535
+ @event.attendees.add(@person3)
536
+ assert 3 == @event.attendees.size
537
+ end
538
+
539
+ test "empty the set" do
540
+ @event.save
541
+ @event.attendees.add(@person1)
542
+
543
+ Event.redis.call("DEL", @event.attendees.key)
544
+
545
+ assert @event.attendees.empty?
546
+ end
547
+
548
+ test "replace the values in the set" do
549
+ @event.save
550
+ @event.attendees.add(@person1)
551
+
552
+ assert [@person1] == @event.attendees.to_a
553
+
554
+ @event.attendees.replace([@person2, @person3])
555
+
556
+ assert [@person2, @person3] == @event.attendees.to_a.sort_by(&:id)
557
+ end
558
+
559
+ # Sorting lists and sets by model attributes
560
+ setup do
561
+ @event = Event.create(:name => "Ruby Tuesday")
562
+ {'D' => 4, 'C' => 2, 'B' => 5, 'A' => 3}.each_pair do |name, logins|
563
+ person = Person.create(:name => name)
564
+ person.incr :logins, logins
565
+ @event.attendees.add(person)
566
+ end
567
+ end
568
+
569
+ test "sort the model instances by the values provided" do
570
+ people = @event.attendees.sort_by(:name, :order => "ALPHA")
571
+ assert %w[A B C D] == people.map(&:name)
572
+ end
573
+
574
+ test "accept a number in the limit parameter" do
575
+ people = @event.attendees.sort_by(:name, :limit => [0, 2], :order => "ALPHA")
576
+ assert %w[A B] == people.map(&:name)
577
+ end
578
+
579
+ test "use the start parameter as an offset if the limit is provided" do
580
+ people = @event.attendees.sort_by(:name, :limit => [1, 2], :order => "ALPHA")
581
+ assert %w[B C] == people.map(&:name)
582
+ end
583
+
584
+ test "use counter attributes for sorting" do
585
+ people = @event.attendees.sort_by(:logins, :limit => [0, 3], :order => "ALPHA")
586
+ assert %w[C A D] == people.map(&:name)
587
+ end
588
+
589
+ test "use counter attributes for sorting with key option" do
590
+ people = @event.attendees.sort_by(:logins, :get => :logins, :limit => [0, 3], :order => "ALPHA")
591
+ assert %w[2 3 4] == people
592
+ end
593
+
594
+ # Collections initialized with a Model parameter
595
+ setup do
596
+ @user = User.create(:email => "albert@example.com")
597
+ @user.posts.add(Post.create(:body => "D"))
598
+ @user.posts.add(Post.create(:body => "C"))
599
+ @user.posts.add(Post.create(:body => "B"))
600
+ @user.posts.add(Post.create(:body => "A"))
601
+ end
602
+
603
+ test "return instances of the passed model" do
604
+ assert Post == @user.posts.first.class
605
+ end
606
+
607
+ test "remove an object from the set" do
608
+ post = @user.posts.first
609
+ assert @user.posts.include?(post)
610
+
611
+ User.redis.call("SREM", @user.posts.key, post.id)
612
+ assert !@user.posts.include?(post)
613
+ end
614
+
615
+ test "remove an object id from the set" do
616
+ post = @user.posts.first
617
+ assert @user.posts.include?(post)
618
+
619
+ User.redis.call("SREM", @user.posts.key, post.id)
620
+ assert !@user.posts.include?(post)
621
+ end
622
+
623
+ # Counters
624
+ setup do
625
+ @event = Event.create(:name => "Ruby Tuesday")
626
+ end
627
+
628
+ test "be zero if not initialized" do
629
+ assert 0 == @event.votes
630
+ end
631
+
632
+ test "be able to increment a counter" do
633
+ @event.incr(:votes)
634
+ assert 1 == @event.votes
635
+
636
+ @event.incr(:votes, 2)
637
+ assert 3 == @event.votes
638
+ end
639
+
640
+ test "be able to decrement a counter" do
641
+ @event.decr(:votes)
642
+ assert @event.votes == -1
643
+
644
+ @event.decr(:votes, 2)
645
+ assert @event.votes == -3
646
+ end
647
+
648
+ # Comparison
649
+ setup do
650
+ @user = User.create(:email => "foo")
651
+ end
652
+
653
+ test "be comparable to other instances" do
654
+ assert @user == User[@user.id]
655
+
656
+ assert @user != User.create
657
+ assert User.new != User.new
658
+ end
659
+
660
+ test "not be comparable to instances of other models" do
661
+ assert @user != Event.create(:name => "Ruby Tuesday")
662
+ end
663
+
664
+ test "be comparable to non-models" do
665
+ assert @user != 1
666
+ assert @user != true
667
+
668
+ # Not equal although the other object responds to #key.
669
+ assert @user != OpenStruct.new(:key => @user.send(:key))
670
+ end
671
+
672
+ # Debugging
673
+ class ::Bar < Ohm::Model
674
+ attribute :name
675
+ counter :visits
676
+ set :friends, self
677
+ set :comments, self
678
+
679
+ def foo
680
+ bar.foo
681
+ end
682
+
683
+ def baz
684
+ bar.new.foo
685
+ end
686
+
687
+ def bar
688
+ SomeMissingConstant
689
+ end
690
+ end
691
+
692
+ # Models connected to different databases
693
+ class ::Car < Ohm::Model
694
+ attribute :name
695
+
696
+ self.redis = Redic.new
697
+ end
698
+
699
+ class ::Make < Ohm::Model
700
+ attribute :name
701
+ end
702
+
703
+ setup do
704
+ Car.redis.call("SELECT", 15)
705
+ end
706
+
707
+ test "save to the selected database" do
708
+ car = Car.create(:name => "Twingo")
709
+ make = Make.create(:name => "Renault")
710
+
711
+ redis = Redic.new
712
+
713
+ assert ["1"] == redis.call("SMEMBERS", "Make:all")
714
+ assert [] == redis.call("SMEMBERS", "Car:all")
715
+
716
+ assert ["1"] == Car.redis.call("SMEMBERS", "Car:all")
717
+ assert [] == Car.redis.call("SMEMBERS", "Make:all")
718
+
719
+ assert car == Car[1]
720
+ assert make == Make[1]
721
+
722
+ Make.redis.call("FLUSHDB")
723
+
724
+ assert car == Car[1]
725
+ assert Make[1].nil?
726
+ end
727
+
728
+ test "allow changing the database" do
729
+ Car.create(:name => "Twingo")
730
+ assert_equal ["1"], Car.redis.call("SMEMBERS", Car.all.key)
731
+
732
+ Car.redis = Redic.new("redis://127.0.0.1:6379")
733
+ assert_equal [], Car.redis.call("SMEMBERS", Car.all.key)
734
+
735
+ Car.redis.call("SELECT", 15)
736
+ assert_equal ["1"], Car.redis.call("SMEMBERS", Car.all.key)
737
+ end
738
+
739
+ # Persistence
740
+ test "persist attributes to a hash" do
741
+ event = Event.create(:name => "Redis Meetup")
742
+ event.incr(:votes)
743
+
744
+ assert "hash" == Ohm.redis.call("TYPE", "Event:1")
745
+
746
+ expected= %w[Event:1 Event:1:counters Event:all Event:id]
747
+ assert_equal expected, Ohm.redis.call("KEYS", "Event:*").sort
748
+
749
+ assert "Redis Meetup" == Event[1].name
750
+ assert 1 == Event[1].votes
751
+ end
752
+
753
+ # namespaced models
754
+ test "be persisted" do
755
+ SomeNamespace::Foo.create(:name => "foo")
756
+
757
+ SomeNamespace::Bar.create(:foo => SomeNamespace::Foo[1])
758
+
759
+ assert "hash" == Ohm.redis.call("TYPE", "SomeNamespace::Foo:1")
760
+
761
+ assert "foo" == SomeNamespace::Foo[1].name
762
+ assert "foo" == SomeNamespace::Bar[1].foo.name
763
+ end if RUBY_VERSION >= "2.0.0"
764
+
765
+ test "typecast attributes" do
766
+ class Option < Ohm::Model
767
+ attribute :votes, lambda { |x| x.to_i }
768
+ end
769
+
770
+ option = Option.create :votes => 20
771
+ option.update(:votes => option.votes + 1)
772
+
773
+ assert_equal 21, option.votes
774
+ end
775
+
776
+ test "poster-example for overriding writers" do
777
+ silence_warnings do
778
+ class Advertiser < Ohm::Model
779
+ attribute :email
780
+
781
+ def email=(e)
782
+ attributes[:email] = e.to_s.downcase.strip
783
+ end
784
+ end
785
+ end
786
+
787
+ a = Advertiser.new(:email => " FOO@BAR.COM ")
788
+ assert_equal "foo@bar.com", a.email
789
+ end