ohm 0.0.28 → 0.0.29
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ohm.rb +63 -17
- data/test/model_test.rb +20 -0
- data/test/redis_test.rb +74 -52
- metadata +1 -1
data/lib/ohm.rb
CHANGED
@@ -368,15 +368,18 @@ module Ohm
|
|
368
368
|
#
|
369
369
|
# @param name [Symbol] Name of the attribute.
|
370
370
|
def self.attribute(name)
|
371
|
-
|
372
|
-
read_local(name)
|
373
|
-
end
|
371
|
+
unless attributes.include?(name)
|
374
372
|
|
375
|
-
|
376
|
-
|
377
|
-
|
373
|
+
define_method(name) do
|
374
|
+
read_local(name)
|
375
|
+
end
|
378
376
|
|
379
|
-
|
377
|
+
define_method(:"#{name}=") do |value|
|
378
|
+
write_local(name, value)
|
379
|
+
end
|
380
|
+
|
381
|
+
attributes << name
|
382
|
+
end
|
380
383
|
end
|
381
384
|
|
382
385
|
# Defines a counter attribute for the model. This attribute can't be assigned, only incremented
|
@@ -384,11 +387,14 @@ module Ohm
|
|
384
387
|
#
|
385
388
|
# @param name [Symbol] Name of the counter.
|
386
389
|
def self.counter(name)
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
+
unless counters.include?(name)
|
391
|
+
|
392
|
+
define_method(name) do
|
393
|
+
read_local(name).to_i
|
394
|
+
end
|
390
395
|
|
391
|
-
|
396
|
+
counters << name
|
397
|
+
end
|
392
398
|
end
|
393
399
|
|
394
400
|
# Defines a list attribute for the model. It can be accessed only after the model instance
|
@@ -396,8 +402,10 @@ module Ohm
|
|
396
402
|
#
|
397
403
|
# @param name [Symbol] Name of the list.
|
398
404
|
def self.list(name, model = nil)
|
399
|
-
|
400
|
-
|
405
|
+
unless collections.include?(name)
|
406
|
+
attr_list_reader(name, model)
|
407
|
+
collections << name
|
408
|
+
end
|
401
409
|
end
|
402
410
|
|
403
411
|
# Defines a set attribute for the model. It can be accessed only after the model instance
|
@@ -406,8 +414,10 @@ module Ohm
|
|
406
414
|
#
|
407
415
|
# @param name [Symbol] Name of the set.
|
408
416
|
def self.set(name, model = nil)
|
409
|
-
|
410
|
-
|
417
|
+
unless collections.include?(name)
|
418
|
+
attr_set_reader(name, model)
|
419
|
+
collections << name
|
420
|
+
end
|
411
421
|
end
|
412
422
|
|
413
423
|
# Creates an index (a set) that will be used for finding instances.
|
@@ -426,7 +436,9 @@ module Ohm
|
|
426
436
|
#
|
427
437
|
# @param name [Symbol] Name of the attribute to be indexed.
|
428
438
|
def self.index(att)
|
429
|
-
indices
|
439
|
+
unless indices.include?(att)
|
440
|
+
indices << att
|
441
|
+
end
|
430
442
|
end
|
431
443
|
|
432
444
|
def self.attr_list_reader(name, model = nil)
|
@@ -609,10 +621,37 @@ module Ohm
|
|
609
621
|
self.class.key(id, *args)
|
610
622
|
end
|
611
623
|
|
624
|
+
# Rewrite at runtime to use either SET or MSET for persisting to
|
625
|
+
# Redis. The idea is to use MSET when possible.
|
612
626
|
def write
|
627
|
+
if legacy_redis_version?
|
628
|
+
def write
|
629
|
+
write_with_set
|
630
|
+
end
|
631
|
+
else
|
632
|
+
def write
|
633
|
+
write_with_mset
|
634
|
+
end
|
635
|
+
end
|
636
|
+
write
|
637
|
+
end
|
638
|
+
|
639
|
+
# Write attributes using SET
|
640
|
+
# This method will be removed once MSET becomes standard.
|
641
|
+
def write_with_set
|
642
|
+
attributes.each do |att|
|
643
|
+
(value = send(att)) ?
|
644
|
+
db.set(key(att), value) :
|
645
|
+
db.del(key(att))
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
# Write attributes using MSET
|
650
|
+
# This is the preferred method, and will be the only option
|
651
|
+
# available once MSET becomes standard.
|
652
|
+
def write_with_mset
|
613
653
|
unless attributes.empty?
|
614
654
|
rems, adds = attributes.map { |a| [key(a), send(a)] }.partition { |t| t.last.nil? }
|
615
|
-
|
616
655
|
db.del(*rems.flatten.compact) unless rems.empty?
|
617
656
|
db.mset(adds.flatten) unless adds.empty?
|
618
657
|
end
|
@@ -620,6 +659,13 @@ module Ohm
|
|
620
659
|
|
621
660
|
private
|
622
661
|
|
662
|
+
# Determine if MSET is available. This method
|
663
|
+
# and the branch at #write will be deprecated
|
664
|
+
# once Redis 1.1 becomes the recommended version.
|
665
|
+
def legacy_redis_version?
|
666
|
+
db.info[:redis_version] <= "1.02"
|
667
|
+
end
|
668
|
+
|
623
669
|
def self.db
|
624
670
|
Ohm.redis
|
625
671
|
end
|
data/test/model_test.rb
CHANGED
@@ -626,4 +626,24 @@ class TestRedis < Test::Unit::TestCase
|
|
626
626
|
assert_equal %Q{#<Bar:#{bar.id} name="Albert" friends=#<Set: ["1", "2"]> comments=#<List: ["A"]> visits=1>}, Bar[bar.id].inspect
|
627
627
|
end
|
628
628
|
end
|
629
|
+
|
630
|
+
context "Overwritting write" do
|
631
|
+
class ::Baz < Ohm::Model
|
632
|
+
attribute :name
|
633
|
+
|
634
|
+
def write
|
635
|
+
self.name = "Foobar"
|
636
|
+
super
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
should "work properly" do
|
641
|
+
baz = Baz.new
|
642
|
+
baz.name = "Foo"
|
643
|
+
baz.save
|
644
|
+
baz.name = "Foo"
|
645
|
+
baz.save
|
646
|
+
assert_equal "Foobar", Baz[baz.id].name
|
647
|
+
end
|
648
|
+
end
|
629
649
|
end
|
data/test/redis_test.rb
CHANGED
@@ -14,6 +14,12 @@ class Foo
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class RedisTest < Test::Unit::TestCase
|
17
|
+
setup do
|
18
|
+
@legacy ||= begin
|
19
|
+
Ohm.redis.info[:redis_version] <= "1.02"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
17
23
|
describe "redis" do
|
18
24
|
setup do
|
19
25
|
@r ||= Ohm.redis
|
@@ -41,9 +47,11 @@ class RedisTest < Test::Unit::TestCase
|
|
41
47
|
end
|
42
48
|
|
43
49
|
should "be able to MSET keys" do
|
44
|
-
@
|
45
|
-
|
46
|
-
|
50
|
+
unless @legacy
|
51
|
+
@r.mset(:foo => "foobar", :bar => 1000)
|
52
|
+
assert_equal ["foobar", "1000"], @r.mget("foo", "bar")
|
53
|
+
assert_equal ["foobar", "1000", nil], @r.mget("foo", "bar", "baz")
|
54
|
+
end
|
47
55
|
end
|
48
56
|
|
49
57
|
should "be able to MGET keys" do
|
@@ -224,19 +232,21 @@ class RedisTest < Test::Unit::TestCase
|
|
224
232
|
end
|
225
233
|
|
226
234
|
should "be able to pop values from a list and push them onto a temp list with RPOPLPUSH" do
|
227
|
-
@
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
235
|
+
unless @legacy
|
236
|
+
@r.rpush "list", 'one'
|
237
|
+
@r.rpush "list", 'two'
|
238
|
+
@r.rpush "list", 'three'
|
239
|
+
assert_equal "list", @r.type('list')
|
240
|
+
assert_equal 3, @r.llen('list')
|
241
|
+
assert_equal %w(one two three), @r.lrange('list',0,-1)
|
242
|
+
assert_equal [], @r.lrange('tmp',0,-1)
|
243
|
+
assert_equal "three", @r.rpoplpush('list', 'tmp')
|
244
|
+
assert_equal %w(three), @r.lrange('tmp',0,-1)
|
245
|
+
assert_equal "two", @r.rpoplpush('list', 'tmp')
|
246
|
+
assert_equal %w(two three), @r.lrange('tmp',0,-1)
|
247
|
+
assert_equal "one", @r.rpoplpush('list', 'tmp')
|
248
|
+
assert_equal %w(one two three), @r.lrange('tmp',0,-1)
|
249
|
+
end
|
240
250
|
end
|
241
251
|
|
242
252
|
should "be able add members to a set" do
|
@@ -310,58 +320,70 @@ class RedisTest < Test::Unit::TestCase
|
|
310
320
|
end
|
311
321
|
|
312
322
|
should "be able add members to a zset ZADD" do
|
313
|
-
@
|
314
|
-
|
315
|
-
|
316
|
-
|
323
|
+
unless @legacy
|
324
|
+
@r.zadd 'zset', 1, 'set'
|
325
|
+
assert_equal %w(set), @r.zrange('zset', 0, 1)
|
326
|
+
assert_equal 1, @r.zcard('zset')
|
327
|
+
@r.del('zset')
|
328
|
+
end
|
317
329
|
end
|
318
330
|
|
319
331
|
should "be able count the members of a zset ZCARD" do
|
320
|
-
@
|
321
|
-
|
322
|
-
|
332
|
+
unless @legacy
|
333
|
+
@r.zadd 'zset', 1, 'foo'
|
334
|
+
@r.zcard('zset')
|
335
|
+
@r.del('zset')
|
336
|
+
end
|
323
337
|
end
|
324
338
|
|
325
339
|
|
326
340
|
should "be able delete members of a zset ZREM" do
|
327
|
-
@
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
341
|
+
unless @legacy
|
342
|
+
@r.zadd 'zset', 1, 'set'
|
343
|
+
assert_equal 1, @r.zcard('zset')
|
344
|
+
@r.zadd 'zset', 2, 'set2'
|
345
|
+
assert_equal 2, @r.zcard('zset')
|
346
|
+
@r.zrem 'zset', 'set'
|
347
|
+
assert_equal 1, @r.zcard('zset')
|
348
|
+
@r.del('zset')
|
349
|
+
end
|
334
350
|
end
|
335
351
|
|
336
352
|
should "be able to get a range of values from a zset ZRANGE" do
|
337
|
-
@
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
353
|
+
unless @legacy
|
354
|
+
@r.zadd 'zset', 1, 'set'
|
355
|
+
@r.zadd 'zset', 2, 'set2'
|
356
|
+
@r.zadd 'zset', 3, 'set3'
|
357
|
+
assert_equal 3, @r.zcard('zset')
|
358
|
+
assert_equal %w(set set2 set3), @r.zrange('zset', 0, 3)
|
359
|
+
@r.del('set')
|
360
|
+
@r.del('set2')
|
361
|
+
@r.del('set3')
|
362
|
+
@r.del('zset')
|
363
|
+
end
|
346
364
|
end
|
347
365
|
|
348
366
|
should "be able to get a reverse range of values from a zset ZREVRANGE" do
|
349
|
-
@
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
367
|
+
unless @legacy
|
368
|
+
@r.zadd 'zset', 1, 'set'
|
369
|
+
@r.zadd 'zset', 2, 'set2'
|
370
|
+
@r.zadd 'zset', 3, 'set3'
|
371
|
+
assert_equal 3, @r.zcard('zset')
|
372
|
+
assert_equal %w(set3 set2 set), @r.zrevrange('zset', 0, 3)
|
373
|
+
@r.del('zset')
|
374
|
+
end
|
355
375
|
end
|
356
376
|
|
357
377
|
should "be able to get a range by score of values from a zset ZRANGEBYSCORE" do
|
358
|
-
@
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
378
|
+
unless @legacy
|
379
|
+
@r.zadd 'zset', 1, 'set'
|
380
|
+
@r.zadd 'zset', 2, 'set2'
|
381
|
+
@r.zadd 'zset', 3, 'set3'
|
382
|
+
@r.zadd 'zset', 4, 'set4'
|
383
|
+
assert_equal 4, @r.zcard('zset')
|
384
|
+
assert_equal %w(set2 set3), @r.zrangebyscore('zset', 2, 3)
|
385
|
+
@r.del('zset')
|
386
|
+
end
|
365
387
|
end
|
366
388
|
|
367
389
|
should "provide info" do
|