ohm 0.0.34 → 0.0.35
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/lib/ohm.rb +63 -36
- data/lib/ohm/collection.rb +1 -1
- data/lib/ohm/compat-1.8.6.rb +16 -1
- data/test/benchmarks.rb +15 -37
- data/test/model_test.rb +93 -26
- metadata +31 -8
- data/Thorfile +0 -20
- data/lib/ohm/redis.rb +0 -305
- data/test/redis_test.rb +0 -432
data/lib/ohm.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require "base64"
|
4
|
-
require
|
4
|
+
require "redis"
|
5
|
+
|
5
6
|
require File.join(File.dirname(__FILE__), "ohm", "validations")
|
6
7
|
require File.join(File.dirname(__FILE__), "ohm", "compat-1.8.6")
|
7
8
|
require File.join(File.dirname(__FILE__), "ohm", "key")
|
8
9
|
require File.join(File.dirname(__FILE__), "ohm", "collection")
|
9
10
|
|
10
11
|
module Ohm
|
11
|
-
VERSION = "0.0.
|
12
|
+
VERSION = "0.0.35"
|
12
13
|
|
13
14
|
# Provides access to the Redis database. This is shared accross all models and instances.
|
14
15
|
def redis
|
@@ -39,9 +40,9 @@ module Ohm
|
|
39
40
|
|
40
41
|
# Return a connection to Redis.
|
41
42
|
#
|
42
|
-
# This is a wapper around
|
43
|
+
# This is a wapper around Redis.new(options)
|
43
44
|
def connection(*options)
|
44
|
-
|
45
|
+
Redis.new(*options)
|
45
46
|
end
|
46
47
|
|
47
48
|
def options
|
@@ -53,7 +54,6 @@ module Ohm
|
|
53
54
|
redis.flushdb
|
54
55
|
end
|
55
56
|
|
56
|
-
# Join the parameters with ":" to create a key.
|
57
57
|
def key(*args)
|
58
58
|
Key[*args]
|
59
59
|
end
|
@@ -63,15 +63,47 @@ module Ohm
|
|
63
63
|
Error = Class.new(StandardError)
|
64
64
|
|
65
65
|
class Model
|
66
|
+
|
67
|
+
# Wraps a model name for lazy evaluation.
|
68
|
+
class Wrapper < BasicObject
|
69
|
+
def initialize(name, &block)
|
70
|
+
@name = name
|
71
|
+
@caller = ::Kernel.caller[2]
|
72
|
+
@block = block
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def method_missing(method_id, *args)
|
76
|
+
::Kernel.raise ::NoMethodError, "You tried to call #{@name}##{method_id}, but #{@name} is not defined on #{@caller}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.wrap(object)
|
82
|
+
object.class == self ? object : new(object.inspect) { object }
|
83
|
+
end
|
84
|
+
|
85
|
+
def unwrap
|
86
|
+
@block.call
|
87
|
+
end
|
88
|
+
|
89
|
+
def class
|
90
|
+
Wrapper
|
91
|
+
end
|
92
|
+
|
93
|
+
def inspect
|
94
|
+
"<Wrapper for #{@name} (in #{@caller})>"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
66
98
|
class Collection
|
67
99
|
include Enumerable
|
68
100
|
|
69
101
|
attr :raw
|
70
102
|
attr :model
|
71
103
|
|
72
|
-
def initialize(key, model, db =
|
73
|
-
@
|
74
|
-
@
|
104
|
+
def initialize(key, model, db = nil)
|
105
|
+
@model = model.unwrap
|
106
|
+
@raw = self.class::Raw.new(key, db || @model.db)
|
75
107
|
end
|
76
108
|
|
77
109
|
def <<(model)
|
@@ -197,7 +229,7 @@ module Ohm
|
|
197
229
|
def apply(operation, hash, glue)
|
198
230
|
target = key.volatile.group(glue).append(*keys(hash))
|
199
231
|
model.db.send(operation, target, *target.sub_keys)
|
200
|
-
Set.new(target, model)
|
232
|
+
Set.new(target, Wrapper.wrap(model))
|
201
233
|
end
|
202
234
|
|
203
235
|
# Transform a hash of attribute/values into an array of keys.
|
@@ -240,7 +272,7 @@ module Ohm
|
|
240
272
|
class Index < Set
|
241
273
|
def apply(operation, hash, glue)
|
242
274
|
if hash.keys.size == 1
|
243
|
-
return Set.new(keys(hash).first, model)
|
275
|
+
return Set.new(keys(hash).first, Wrapper.wrap(model))
|
244
276
|
else
|
245
277
|
super
|
246
278
|
end
|
@@ -390,6 +422,8 @@ module Ohm
|
|
390
422
|
#
|
391
423
|
# @see Ohm::Model::collection
|
392
424
|
def self.reference(name, model)
|
425
|
+
model = Wrapper.wrap(model)
|
426
|
+
|
393
427
|
reader = :"#{name}_id"
|
394
428
|
writer = :"#{name}_id="
|
395
429
|
|
@@ -397,7 +431,7 @@ module Ohm
|
|
397
431
|
index reader
|
398
432
|
|
399
433
|
define_memoized_method(name) do
|
400
|
-
model[send(reader)]
|
434
|
+
model.unwrap[send(reader)]
|
401
435
|
end
|
402
436
|
|
403
437
|
define_method(:"#{name}=") do |value|
|
@@ -451,7 +485,8 @@ module Ohm
|
|
451
485
|
# @param model [Constant] Model where the reference is defined.
|
452
486
|
# @param reference [Symbol] Reference as defined in the associated model.
|
453
487
|
def self.collection(name, model, reference = to_reference)
|
454
|
-
|
488
|
+
model = Wrapper.wrap(model)
|
489
|
+
define_method(name) { model.unwrap.find(:"#{reference}_id" => send(:id)) }
|
455
490
|
end
|
456
491
|
|
457
492
|
def self.to_reference
|
@@ -460,6 +495,7 @@ module Ohm
|
|
460
495
|
|
461
496
|
def self.attr_collection_reader(name, type, model)
|
462
497
|
if model
|
498
|
+
model = Wrapper.wrap(model)
|
463
499
|
define_memoized_method(name) { Ohm::Model::const_get(type).new(key(name), model, db) }
|
464
500
|
else
|
465
501
|
define_memoized_method(name) { Ohm::const_get(type).new(key(name), db) }
|
@@ -482,7 +518,7 @@ module Ohm
|
|
482
518
|
end
|
483
519
|
|
484
520
|
def self.all
|
485
|
-
@all ||= Ohm::Model::Index.new(key(:all), self)
|
521
|
+
@all ||= Ohm::Model::Index.new(key(:all), Wrapper.wrap(self))
|
486
522
|
end
|
487
523
|
|
488
524
|
def self.attributes
|
@@ -659,35 +695,20 @@ module Ohm
|
|
659
695
|
self.class.key(id, *args)
|
660
696
|
end
|
661
697
|
|
662
|
-
# Use MSET if possible, SET otherwise.
|
663
|
-
def write
|
664
|
-
db.support_mset? ?
|
665
|
-
write_with_mset :
|
666
|
-
write_with_set
|
667
|
-
end
|
668
|
-
|
669
|
-
# Write attributes using SET
|
670
|
-
# This method will be removed once MSET becomes standard.
|
671
|
-
def write_with_set
|
672
|
-
attributes.each do |att|
|
673
|
-
value = send(att)
|
674
|
-
value.to_s.empty? ?
|
675
|
-
db.set(key(att), value) :
|
676
|
-
db.del(key(att))
|
677
|
-
end
|
678
|
-
end
|
679
|
-
|
680
698
|
# Write attributes using MSET
|
681
|
-
|
682
|
-
# available once MSET becomes standard.
|
683
|
-
def write_with_mset
|
699
|
+
def write
|
684
700
|
unless attributes.empty?
|
685
701
|
rems, adds = attributes.map { |a| [key(a), send(a)] }.partition { |t| t.last.to_s.empty? }
|
702
|
+
|
686
703
|
db.del(*rems.flatten.compact) unless rems.empty?
|
687
|
-
db.
|
704
|
+
db.mapped_mset(adds.flatten) unless adds.empty?
|
688
705
|
end
|
689
706
|
end
|
690
707
|
|
708
|
+
def self.const_missing(name)
|
709
|
+
Wrapper.new(name) { const_get(name) }
|
710
|
+
end
|
711
|
+
|
691
712
|
private
|
692
713
|
|
693
714
|
# Provides access to the Redis database. This is shared accross all models and instances.
|
@@ -759,6 +780,7 @@ module Ohm
|
|
759
780
|
def delete_from_indices
|
760
781
|
db.smembers(key(:_indices)).each do |index|
|
761
782
|
db.srem(index, id)
|
783
|
+
db.srem(key(:_indices), index)
|
762
784
|
end
|
763
785
|
end
|
764
786
|
|
@@ -771,7 +793,12 @@ module Ohm
|
|
771
793
|
end
|
772
794
|
|
773
795
|
def read_remote(att)
|
774
|
-
|
796
|
+
unless new?
|
797
|
+
value = db.get(key(att))
|
798
|
+
value.respond_to?(:force_encoding) ?
|
799
|
+
value.force_encoding("UTF-8") :
|
800
|
+
value
|
801
|
+
end
|
775
802
|
end
|
776
803
|
|
777
804
|
def read_locals(attrs)
|
data/lib/ohm/collection.rb
CHANGED
data/lib/ohm/compat-1.8.6.rb
CHANGED
@@ -14,7 +14,7 @@ unless "".respond_to?(:lines)
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
unless
|
17
|
+
unless respond_to?(:tap)
|
18
18
|
class Object
|
19
19
|
def tap
|
20
20
|
yield(self)
|
@@ -22,3 +22,18 @@ unless Object.new.respond_to?(:tap)
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
module Ohm
|
27
|
+
if defined?(BasicObject)
|
28
|
+
BasicObject = ::BasicObject
|
29
|
+
elsif defined?(BlankSlate)
|
30
|
+
BasicObject = ::BlankSlate
|
31
|
+
else
|
32
|
+
|
33
|
+
# If neither BasicObject (Ruby 1.9) nor BlankSlate (typically provided by Builder)
|
34
|
+
# are present, define our simple implementation inside the Ohm module.
|
35
|
+
class BasicObject
|
36
|
+
instance_methods.each { |meth| undef_method(meth) unless meth =~ /\A(__|instance_eval)/ }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/benchmarks.rb
CHANGED
@@ -7,55 +7,33 @@ Ohm.flush
|
|
7
7
|
|
8
8
|
class Event < Ohm::Model
|
9
9
|
attribute :name
|
10
|
-
|
10
|
+
attribute :location
|
11
|
+
|
12
|
+
index :name
|
13
|
+
index :location
|
11
14
|
|
12
15
|
def validate
|
13
16
|
assert_present :name
|
17
|
+
assert_present :location
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
array = []
|
19
|
-
|
20
|
-
benchmark "add to set with ohm redis" do
|
21
|
-
Ohm.redis.sadd("foo", 1)
|
22
|
-
end
|
23
|
-
|
24
|
-
benchmark "add to set with ohm" do
|
25
|
-
event.attendees << 1
|
26
|
-
end
|
27
|
-
|
28
|
-
Ohm.redis.sadd("bar", 1)
|
29
|
-
Ohm.redis.sadd("bar", 2)
|
30
|
-
|
31
|
-
benchmark "retrieve a set of two members with ohm redis" do
|
32
|
-
Ohm.redis.sadd("bar", 3)
|
33
|
-
Ohm.redis.srem("bar", 3)
|
34
|
-
Ohm.redis.smembers("bar")
|
35
|
-
end
|
36
|
-
|
37
|
-
Ohm.redis.del("Event:#{event.id}:attendees")
|
38
|
-
|
39
|
-
event.attendees << 1
|
40
|
-
event.attendees << 2
|
21
|
+
i = 0
|
41
22
|
|
42
|
-
benchmark "
|
43
|
-
|
44
|
-
event.attendees.delete(3)
|
45
|
-
event.attendees
|
23
|
+
benchmark "Create Events" do
|
24
|
+
Event.create(:name => "Redis Meetup #{i}", :location => "London #{i}")
|
46
25
|
end
|
47
26
|
|
48
|
-
benchmark "
|
49
|
-
|
50
|
-
Ohm.redis.sismember("bar", "1")
|
27
|
+
benchmark "Find by indexed attribute" do
|
28
|
+
Event.find(:name => "Redis Meetup #{i}").first
|
51
29
|
end
|
52
30
|
|
53
|
-
benchmark "
|
54
|
-
|
31
|
+
benchmark "Mass update" do
|
32
|
+
Event[1].update(:name => "Redis Meetup II")
|
55
33
|
end
|
56
34
|
|
57
|
-
benchmark "
|
58
|
-
|
35
|
+
benchmark "Load events" do
|
36
|
+
Event[1].name
|
59
37
|
end
|
60
38
|
|
61
|
-
run
|
39
|
+
run 5000
|
data/test/model_test.rb
CHANGED
@@ -41,6 +41,10 @@ class Event < Ohm::Model
|
|
41
41
|
end
|
42
42
|
|
43
43
|
class TestRedis < Test::Unit::TestCase
|
44
|
+
setup do
|
45
|
+
Ohm.flush
|
46
|
+
end
|
47
|
+
|
44
48
|
context "An event initialized with a hash of attributes" do
|
45
49
|
should "assign the passed attributes" do
|
46
50
|
event = Event.new(:name => "Ruby Tuesday")
|
@@ -50,8 +54,6 @@ class TestRedis < Test::Unit::TestCase
|
|
50
54
|
|
51
55
|
context "An event created from a hash of attributes" do
|
52
56
|
should "assign an id and save the object" do
|
53
|
-
Ohm.flush
|
54
|
-
|
55
57
|
event1 = Event.create(:name => "Ruby Tuesday")
|
56
58
|
event2 = Event.create(:name => "Ruby Meetup")
|
57
59
|
|
@@ -218,8 +220,6 @@ class TestRedis < Test::Unit::TestCase
|
|
218
220
|
|
219
221
|
context "Creating a new model" do
|
220
222
|
should "assign a new id to the event" do
|
221
|
-
Ohm.flush
|
222
|
-
|
223
223
|
event1 = Event.new
|
224
224
|
event1.create
|
225
225
|
|
@@ -259,20 +259,18 @@ class TestRedis < Test::Unit::TestCase
|
|
259
259
|
end
|
260
260
|
|
261
261
|
context "Delete" do
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
262
|
+
should "delete an existing model" do
|
263
|
+
class ModelToBeDeleted < Ohm::Model
|
264
|
+
attribute :name
|
265
|
+
set :foos
|
266
|
+
list :bars
|
267
|
+
end
|
267
268
|
|
268
|
-
setup do
|
269
269
|
@model = ModelToBeDeleted.create(:name => "Lorem")
|
270
270
|
|
271
271
|
@model.foos << "foo"
|
272
272
|
@model.bars << "bar"
|
273
|
-
end
|
274
273
|
|
275
|
-
should "delete an existing model" do
|
276
274
|
id = @model.id
|
277
275
|
|
278
276
|
@model.delete
|
@@ -280,10 +278,27 @@ class TestRedis < Test::Unit::TestCase
|
|
280
278
|
assert_nil Ohm.redis.get(ModelToBeDeleted.key(id))
|
281
279
|
assert_nil Ohm.redis.get(ModelToBeDeleted.key(id, :name))
|
282
280
|
assert_equal Array.new, Ohm.redis.smembers(ModelToBeDeleted.key(id, :foos))
|
283
|
-
assert_equal Array.new, Ohm.redis.
|
281
|
+
assert_equal Array.new, Ohm.redis.lrange(ModelToBeDeleted.key(id, :bars), 0, -1)
|
284
282
|
|
285
283
|
assert ModelToBeDeleted.all.empty?
|
286
284
|
end
|
285
|
+
|
286
|
+
should "be no leftover keys" do
|
287
|
+
class ::Foo < Ohm::Model
|
288
|
+
attribute :name
|
289
|
+
index :name
|
290
|
+
end
|
291
|
+
|
292
|
+
assert_equal [], Ohm.redis.keys("*")
|
293
|
+
|
294
|
+
Foo.create(:name => "Bar")
|
295
|
+
|
296
|
+
assert_equal ["Foo:1:_indices", "Foo:1:name", "Foo:all", "Foo:id", "Foo:name:QmFy"], Ohm.redis.keys("*").sort
|
297
|
+
|
298
|
+
Foo[1].delete
|
299
|
+
|
300
|
+
assert_equal ["Foo:id"], Ohm.redis.keys("*")
|
301
|
+
end
|
287
302
|
end
|
288
303
|
|
289
304
|
context "Listing" do
|
@@ -305,7 +320,6 @@ class TestRedis < Test::Unit::TestCase
|
|
305
320
|
|
306
321
|
context "Sorting" do
|
307
322
|
should "sort all" do
|
308
|
-
Ohm.flush
|
309
323
|
Person.create :name => "D"
|
310
324
|
Person.create :name => "C"
|
311
325
|
Person.create :name => "B"
|
@@ -315,26 +329,22 @@ class TestRedis < Test::Unit::TestCase
|
|
315
329
|
end
|
316
330
|
|
317
331
|
should "return an empty array if there are no elements to sort" do
|
318
|
-
Ohm.flush
|
319
332
|
assert_equal [], Person.all.sort_by(:name)
|
320
333
|
end
|
321
334
|
|
322
335
|
should "return the first element sorted by id when using first" do
|
323
|
-
Ohm.flush
|
324
336
|
Person.create :name => "A"
|
325
337
|
Person.create :name => "B"
|
326
338
|
assert_equal "A", Person.all.first.name
|
327
339
|
end
|
328
340
|
|
329
341
|
should "return the first element sorted by name if first receives a sorting option" do
|
330
|
-
Ohm.flush
|
331
342
|
Person.create :name => "B"
|
332
343
|
Person.create :name => "A"
|
333
344
|
assert_equal "A", Person.all.first(:by => :name, :order => "ALPHA").name
|
334
345
|
end
|
335
346
|
|
336
347
|
should "return attribute values when the get parameter is specified" do
|
337
|
-
Ohm.flush
|
338
348
|
Person.create :name => "B"
|
339
349
|
Person.create :name => "A"
|
340
350
|
|
@@ -344,8 +354,6 @@ class TestRedis < Test::Unit::TestCase
|
|
344
354
|
|
345
355
|
context "Loading attributes" do
|
346
356
|
setup do
|
347
|
-
Ohm.flush
|
348
|
-
|
349
357
|
event = Event.new
|
350
358
|
event.name = "Ruby Tuesday"
|
351
359
|
@id = event.create.id
|
@@ -367,8 +375,6 @@ class TestRedis < Test::Unit::TestCase
|
|
367
375
|
|
368
376
|
context "Attributes of type Set" do
|
369
377
|
setup do
|
370
|
-
Ohm.flush
|
371
|
-
|
372
378
|
@person1 = Person.create(:name => "Albert")
|
373
379
|
@person2 = Person.create(:name => "Bertrand")
|
374
380
|
@person3 = Person.create(:name => "Charles")
|
@@ -450,8 +456,6 @@ class TestRedis < Test::Unit::TestCase
|
|
450
456
|
|
451
457
|
context "Attributes of type List" do
|
452
458
|
setup do
|
453
|
-
Ohm.flush
|
454
|
-
|
455
459
|
@post = Post.new
|
456
460
|
@post.body = "Hello world!"
|
457
461
|
@post.create
|
@@ -585,13 +589,19 @@ class TestRedis < Test::Unit::TestCase
|
|
585
589
|
end
|
586
590
|
end
|
587
591
|
|
588
|
-
class Calendar < Ohm::Model
|
592
|
+
class ::Calendar < Ohm::Model
|
589
593
|
list :holidays, lambda { |v| Date.parse(v) }
|
590
594
|
list :subscribers, lambda { |id| MyActiveRecordModel.find(id) }
|
595
|
+
list :appointments, Appointment
|
596
|
+
end
|
597
|
+
|
598
|
+
class ::Appointment < Ohm::Model
|
599
|
+
attribute :text
|
591
600
|
end
|
592
601
|
|
593
602
|
setup do
|
594
603
|
@calendar = Calendar.create
|
604
|
+
|
595
605
|
@calendar.holidays.raw << "2009-05-25"
|
596
606
|
@calendar.holidays.raw << "2009-07-09"
|
597
607
|
|
@@ -604,6 +614,12 @@ class TestRedis < Test::Unit::TestCase
|
|
604
614
|
assert_equal ["1"], @calendar.subscribers.raw.all
|
605
615
|
assert_equal [MyActiveRecordModel.find(1)], @calendar.subscribers.all
|
606
616
|
end
|
617
|
+
|
618
|
+
should "work with models too" do
|
619
|
+
@calendar.appointments.add(Appointment.create(:text => "Meet with Bertrand"))
|
620
|
+
|
621
|
+
assert_equal [Appointment[1]], Calendar[1].appointments.sort
|
622
|
+
end
|
607
623
|
end
|
608
624
|
|
609
625
|
context "Sorting lists and sets" do
|
@@ -715,6 +731,18 @@ class TestRedis < Test::Unit::TestCase
|
|
715
731
|
counter :visits
|
716
732
|
set :friends
|
717
733
|
list :comments
|
734
|
+
|
735
|
+
def foo
|
736
|
+
bar.foo
|
737
|
+
end
|
738
|
+
|
739
|
+
def baz
|
740
|
+
bar.new.foo
|
741
|
+
end
|
742
|
+
|
743
|
+
def bar
|
744
|
+
SomeMissingConstant
|
745
|
+
end
|
718
746
|
end
|
719
747
|
|
720
748
|
should "provide a meaningful inspect" do
|
@@ -730,9 +758,26 @@ class TestRedis < Test::Unit::TestCase
|
|
730
758
|
|
731
759
|
assert_equal %Q{#<Bar:#{bar.id} name="Albert" friends=#<Set: ["1", "2"]> comments=#<List: ["A"]> visits=1>}, Bar[bar.id].inspect
|
732
760
|
end
|
761
|
+
|
762
|
+
def assert_wrapper_exception(&block)
|
763
|
+
begin
|
764
|
+
block.call
|
765
|
+
rescue NoMethodError => exception_raised
|
766
|
+
end
|
767
|
+
|
768
|
+
assert_match /You tried to call SomeMissingConstant#\w+, but SomeMissingConstant is not defined on #{__FILE__}:\d+:in `bar'/, exception_raised.message
|
769
|
+
end
|
770
|
+
|
771
|
+
should "inform about a miscatch by Wrapper when calling class methods" do
|
772
|
+
assert_wrapper_exception { Bar.new.baz }
|
773
|
+
end
|
774
|
+
|
775
|
+
should "inform about a miscatch by Wrapper when calling instance methods" do
|
776
|
+
assert_wrapper_exception { Bar.new.foo }
|
777
|
+
end
|
733
778
|
end
|
734
779
|
|
735
|
-
context "
|
780
|
+
context "Overwriting write" do
|
736
781
|
class ::Baz < Ohm::Model
|
737
782
|
attribute :name
|
738
783
|
|
@@ -756,6 +801,16 @@ class TestRedis < Test::Unit::TestCase
|
|
756
801
|
class ::Note < Ohm::Model
|
757
802
|
attribute :content
|
758
803
|
reference :source, Post
|
804
|
+
collection :comments, Comment
|
805
|
+
list :ratings, Rating
|
806
|
+
end
|
807
|
+
|
808
|
+
class ::Comment < Ohm::Model
|
809
|
+
reference :note, Note
|
810
|
+
end
|
811
|
+
|
812
|
+
class ::Rating < Ohm::Model
|
813
|
+
attribute :value
|
759
814
|
end
|
760
815
|
|
761
816
|
class ::Editor < Ohm::Model
|
@@ -813,6 +868,7 @@ class TestRedis < Test::Unit::TestCase
|
|
813
868
|
context "a collection of other objects" do
|
814
869
|
setup do
|
815
870
|
@note = Note.create(:content => "Interesting stuff", :source => @post)
|
871
|
+
@comment = Comment.create(:note => @note)
|
816
872
|
end
|
817
873
|
|
818
874
|
should "return a set of notes" do
|
@@ -820,6 +876,17 @@ class TestRedis < Test::Unit::TestCase
|
|
820
876
|
assert_equal @note, @post.notes.first
|
821
877
|
end
|
822
878
|
|
879
|
+
should "return a set of comments" do
|
880
|
+
assert_equal @comment, @note.comments.first
|
881
|
+
end
|
882
|
+
|
883
|
+
should "return a list of ratings" do
|
884
|
+
@rating = Rating.create(:value => 5)
|
885
|
+
@note.ratings << @rating
|
886
|
+
|
887
|
+
assert_equal @rating, @note.ratings.first
|
888
|
+
end
|
889
|
+
|
823
890
|
should "default to the current class name" do
|
824
891
|
@editor = Editor.create(:name => "Albert", :post => @post)
|
825
892
|
|