redis-objects 0.4.1 → 0.5.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/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,29 @@
1
1
  = Changelog for Redis::Objects
2
2
 
3
+ == 0.5.1 [Final] (23 May 2011)
4
+
5
+ * Fixed super class delegation conflicts with Redis Counters vs ActiveRecord [Tim Aßmann]
6
+
7
+ * Added zcount method to SortedSet [dunedain289]
8
+
9
+ * Updated redis-objects to look for Redis.current and prefer it over global $redis variable [Jean Boussier]
10
+
11
+ * Updated URLs to reflect new redis.io website [Jérémy Lecour]
12
+
13
+ == 0.5.0 [Final] (8 November 2010)
14
+
15
+ * Incompatible change: Had to rename Redis::Hash to Redis::HashKey due to internal conflicts with Redis lib and Ruby [Nate Wiger]
16
+
17
+ * Fixed AR counter override so that Redis::Objects doesn't hide AR counters [Mattias Pfeiffer]
18
+
19
+ * Fixed delete problem with Redis::List and complex values [Esdras Mayrink]
20
+
21
+ * Fix Redis::HashKey to support complex (marshaled) types [Mattias Pfeiffer]
22
+
23
+ * Group results of SortedSet#rangebyscore and #revrangebyscore if :withscores option is passed [Szymon Nowak]
24
+
25
+ * Updated Redis DEL semantics per API change [Gabe da Silveira]
26
+
3
27
  == 0.4.1 [Final] (23 August 2010)
4
28
 
5
29
  * Fixes for Ruby 1.8 failures due to missing flatten() [Gabe da Silveira]
data/README.rdoc CHANGED
@@ -7,7 +7,7 @@ on _individual_ data structures, like counters, lists, and sets. The *atomic* p
7
7
  Using an ORM wrapper that retrieves a "record", updates values, then sends those values back,
8
8
  _removes_ the atomicity, cutting the nuts off the major advantage of Redis. Just use MySQL, k?
9
9
 
10
- This gem provides a Rubyish interface to Redis, by mapping {Redis types}[http://code.google.com/p/redis/wiki/CommandReference]
10
+ This gem provides a Rubyish interface to Redis, by mapping {Redis types}[http://redis.io/commands]
11
11
  to Ruby objects, via a thin layer over Ezra's +redis+ gem. It offers several advantages
12
12
  over the lower-level redis-rb API:
13
13
 
@@ -45,7 +45,7 @@ config/initializers/redis.rb is a good place for this.)
45
45
 
46
46
  require 'redis'
47
47
  require 'redis/objects'
48
- Redis::Objects.redis = Redis.new(:host => 127.0.0.1, :port => 6379)
48
+ Redis::Objects.redis = Redis.new(:host => '127.0.0.1', :port => 6379)
49
49
 
50
50
  Remember you can use Redis::Objects in any Ruby code. There are *no* dependencies
51
51
  on Rails. Standalone, Sinatra, Resque - no problem.
@@ -111,12 +111,12 @@ Finally, for free, you get a +redis+ method that points directly to a Redis conn
111
111
  @team.redis.get('somekey')
112
112
  @team.redis.smembers('someset')
113
113
 
114
- You can use the +redis+ handle to directly call any {Redis API command}[http://code.google.com/p/redis/wiki/CommandReference].
114
+ You can use the +redis+ handle to directly call any {Redis API command}[http://redis.io/commands].
115
115
 
116
116
  == Example 2: Standalone Usage
117
117
 
118
118
  There is a Ruby class that maps to each Redis type, with methods for each
119
- {Redis API command}[http://code.google.com/p/redis/wiki/CommandReference].
119
+ {Redis API command}[http://redis.io/commands].
120
120
  Note that calling +new+ does not imply it's actually a "new" value - it just
121
121
  creates a mapping between that object and the corresponding Redis data structure,
122
122
  which may already exist on the redis-server.
@@ -154,7 +154,7 @@ See the section on "Atomicity" for cool uses of atomic counter blocks.
154
154
 
155
155
  === Locks
156
156
 
157
- A convenience class that wraps the pattern of {using +setnx+ to perform locking}[http://code.google.com/p/redis/wiki/SetnxCommand].
157
+ A convenience class that wraps the pattern of {using +setnx+ to perform locking}[http://redis.io/commands/setnx].
158
158
 
159
159
  require 'redis/lock'
160
160
  @lock = Redis::Lock.new('image_resizing', :expiration => 15, :timeout => 0.1)
@@ -217,10 +217,11 @@ Complex data types are no problem with :marshal => true:
217
217
  === Hashes
218
218
 
219
219
  Hashes work like a Ruby {Hash}[http://ruby-doc.org/core/classes/Hash.html], with
220
- a few Redis-specific additions.
220
+ a few Redis-specific additions. (The class name is "HashKey" not just "Hash", due to
221
+ conflicts with the Ruby core Hash class in other gems.)
221
222
 
222
- require 'redis/hash'
223
- @hash = Redis::Hash.new('hash_name')
223
+ require 'redis/hash_key'
224
+ @hash = Redis::HashKey.new('hash_name')
224
225
  @hash['a'] = 1
225
226
  @hash['b'] = 2
226
227
  @hash.each do |k,v|
@@ -330,7 +331,7 @@ a Hash and an Array. You assign like a Hash, but retrieve like an Array:
330
331
  @sorted_set.incr('Peter') # shorthand
331
332
  @sorted_set.incr('Jeff', 4)
332
333
 
333
- The other Redis Sorted Set commands are supported as well; see {Sorted Sets API}[http://code.google.com/p/redis/wiki/SortedSets].
334
+ The other Redis Sorted Set commands are supported as well; see {Sorted Sets API}[http://redis.io/commands#sorted_set].
334
335
 
335
336
  == Atomic Counters and Locks
336
337
 
data/Rakefile CHANGED
@@ -11,8 +11,8 @@ begin
11
11
  gem.homepage = "http://github.com/nateware/redis-objects"
12
12
  gem.authors = ["Nate Wiger"]
13
13
  gem.add_development_dependency "bacon", ">= 0"
14
- gem.requirements << 'redis, v2.0.4 or greater'
15
- gem.add_dependency('redis', '>= 2.0.4')
14
+ gem.requirements << 'redis, v2.1.1 or greater'
15
+ gem.add_dependency('redis', '>= 2.1.1') # ALSO: update spec/spec_helper.rb
16
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
17
  end
18
18
  Jeweler::GemcutterTasks.new
@@ -27,6 +27,7 @@ end
27
27
  # spec.verbose = true
28
28
  # end
29
29
 
30
+ desc "run all the specs"
30
31
  task :test do
31
32
  sh "bacon spec/*_spec.rb"
32
33
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.5.1
@@ -3,8 +3,10 @@ class Redis
3
3
  class BaseObject
4
4
  def initialize(key, *args)
5
5
  @key = key.is_a?(Array) ? key.flatten.join(':') : key
6
- @options = args.last.is_a?(::Hash) ? args.pop : {} # ::Hash because of Redis::Hash
7
- @redis = args.first || $redis
6
+ @options = args.last.is_a?(Hash) ? args.pop : {}
7
+ @redis = args.first || $redis || Redis.current
8
8
  end
9
+
10
+ alias :inspect :to_s # Ruby 1.9.2
9
11
  end
10
12
  end
data/lib/redis/counter.rb CHANGED
@@ -62,7 +62,6 @@ class Redis
62
62
  ##
63
63
  # Proxy methods to help make @object.counter == 10 work
64
64
  def to_s; value.to_s; end
65
- alias_method :to_str, :to_s
66
65
  alias_method :to_i, :value
67
66
  def nil?; value.nil? end
68
67
 
@@ -1,8 +1,10 @@
1
+ require File.dirname(__FILE__) + '/base_object'
2
+
1
3
  class Redis
2
4
  #
3
5
  # Class representing a Redis hash.
4
6
  #
5
- class Hash < BaseObject
7
+ class HashKey < BaseObject
6
8
  require 'enumerator'
7
9
  include Enumerable
8
10
  require 'redis/helpers/core_commands'
@@ -10,7 +12,12 @@ class Redis
10
12
  require 'redis/helpers/serialize'
11
13
  include Redis::Helpers::Serialize
12
14
 
13
- attr_reader :key, :redis
15
+ attr_reader :key, :options, :redis
16
+
17
+ def initialize(key, *args)
18
+ super
19
+ @options[:marshal_keys] ||= {}
20
+ end
14
21
 
15
22
  # Needed since Redis::Hash masks bare Hash in redis.rb
16
23
  def self.[](*args)
@@ -19,7 +26,7 @@ class Redis
19
26
 
20
27
  # Sets a field to value
21
28
  def []=(field, value)
22
- store(field, value)
29
+ store(field, to_redis(value))
23
30
  end
24
31
 
25
32
  # Gets the value of a field
@@ -29,12 +36,12 @@ class Redis
29
36
 
30
37
  # Redis: HSET
31
38
  def store(field, value)
32
- redis.hset(key, field, value)
39
+ redis.hset(key, field, to_redis(value, options[:marshal_keys][field]))
33
40
  end
34
41
 
35
42
  # Redis: HGET
36
43
  def fetch(field)
37
- redis.hget(key, field)
44
+ from_redis redis.hget(key, field), options[:marshal_keys][field]
38
45
  end
39
46
 
40
47
  # Verify that a field exists. Redis: HEXISTS
@@ -57,13 +64,15 @@ class Redis
57
64
 
58
65
  # Return all the values of the hash. Redis: HVALS
59
66
  def values
60
- redis.hvals(key)
67
+ from_redis redis.hvals(key)
61
68
  end
62
69
  alias_method :vals, :values
63
70
 
64
71
  # Retrieve the entire hash. Redis: HGETALL
65
72
  def all
66
- redis.hgetall(key)
73
+ h = redis.hgetall(key)
74
+ h.each { |k,v| h[k] = from_redis(v, options[:marshal_keys][k]) }
75
+ h
67
76
  end
68
77
  alias_method :clone, :all
69
78
 
@@ -102,7 +111,9 @@ class Redis
102
111
  # Set keys in bulk, takes a hash of field/values {'field1' => 'val1'}. Redis: HMSET
103
112
  def bulk_set(*args)
104
113
  raise ArgumentError, "Argument to bulk_set must be hash of key/value pairs" unless args.last.is_a?(::Hash)
105
- redis.hmset(key, *args.last.inject([]){ |arr,kv| arr + kv })
114
+ redis.hmset(key, *args.last.inject([]){ |arr,kv|
115
+ arr + [kv[0], to_redis(kv[1], options[:marshal_keys][kv[0]])]
116
+ })
106
117
  end
107
118
 
108
119
  # Get keys in bulk, takes an array of fields as arguments. Redis: HMGET
@@ -110,14 +121,19 @@ class Redis
110
121
  hsh = {}
111
122
  res = redis.hmget(key, *fields.flatten)
112
123
  fields.each do |k|
113
- hsh[k] = res.shift
124
+ hsh[k] = from_redis(res.shift, options[:marshal_keys][k])
114
125
  end
115
126
  hsh
116
127
  end
117
128
 
118
129
  # Increment value by integer at field. Redis: HINCRBY
119
130
  def incrby(field, val = 1)
120
- redis.hincrby(key, field, val).to_i
131
+ ret = redis.hincrby(key, field, val)
132
+ unless ret.is_a? Array
133
+ ret.to_i
134
+ else
135
+ nil
136
+ end
121
137
  end
122
138
  alias_method :incr, :incrby
123
139
 
@@ -41,14 +41,12 @@ class Redis
41
41
  def move(dbindex)
42
42
  redis.move key, dbindex
43
43
  end
44
-
45
- # See the documentation for SORT: http://code.google.com/p/redis/wiki/SortCommand
46
- # TODO
47
- # def sort(options)
48
- # args = []
49
- # args += ['sort']
50
- # from_redis redis.sort key
51
- # end
44
+
45
+ def sort(options={})
46
+ options[:order] ||= "asc alpha"
47
+ redis.sort(key, options)
48
+ end
52
49
  end
50
+
53
51
  end
54
52
  end
@@ -3,8 +3,8 @@ class Redis
3
3
  module Serialize
4
4
  include Marshal
5
5
 
6
- def to_redis(value)
7
- return value unless options[:marshal]
6
+ def to_redis(value, marshal=false)
7
+ return value unless options[:marshal] || marshal
8
8
  case value
9
9
  when String, Fixnum, Bignum, Float
10
10
  value
@@ -13,15 +13,17 @@ class Redis
13
13
  end
14
14
  end
15
15
 
16
- def from_redis(value)
17
- return value unless options[:marshal]
16
+ def from_redis(value, marshal=false)
17
+ return value unless options[:marshal] || marshal
18
18
  case value
19
19
  when Array
20
20
  value.collect{|v| from_redis(v)}
21
+ when Hash
22
+ value.inject({}) { |h, (k, v)| h[k] = from_redis(v); h }
21
23
  else
22
24
  restore(value) rescue value
23
25
  end
24
26
  end
25
27
  end
26
28
  end
27
- end
29
+ end
data/lib/redis/list.rb CHANGED
@@ -73,7 +73,7 @@ class Redis
73
73
  # Use .del to completely delete the entire key.
74
74
  # Redis: LREM
75
75
  def delete(name, count=0)
76
- redis.lrem(key, count, name) # weird api
76
+ redis.lrem(key, count, to_redis(name)) # weird api
77
77
  end
78
78
 
79
79
  # Iterate through each member of the set. Redis::Objects mixes in Enumerable,
data/lib/redis/lock.rb CHANGED
@@ -41,7 +41,7 @@ class Redis
41
41
 
42
42
  # Lock is being held. Now check to see if it's expired (if we're using
43
43
  # lock expiration).
44
- # See "Handling Deadlocks" section on http://code.google.com/p/redis/wiki/SetnxCommand
44
+ # See "Handling Deadlocks" section on http://redis.io/commands/setnx
45
45
  if !@options[:expiration].nil?
46
46
  old_expiration = redis.get(key).to_f
47
47
 
@@ -55,6 +55,7 @@ class Redis
55
55
  # Increment a counter with the specified name and id. Accepts a block
56
56
  # like the instance method. See Redis::Objects::Counter for details.
57
57
  def increment_counter(name, id=nil, by=1, &block)
58
+ return super(name, id) unless counter_defined?(name)
58
59
  verify_counter_defined!(name, id)
59
60
  initialize_counter!(name, id)
60
61
  value = redis.incrby(redis_field_key(name, id), by).to_i
@@ -64,6 +65,7 @@ class Redis
64
65
  # Decrement a counter with the specified name and id. Accepts a block
65
66
  # like the instance method. See Redis::Objects::Counter for details.
66
67
  def decrement_counter(name, id=nil, by=1, &block)
68
+ return super(name, id) unless counter_defined?(name)
67
69
  verify_counter_defined!(name, id)
68
70
  initialize_counter!(name, id)
69
71
  value = redis.decrby(redis_field_key(name, id), by).to_i
@@ -81,12 +83,16 @@ class Redis
81
83
  private
82
84
 
83
85
  def verify_counter_defined!(name, id) #:nodoc:
84
- raise Redis::Objects::UndefinedCounter, "Undefined counter :#{name} for class #{self.name}" unless @redis_objects.has_key?(name)
86
+ raise NoMethodError, "Undefined counter :#{name} for class #{self.name}" unless counter_defined?(name)
85
87
  if id.nil? and !@redis_objects[name][:global]
86
88
  raise Redis::Objects::MissingID, "Missing ID for non-global counter #{self.name}##{name}"
87
89
  end
88
90
  end
89
91
 
92
+ def counter_defined?(name) #:nodoc:
93
+ @redis_objects && @redis_objects.has_key?(name)
94
+ end
95
+
90
96
  def initialize_counter!(name, id) #:nodoc:
91
97
  key = redis_field_key(name, id)
92
98
  unless @initialized_counters[key]
@@ -117,16 +123,24 @@ class Redis
117
123
  # It is more efficient to use increment_[counter_name] directly.
118
124
  # This is mainly just for completeness to override ActiveRecord.
119
125
  def increment(name, by=1)
120
- send(name).increment(by)
126
+ if self.class.send("counter_defined?", name)
127
+ send(name).increment(by)
128
+ else
129
+ super
130
+ end
121
131
  end
122
132
 
123
133
  # Decrement a counter.
124
134
  # It is more efficient to use increment_[counter_name] directly.
125
135
  # This is mainly just for completeness to override ActiveRecord.
126
136
  def decrement(name, by=1)
127
- send(name).decrement(by)
137
+ if self.class.send("counter_defined?", name)
138
+ send(name).decrement(by)
139
+ else
140
+ super
141
+ end
128
142
  end
129
143
  end
130
144
  end
131
145
  end
132
- end
146
+ end
@@ -1,6 +1,6 @@
1
1
  # This is the class loader, for use as "include Redis::Objects::Hashes"
2
2
  # For the object itself, see "Redis::Hash"
3
- require 'redis/hash'
3
+ require 'redis/hash_key'
4
4
  class Redis
5
5
  module Objects
6
6
  module Hashes
@@ -19,7 +19,7 @@ class Redis
19
19
  if options[:global]
20
20
  instance_eval <<-EndMethods
21
21
  def #{name}
22
- @#{name} ||= Redis::Hash.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
+ @#{name} ||= Redis::HashKey.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
23
23
  end
24
24
  EndMethods
25
25
  class_eval <<-EndMethods
@@ -30,7 +30,7 @@ class Redis
30
30
  else
31
31
  class_eval <<-EndMethods
32
32
  def #{name}
33
- @#{name} ||= Redis::Hash.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
33
+ @#{name} ||= Redis::HashKey.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
34
34
  end
35
35
  EndMethods
36
36
  end
data/lib/redis/objects.rb CHANGED
@@ -46,12 +46,13 @@ class Redis
46
46
  autoload :Values, File.join(dir, 'values')
47
47
  autoload :Hashes, File.join(dir, 'hashes')
48
48
 
49
- class NotConnected < StandardError; end
49
+ class NotConnected < StandardError; end
50
+ class NilObjectId < StandardError; end
50
51
 
51
52
  class << self
52
53
  def redis=(conn) @redis = conn end
53
54
  def redis
54
- @redis ||= $redis || raise(NotConnected, "Redis::Objects.redis not set to a Redis.new connection")
55
+ @redis ||= $redis || Redis.current || raise(NotConnected, "Redis::Objects.redis not set to a Redis.new connection")
55
56
  end
56
57
 
57
58
  def included(klass)
@@ -74,7 +75,9 @@ class Redis
74
75
 
75
76
  # Class methods that appear in your class when you include Redis::Objects.
76
77
  module ClassMethods
77
- attr_accessor :redis, :redis_objects
78
+ attr_writer :redis
79
+ attr_accessor :redis_objects
80
+ def redis() @redis ||= Objects.redis end
78
81
 
79
82
  # Set the Redis redis_prefix to use. Defaults to model_name
80
83
  def redis_prefix=(redis_prefix) @redis_prefix = redis_prefix end
@@ -86,10 +89,19 @@ class Redis
86
89
  downcase
87
90
  end
88
91
 
89
- def redis_field_key(name, id='') #:nodoc:
92
+ def redis_field_key(name, id=nil) #:nodoc:
90
93
  klass = first_ancestor_with(name)
91
- # This can never ever ever ever change or upgrades will corrupt all data
92
- klass.redis_objects[name.to_sym][:key] || "#{redis_prefix(klass)}:#{id}:#{name}"
94
+ # READ THIS: This can never ever ever ever change or upgrades will corrupt all data
95
+ # I don't think people were using Proc as keys before (that would create a weird key). Should be ok
96
+ key = klass.redis_objects[name.to_sym][:key]
97
+ if key && key.respond_to?(:call)
98
+ key = key.call self
99
+ end
100
+ if id.nil? and !klass.redis_objects[name.to_sym][:global]
101
+ raise NilObjectId,
102
+ "[#{klass.redis_objects[name.to_sym]}] Attempt to address redis-object :#{name} on class #{klass.name} with nil id (unsaved record?) [object_id=#{object_id}]"
103
+ end
104
+ key || "#{redis_prefix(klass)}:#{id}:#{name}"
93
105
  end
94
106
 
95
107
  def first_ancestor_with(name)
@@ -107,8 +119,16 @@ class Redis
107
119
  def redis_field_key(name) #:nodoc:
108
120
  klass = self.class.first_ancestor_with(name)
109
121
  if key = klass.redis_objects[name.to_sym][:key]
110
- eval "%(#{key})"
122
+ if key.respond_to?(:call)
123
+ key.call self
124
+ else
125
+ eval "%(#{key})"
126
+ end
111
127
  else
128
+ if id.nil? and !klass.redis_objects[name.to_sym][:global]
129
+ raise NilObjectId,
130
+ "Attempt to address redis-object :#{name} on class #{klass.name} with nil id (unsaved record?) [object_id=#{object_id}]"
131
+ end
112
132
  # don't try to refactor into class redis_field_key because fucks up eval context
113
133
  "#{klass.redis_prefix}:#{id}:#{name}"
114
134
  end
@@ -16,7 +16,7 @@ class Redis
16
16
 
17
17
  # How to add values using a sorted set. The key is the member, eg,
18
18
  # "Peter", and the value is the score, eg, 163. So:
19
- # num_posts['Peter'] = 163
19
+ # num_posts['Peter'] = 163
20
20
  def []=(member, score)
21
21
  add(member, score)
22
22
  end
@@ -77,11 +77,7 @@ class Redis
77
77
  def range(start_index, end_index, options={})
78
78
  if options[:withscores] || options[:with_scores]
79
79
  val = from_redis redis.zrange(key, start_index, end_index, :with_scores => true)
80
- ret = []
81
- while k = val.shift and v = val.shift
82
- ret << [k, v.to_f]
83
- end
84
- ret
80
+ group_set_with_scores(val)
85
81
  else
86
82
  from_redis redis.zrange(key, start_index, end_index)
87
83
  end
@@ -91,11 +87,7 @@ class Redis
91
87
  def revrange(start_index, end_index, options={})
92
88
  if options[:withscores] || options[:with_scores]
93
89
  val = from_redis redis.zrevrange(key, start_index, end_index, :with_scores => true)
94
- ret = []
95
- while k = val.shift and v = val.shift
96
- ret << [k, v.to_f]
97
- end
98
- ret
90
+ group_set_with_scores(val)
99
91
  else
100
92
  from_redis redis.zrevrange(key, start_index, end_index)
101
93
  end
@@ -111,7 +103,13 @@ class Redis
111
103
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
112
104
  options[:offset] || options[:limit] || options[:count]
113
105
  args[:with_scores] = true if options[:withscores] || options[:with_scores]
114
- from_redis redis.zrangebyscore(key, min, max, args)
106
+
107
+ if args[:with_scores]
108
+ val = from_redis redis.zrangebyscore(key, min, max, args)
109
+ group_set_with_scores(val)
110
+ else
111
+ from_redis redis.zrangebyscore(key, min, max, args)
112
+ end
115
113
  end
116
114
 
117
115
  # Forwards compat (not yet implemented in Redis)
@@ -120,13 +118,19 @@ class Redis
120
118
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
121
119
  options[:offset] || options[:limit] || options[:count]
122
120
  args[:with_scores] = true if options[:withscores] || options[:with_scores]
123
- from_redis redis.zrevrangebyscore(key, min, max, args)
121
+
122
+ if args[:with_scores]
123
+ val = from_redis redis.zrevrangebyscore(key, min, max, args)
124
+ group_set_with_scores(val)
125
+ else
126
+ from_redis redis.zrevrangebyscore(key, min, max, args)
127
+ end
124
128
  end
125
129
 
126
130
  # Remove all elements in the sorted set at key with rank between start and end. Start and end are
127
131
  # 0-based with rank 0 being the element with the lowest score. Both start and end can be negative
128
132
  # numbers, where they indicate offsets starting at the element with the highest rank. For example:
129
- # -1 is the element with the highest score, -2 the element with the second highest score and so forth.
133
+ # -1 is the element with the highest score, -2 the element with the second highest score and so forth.
130
134
  # Redis: ZREMRANGEBYRANK
131
135
  def remrangebyrank(min, max)
132
136
  redis.zremrangebyrank(key, min, max)
@@ -163,7 +167,7 @@ class Redis
163
167
  alias_method :incr, :increment
164
168
  alias_method :incrby, :increment
165
169
 
166
- # Convenience to calling increment() with a negative number.
170
+ # Convenience to calling increment() with a negative number.
167
171
  def decrement(by=1)
168
172
  redis.zincrby(key, -by).to_i
169
173
  end
@@ -187,7 +191,7 @@ class Redis
187
191
  alias_method :intersect, :intersection
188
192
  alias_method :inter, :intersection
189
193
  alias_method :&, :intersection
190
-
194
+
191
195
  # Calculate the intersection and store it in Redis as +name+. Returns the number
192
196
  # of elements in the stored intersection. Redis: SUNIONSTORE
193
197
  def interstore(name, *sets)
@@ -250,7 +254,7 @@ class Redis
250
254
  def ==(x)
251
255
  members == x
252
256
  end
253
-
257
+
254
258
  def to_s
255
259
  members.join(', ')
256
260
  end
@@ -270,19 +274,31 @@ class Redis
270
274
  def last
271
275
  at(-1)
272
276
  end
273
-
277
+
274
278
  # The number of members in the set. Aliased as size. Redis: ZCARD
275
279
  def length
276
280
  redis.zcard(key)
277
281
  end
278
282
  alias_method :size, :length
283
+
284
+ # The number of members within a range of scores. Redis: ZCOUNT
285
+ def range_size(min, max)
286
+ redis.zcount(key, min, max)
287
+ end
279
288
 
280
289
  private
281
-
290
+
282
291
  def keys_from_objects(sets)
283
292
  raise ArgumentError, "Must pass in one or more set names" if sets.empty?
284
293
  sets.collect{|set| set.is_a?(Redis::SortedSet) ? set.key : set}
285
294
  end
286
-
295
+
296
+ def group_set_with_scores(set_with_scores)
297
+ ret = []
298
+ while k = set_with_scores.shift and v = set_with_scores.shift
299
+ ret << [k, v.to_f]
300
+ end
301
+ ret
302
+ end
287
303
  end
288
304
  end
data/lib/redis/value.rb CHANGED
@@ -27,8 +27,6 @@ class Redis
27
27
  alias_method :get, :value
28
28
 
29
29
  def to_s; value.to_s; end
30
- alias_method :to_str, :to_s
31
-
32
30
  def ==(x); value == x; end
33
31
  def nil?; value.nil?; end
34
32
  end