redis-objects 0.2.2 → 0.3.0

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.
@@ -3,8 +3,10 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
4
  require 'redis/counter'
5
5
  require 'redis/list'
6
- require 'redis/set'
7
6
  require 'redis/value'
7
+ require 'redis/lock'
8
+ require 'redis/set'
9
+ require 'redis/sorted_set'
8
10
 
9
11
  describe Redis::Value do
10
12
  before :all do
@@ -25,15 +27,24 @@ describe Redis::Value do
25
27
  end
26
28
 
27
29
  it "should handle complex marshaled values" do
30
+ @value.options[:marshal] = true
28
31
  @value.should == nil
29
32
  @value.value = {:json => 'data'}
30
33
  @value.should == {:json => 'data'}
31
- @value.get.should == {:json => 'data'}
34
+
35
+ # no marshaling
36
+ @value.options[:marshal] = false
37
+ v = {:json => 'data'}
38
+ @value.value = v
39
+ @value.should == v.to_s
40
+
41
+ @value.options[:marshal] = true
32
42
  @value.value = [[1,2], {:t3 => 4}]
33
43
  @value.should == [[1,2], {:t3 => 4}]
34
44
  @value.get.should == [[1,2], {:t3 => 4}]
35
45
  @value.del.should be_true
36
46
  @value.should be_nil
47
+ @value.options[:marshal] = false
37
48
  end
38
49
 
39
50
  it "should support renaming values" do
@@ -46,6 +57,7 @@ describe Redis::Value do
46
57
  old.should be_nil
47
58
  old.value = 'Tuff'
48
59
  @value.renamenx('spec/value').should be_false
60
+ @value.value.should == 'Peter Pan'
49
61
  end
50
62
 
51
63
  after :all do
@@ -103,6 +115,7 @@ describe Redis::List do
103
115
  @list << 'j'
104
116
  @list.should == ['a','c','f','j']
105
117
  @list[0..2].should == ['a','c','f']
118
+ @list[0, 2].should == ['a','c','f'] # consistent with Redis, not Ruby
106
119
  @list[1, 3].should == ['c','f','j']
107
120
  @list.length.should == 4
108
121
  @list.size.should == 4
@@ -135,13 +148,17 @@ describe Redis::List do
135
148
  end
136
149
 
137
150
  it "should handle lists of complex data types" do
138
- @list << {:json => 'data'}
139
- @list << {:json2 => 'data2'}
140
- @list.first.should == {:json => 'data'}
141
- @list.last.should == {:json2 => 'data2'}
151
+ @list.options[:marshal] = true
152
+ v1 = {:json => 'data'}
153
+ v2 = {:json2 => 'data2'}
154
+ @list << v1
155
+ @list << v2
156
+ @list.first.should == v1
157
+ @list.last.should == v2
142
158
  @list << [1,2,3,[4,5]]
143
159
  @list.last.should == [1,2,3,[4,5]]
144
160
  @list.shift.should == {:json => 'data'}
161
+ @list.options[:marshal] = false
145
162
  end
146
163
 
147
164
  it "should support renaming lists" do
@@ -159,9 +176,11 @@ describe Redis::List do
159
176
  old = Redis::List.new('spec/list')
160
177
  old.should be_empty
161
178
  old << 'Tuff'
179
+ old.values.should == ['Tuff']
162
180
  @list.renamenx('spec/list').should be_false
163
181
  @list.renamenx(old).should be_false
164
182
  @list.renamenx('spec/foo').should be_true
183
+ old.values.should == ['Tuff']
165
184
  @list.clear
166
185
  @list.redis.del('spec/list2')
167
186
  end
@@ -171,6 +190,134 @@ describe Redis::List do
171
190
  end
172
191
  end
173
192
 
193
+ describe Redis::Counter do
194
+ before :all do
195
+ @counter = Redis::Counter.new('spec/counter')
196
+ @counter2 = Redis::Counter.new('spec/counter')
197
+ end
198
+
199
+ before :each do
200
+ @counter.reset
201
+ end
202
+
203
+ it "should support increment/decrement of counters" do
204
+ @counter.key.should == 'spec/counter'
205
+ @counter.incr(10)
206
+ @counter.should == 10
207
+
208
+ # math proxy ops
209
+ (@counter == 10).should be_true
210
+ (@counter <= 10).should be_true
211
+ (@counter < 11).should be_true
212
+ (@counter > 9).should be_true
213
+ (@counter >= 10).should be_true
214
+ "#{@counter}".should == "10"
215
+
216
+ @counter.increment.should == 11
217
+ @counter.increment.should == 12
218
+ @counter2.increment.should == 13
219
+ @counter2.increment(2).should == 15
220
+ @counter.decrement.should == 14
221
+ @counter2.decrement.should == 13
222
+ @counter.decrement.should == 12
223
+ @counter2.decrement(4).should == 8
224
+ @counter.should == 8
225
+ @counter.reset.should be_true
226
+ @counter.should == 0
227
+ @counter.reset(15).should be_true
228
+ @counter.should == 15
229
+ end
230
+
231
+ after :all do
232
+ @counter.delete
233
+ end
234
+ end
235
+
236
+ describe Redis::Lock do
237
+ before :each do
238
+ $redis.flushall
239
+ end
240
+
241
+ it "should set the value to the expiration" do
242
+ start = Time.now
243
+ expiry = 15
244
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry)
245
+ lock.lock do
246
+ expiration = $redis.get("test_lock").to_f
247
+
248
+ # The expiration stored in redis should be 15 seconds from when we started
249
+ # or a little more
250
+ expiration.should be_close((start + expiry).to_f, 2.0)
251
+ end
252
+
253
+ # key should have been cleaned up
254
+ $redis.get("test_lock").should be_nil
255
+ end
256
+
257
+ it "should set value to 1 when no expiration is set" do
258
+ lock = Redis::Lock.new(:test_lock)
259
+ lock.lock do
260
+ $redis.get('test_lock').should == '1'
261
+ end
262
+
263
+ # key should have been cleaned up
264
+ $redis.get("test_lock").should be_nil
265
+ end
266
+
267
+ it "should let lock be gettable when lock is expired" do
268
+ expiry = 15
269
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
270
+
271
+ # create a fake lock in the past
272
+ $redis.set("test_lock", Time.now-(expiry + 60))
273
+
274
+ gotit = false
275
+ lock.lock do
276
+ gotit = true
277
+ end
278
+
279
+ # should get the lock because it has expired
280
+ gotit.should be_true
281
+ $redis.get("test_lock").should be_nil
282
+ end
283
+
284
+ it "should not let non-expired locks be gettable" do
285
+ expiry = 15
286
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
287
+
288
+ # create a fake lock
289
+ $redis.set("test_lock", (Time.now + expiry).to_f)
290
+
291
+ gotit = false
292
+ error = nil
293
+ begin
294
+ lock.lock do
295
+ gotit = true
296
+ end
297
+ rescue => error
298
+ end
299
+
300
+ error.should be_kind_of(Redis::Lock::LockTimeout)
301
+
302
+ # should not have the lock
303
+ gotit.should_not be_true
304
+
305
+ # lock value should still be set
306
+ $redis.get("test_lock").should_not be_nil
307
+ end
308
+
309
+ it "should not remove the key if lock is held past expiration" do
310
+ lock = Redis::Lock.new(:test_lock, :expiration => 0.0)
311
+
312
+ lock.lock do
313
+ sleep 1.1
314
+ end
315
+
316
+ # lock value should still be set since the lock was held for more than the expiry
317
+ $redis.get("test_lock").should_not be_nil
318
+ end
319
+ end
320
+
174
321
  describe Redis::Set do
175
322
  before :all do
176
323
  @set = Redis::Set.new('spec/set')
@@ -288,45 +435,162 @@ describe Redis::Set do
288
435
  end
289
436
  end
290
437
 
291
- describe Redis::Counter do
438
+ describe Redis::SortedSet do
292
439
  before :all do
293
- @counter = Redis::Counter.new('spec/counter')
294
- @counter2 = Redis::Counter.new('spec/counter')
440
+ @set = Redis::SortedSet.new('spec/zset')
441
+ @set_1 = Redis::SortedSet.new('spec/zset_1')
442
+ @set_2 = Redis::SortedSet.new('spec/zset_2')
443
+ @set_3 = Redis::SortedSet.new('spec/zset_3')
295
444
  end
296
445
 
297
446
  before :each do
298
- @counter.reset
447
+ @set.clear
448
+ @set_1.clear
449
+ @set_2.clear
450
+ @set_3.clear
299
451
  end
300
452
 
301
- it "should support increment/decrement of counters" do
302
- @counter.key.should == 'spec/counter'
303
- @counter.incr(10)
304
- @counter.should == 10
453
+ it "should handle sets of simple values" do
454
+ @set.should be_empty
455
+ @set['a'] = 11
456
+ @set['a'] = 21
457
+ @set.add('a', 5)
458
+ @set.score('a').should == 5
459
+ @set['a'].should == 5
460
+ @set['a'] = 3
461
+ @set['b'] = 5
462
+ @set['b'].should == 5
463
+ @set['c'] = 4
464
+
465
+ @set[0,-1].should == ['a','c','b']
466
+ @set[0..2].should == ['a','c','b']
467
+ @set[0,2].should == ['a','c','b'] # consistent with Redis, not Ruby
468
+ @set.range(0,1,:withscores => true).should == [['a',3],['c',4]]
469
+ @set.range(0,-1).should == ['a','c','b']
470
+ @set.revrange(0,-1).should == ['b','c','a']
471
+ @set[0..1].should == ['a','c']
472
+ @set[1].should == 0 # missing
473
+ @set.at(1).should == 'c'
474
+ @set.first.should == 'a'
475
+ @set.last.should == 'b'
476
+
477
+ @set.members.should == ['a','c','b']
478
+ @set.members(:withscores => true).should == [['a',3],['c',4],['b',5]]
479
+
480
+ @set['b'] = 5
481
+ @set['b'] = 6
482
+ @set.score('b').should == 6
483
+ @set.delete('c')
484
+ @set.to_s.should == 'a, b'
485
+ @set.should == ['a','b']
486
+ @set.members.should == ['a','b']
487
+ @set['d'] = 0
305
488
 
306
- # math proxy ops
307
- (@counter == 10).should be_true
308
- (@counter <= 10).should be_true
309
- (@counter < 11).should be_true
310
- (@counter > 9).should be_true
311
- (@counter >= 10).should be_true
312
- "#{@counter}".should == "10"
489
+ @set.rangebyscore(0, 4).should == ['d','a']
490
+ @set.rangebyscore(0, 4, :count => 1).should == ['d']
491
+ @set.rangebyscore(0, 4, :count => 2).should == ['d','a']
492
+ @set.rangebyscore(0, 4, :limit => 2).should == ['d','a']
493
+
494
+ # Redis 1.3.5
495
+ # @set.rangebyscore(0,4, :withscores => true).should == [['d',4],['a',3]]
496
+ # @set.revrangebyscore(0,4).should == ['d','a']
497
+ # @set.revrangebyscore(0,4, :count => 2).should == ['a','d']
498
+ # @set.rank('b').should == 2
499
+ # @set.revrank('b').should == 3
500
+
501
+ @set['f'] = 100
502
+ @set['g'] = 110
503
+ @set['h'] = 120
504
+ @set['j'] = 130
505
+ @set.incr('h', 20)
506
+ @set.remrangebyscore(100, 120)
507
+ @set.members.should == ['d','a','b','j','h']
508
+
509
+ # Redis 1.3.5
510
+ # @set['h'] = 12
511
+ # @set['j'] = 13
512
+ # @set.remrangebyrank(4,-1)
513
+ # @set.members.should == ['d','a','b']
514
+
515
+ @set.delete('d')
516
+ @set['c'] = 200
517
+ @set.members.should == ['a','b','j','h','c']
518
+ @set.delete('c')
519
+ @set.length.should == 4
520
+ @set.size.should == 4
521
+ end
313
522
 
314
- @counter.increment.should == 11
315
- @counter.increment.should == 12
316
- @counter2.increment.should == 13
317
- @counter2.increment(2).should == 15
318
- @counter.decrement.should == 14
319
- @counter2.decrement.should == 13
320
- @counter.decrement.should == 12
321
- @counter2.decrement(4).should == 8
322
- @counter.should == 8
323
- @counter.reset.should be_true
324
- @counter.should == 0
325
- @counter.reset(15).should be_true
326
- @counter.should == 15
523
+ # Not until Redis 1.3.5 with hashes
524
+ xit "Redis 1.3.5: should handle set intersections, unions, and diffs" do
525
+ @set_1['a'] = 5
526
+ @set_2['b'] = 18
527
+ @set_2['c'] = 12
528
+
529
+ @set_2['a'] = 10
530
+ @set_2['b'] = 15
531
+ @set_2['c'] = 15
532
+
533
+ (@set_1 & @set_2).sort.should == ['c','d','e']
534
+
535
+ @set_1 << 'a' << 'b' << 'c' << 'd' << 'e'
536
+ @set_2 << 'c' << 'd' << 'e' << 'f' << 'g'
537
+ @set_3 << 'a' << 'd' << 'g' << 'l' << 'm'
538
+ @set_1.sort.should == %w(a b c d e)
539
+ @set_2.sort.should == %w(c d e f g)
540
+ @set_3.sort.should == %w(a d g l m)
541
+ (@set_1 & @set_2).sort.should == ['c','d','e']
542
+ @set_1.intersection(@set_2).sort.should == ['c','d','e']
543
+ @set_1.intersection(@set_2, @set_3).sort.should == ['d']
544
+ @set_1.intersect(@set_2).sort.should == ['c','d','e']
545
+ @set_1.inter(@set_2, @set_3).sort.should == ['d']
546
+ @set_1.interstore(INTERSTORE_KEY, @set_2).should == 3
547
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['c','d','e']
548
+ @set_1.interstore(INTERSTORE_KEY, @set_2, @set_3).should == 1
549
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['d']
550
+
551
+ (@set_1 | @set_2).sort.should == ['a','b','c','d','e','f','g']
552
+ (@set_1 + @set_2).sort.should == ['a','b','c','d','e','f','g']
553
+ @set_1.union(@set_2).sort.should == ['a','b','c','d','e','f','g']
554
+ @set_1.union(@set_2, @set_3).sort.should == ['a','b','c','d','e','f','g','l','m']
555
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2).should == 7
556
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g']
557
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2, @set_3).should == 9
558
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g','l','m']
559
+
560
+ (@set_1 ^ @set_2).sort.should == ["a", "b"]
561
+ (@set_1 - @set_2).sort.should == ["a", "b"]
562
+ (@set_2 - @set_1).sort.should == ["f", "g"]
563
+ @set_1.difference(@set_2).sort.should == ["a", "b"]
564
+ @set_1.diff(@set_2).sort.should == ["a", "b"]
565
+ @set_1.difference(@set_2, @set_3).sort.should == ['b']
566
+ @set_1.diffstore(DIFFSTORE_KEY, @set_2).should == 2
567
+ @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['a','b']
568
+ @set_1.diffstore(DIFFSTORE_KEY, @set_2, @set_3).should == 1
569
+ @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['b']
570
+ end
571
+
572
+ it "should support renaming sets" do
573
+ @set.should be_empty
574
+ @set['zynga'] = 151
575
+ @set['playfish'] = 202
576
+ @set.members.should == ['zynga','playfish']
577
+ @set.key.should == 'spec/zset'
578
+ @set.rename('spec/zset2').should be_true
579
+ @set.key.should == 'spec/zset2'
580
+ old = Redis::SortedSet.new('spec/zset')
581
+ old.should be_empty
582
+ old['tuff'] = 54
583
+ @set.renamenx('spec/zset').should be_false
584
+ @set.renamenx(old).should be_false
585
+ @set.renamenx('spec/zfoo').should be_true
586
+ @set.clear
587
+ @set.redis.del('spec/zset2')
327
588
  end
328
589
 
329
590
  after :all do
330
- @counter.delete
591
+ @set.clear
592
+ @set_1.clear
593
+ @set_2.clear
594
+ @set_3.clear
331
595
  end
332
- end
596
+ end
@@ -10,9 +10,9 @@ class Roster
10
10
  counter :pitchers, :limit => :max_pitchers
11
11
  counter :basic
12
12
  lock :resort, :timeout => 2
13
- value :starting_pitcher
14
- list :player_stats
15
- set :outfielders
13
+ value :starting_pitcher, :marshal => true
14
+ list :player_stats, :marshal => true
15
+ set :outfielders, :marshal => true
16
16
 
17
17
  # global class counters
18
18
  counter :total_players_online, :global => true
@@ -58,7 +58,7 @@ describe Redis::Objects do
58
58
 
59
59
  it "should provide a connection method" do
60
60
  Roster.redis.should == Redis::Objects.redis
61
- Roster.redis.should be_kind_of(Redis)
61
+ # Roster.redis.should be_kind_of(Redis)
62
62
  end
63
63
 
64
64
  it "should create counter accessors" do
@@ -282,6 +282,19 @@ describe Redis::Objects do
282
282
  end
283
283
  error.should be_kind_of(NoMethodError)
284
284
  end
285
+
286
+ it "should support obtain_lock as a class method" do
287
+ error = nil
288
+ begin
289
+ Roster.obtain_lock(:resort, 2) do
290
+ Roster.redis.get("roster:2:resort_lock").should_not be_nil
291
+ end
292
+ rescue => error
293
+ end
294
+
295
+ error.should be_nil
296
+ Roster.redis.get("roster:2:resort_lock").should be_nil
297
+ end
285
298
 
286
299
  it "should handle simple values" do
287
300
  @roster.starting_pitcher.should == nil
@@ -635,4 +648,5 @@ describe Redis::Objects do
635
648
  error.should_not be_nil
636
649
  error.should be_kind_of(Redis::Lock::LockTimeout)
637
650
  end
651
+
638
652
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Nate Wiger
@@ -9,19 +14,23 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-12-14 00:00:00 -08:00
17
+ date: 2010-04-14 00:00:00 -07:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: redis
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
23
- version: "0.1"
24
- version:
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 3
31
+ version: 1.0.3
32
+ type: :runtime
33
+ version_requirements: *id001
25
34
  description: Map Redis types directly to Ruby objects. Works with any class or ORM.
26
35
  email: nate@wiger.org
27
36
  executables: []
@@ -30,7 +39,7 @@ extensions: []
30
39
 
31
40
  extra_rdoc_files:
32
41
  - ATOMICITY.rdoc
33
- - ChangeLog
42
+ - CHANGELOG.rdoc
34
43
  - README.rdoc
35
44
  files:
36
45
  - lib/redis/counter.rb
@@ -42,15 +51,17 @@ files:
42
51
  - lib/redis/objects/lists.rb
43
52
  - lib/redis/objects/locks.rb
44
53
  - lib/redis/objects/sets.rb
54
+ - lib/redis/objects/sorted_sets.rb
45
55
  - lib/redis/objects/values.rb
46
56
  - lib/redis/objects.rb
47
57
  - lib/redis/set.rb
58
+ - lib/redis/sorted_set.rb
48
59
  - lib/redis/value.rb
49
60
  - spec/redis_objects_instance_spec.rb
50
61
  - spec/redis_objects_model_spec.rb
51
62
  - spec/spec_helper.rb
52
63
  - ATOMICITY.rdoc
53
- - ChangeLog
64
+ - CHANGELOG.rdoc
54
65
  - README.rdoc
55
66
  has_rdoc: true
56
67
  homepage: http://github.com/nateware/redis-objects
@@ -66,18 +77,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
77
  requirements:
67
78
  - - ">="
68
79
  - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
69
82
  version: "0"
70
- version:
71
83
  required_rubygems_version: !ruby/object:Gem::Requirement
72
84
  requirements:
73
85
  - - ">="
74
86
  - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
75
89
  version: "0"
76
- version:
77
90
  requirements:
78
- - redis, v0.1 or greater
91
+ - redis, v1.0.3 or greater
79
92
  rubyforge_project: redis-objects
80
- rubygems_version: 1.3.5
93
+ rubygems_version: 1.3.6
81
94
  signing_key:
82
95
  specification_version: 3
83
96
  summary: Maps Redis types to Ruby objects
data/ChangeLog DELETED
@@ -1,15 +0,0 @@
1
-
2
- *0.2.2 [Final] (14 December 2009)*
3
-
4
- * Added @set.diff(@set2) with "^" and "-" synonyms (oversight). [Nate Wiger]
5
-
6
- * Implemented Redis core commands in all data types, such as rename. [Nate Wiger]
7
-
8
- * Renamed Redis::Serialize to Redis::Helpers::Serialize to keep Redis:: cleaner. [Nate Wiger]
9
-
10
- * More spec coverage. [Nate Wiger]
11
-
12
- *0.2.1 [Final] (27 November 2009)*
13
-
14
- * First worthwhile public release, with good spec coverage and functionality. [Nate Wiger]
15
-