ohm 0.0.34 → 0.0.35
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|