redis-objects 0.4.0 → 0.5.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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gemspec
2
+ nbproject
3
+ pkg/
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,29 @@
1
1
  = Changelog for Redis::Objects
2
2
 
3
+ == 0.5.0 [Final] (8 November 2010)
4
+
5
+ * Incompatible change: Had to rename Redis::Hash to Redis::HashKey due to internal conflicts with Redis lib and Ruby [Nate Wiger]
6
+
7
+ * Fixed AR counter override so that Redis::Objects doesn't hide AR counters [Mattias Pfeiffer]
8
+
9
+ * Fixed delete problem with Redis::List and complex values [Esdras Mayrink]
10
+
11
+ * Fix Redis::HashKey to support complex (marshaled) types [Mattias Pfeiffer]
12
+
13
+ * Group results of SortedSet#rangebyscore and #revrangebyscore if :withscores option is passed [Szymon Nowak]
14
+
15
+ * Updated Redis DEL semantics per API change [Gabe da Silveira]
16
+
17
+ == 0.4.1 [Final] (23 August 2010)
18
+
19
+ * Fixes for Ruby 1.8 failures due to missing flatten() [Gabe da Silveira]
20
+
21
+ * Enable subclasses of classes mixing in Redis::Objects to automatically pick up objects from their superclasses [Gabe da Silveira]
22
+
23
+ * Renamed prefix() and field_key() to redis_prefix() and redis_field_key() to prevent gem conflicts [Jason Meinzer]
24
+
25
+ * Fixed a typo in delete_if and added missing test coverage [Julio Capote, Nate Wiger]
26
+
3
27
  == 0.4.0 [Final] (11 August 2010)
4
28
 
5
29
  * Full support for redis hashes via new Redis::Hash class [Julio Capote, Nate Wiger]
data/README.rdoc CHANGED
@@ -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.
@@ -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|
data/Rakefile CHANGED
@@ -1,7 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "redis-objects"
8
+ gem.summary = %Q{Map Redis types directly to Ruby objects}
9
+ gem.description = %Q{Map Redis types directly to Ruby objects. Works with any class or ORM.}
10
+ gem.email = "nate@wiger.org"
11
+ gem.homepage = "http://github.com/nateware/redis-objects"
12
+ gem.authors = ["Nate Wiger"]
13
+ gem.add_development_dependency "bacon", ">= 0"
14
+ gem.requirements << 'redis, v2.1.1 or greater'
15
+ gem.add_dependency('redis', '>= 2.1.1') # ALSO: update spec/spec_helper.rb
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ # require 'rake/testtask'
24
+ # Rake::TestTask.new(:spec) do |spec|
25
+ # spec.libs << 'lib' << 'spec'
26
+ # spec.pattern = 'spec/**/*_spec.rb'
27
+ # spec.verbose = true
28
+ # end
1
29
 
2
30
  task :test do
3
- base = File.dirname(__FILE__)
4
- Dir[base + '/spec/*_spec.rb'].each do |f|
5
- sh "ruby #{f}"
31
+ sh "bacon spec/*_spec.rb"
32
+ end
33
+
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |spec|
38
+ spec.libs << 'spec'
39
+ spec.pattern = 'spec/**/*_spec.rb'
40
+ spec.verbose = true
6
41
  end
7
- end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+ task :spec => :check_dependencies
49
+
50
+ task :default => :spec
51
+
52
+ require 'rake/rdoctask'
53
+ Rake::RDocTask.new do |rdoc|
54
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "Redis::Objects #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -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
6
+ @options = args.last.is_a?(Hash) ? args.pop : {}
7
7
  @redis = args.first || $redis
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
 
@@ -2,7 +2,7 @@ class Redis
2
2
  #
3
3
  # Class representing a Redis hash.
4
4
  #
5
- class Hash < BaseObject
5
+ class HashKey < BaseObject
6
6
  require 'enumerator'
7
7
  include Enumerable
8
8
  require 'redis/helpers/core_commands'
@@ -10,16 +10,11 @@ class Redis
10
10
  require 'redis/helpers/serialize'
11
11
  include Redis::Helpers::Serialize
12
12
 
13
- attr_reader :key, :redis
14
-
15
- # Needed since Redis::Hash masks bare Hash in redis.rb
16
- def self.[](*args)
17
- ::Hash[*args]
18
- end
13
+ attr_reader :key, :options, :redis
19
14
 
20
15
  # Sets a field to value
21
16
  def []=(field, value)
22
- store(field, value)
17
+ store(field, to_redis(value))
23
18
  end
24
19
 
25
20
  # Gets the value of a field
@@ -29,12 +24,12 @@ class Redis
29
24
 
30
25
  # Redis: HSET
31
26
  def store(field, value)
32
- redis.hset(key, field, value)
27
+ redis.hset(key, field, to_redis(value))
33
28
  end
34
29
 
35
30
  # Redis: HGET
36
31
  def fetch(field)
37
- redis.hget(key, field)
32
+ from_redis redis.hget(key, field)
38
33
  end
39
34
 
40
35
  # Verify that a field exists. Redis: HEXISTS
@@ -57,13 +52,13 @@ class Redis
57
52
 
58
53
  # Return all the values of the hash. Redis: HVALS
59
54
  def values
60
- redis.hvals(key)
55
+ from_redis redis.hvals(key)
61
56
  end
62
57
  alias_method :vals, :values
63
58
 
64
59
  # Retrieve the entire hash. Redis: HGETALL
65
60
  def all
66
- redis.hgetall(key)
61
+ from_redis redis.hgetall(key)
67
62
  end
68
63
  alias_method :clone, :all
69
64
 
@@ -71,7 +66,7 @@ class Redis
71
66
  def each(&block)
72
67
  all.each(&block)
73
68
  end
74
-
69
+
75
70
  # Enumerate through each keys. Redis: HKEYS
76
71
  def each_key(&block)
77
72
  keys.each(&block)
@@ -102,24 +97,24 @@ class Redis
102
97
  # Set keys in bulk, takes a hash of field/values {'field1' => 'val1'}. Redis: HMSET
103
98
  def bulk_set(*args)
104
99
  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.flatten)
100
+ redis.hmset(key, *args.last.inject([]){ |arr,kv| arr + [kv[0], to_redis(kv[1])] })
106
101
  end
107
-
102
+
108
103
  # Get keys in bulk, takes an array of fields as arguments. Redis: HMGET
109
104
  def bulk_get(*fields)
110
105
  hsh = {}
111
106
  res = redis.hmget(key, *fields.flatten)
112
107
  fields.each do |k|
113
- hsh[k] = res.shift
108
+ hsh[k] = from_redis(res.shift)
114
109
  end
115
110
  hsh
116
111
  end
117
-
112
+
118
113
  # Increment value by integer at field. Redis: HINCRBY
119
114
  def incrby(field, val = 1)
120
115
  redis.hincrby(key, field, val).to_i
121
116
  end
122
- alias_method :incr, :incrby
117
+ alias_method :incr, :incrby
123
118
 
124
119
  end
125
120
  end
@@ -18,6 +18,8 @@ class Redis
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
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,
@@ -23,10 +23,11 @@ class Redis
23
23
  options[:start] ||= 0
24
24
  options[:type] ||= options[:start] == 0 ? :increment : :decrement
25
25
  @redis_objects[name.to_sym] = options.merge(:type => :counter)
26
+ klass_name = '::' + self.name
26
27
  if options[:global]
27
28
  instance_eval <<-EndMethods
28
29
  def #{name}
29
- @#{name} ||= Redis::Counter.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
30
+ @#{name} ||= Redis::Counter.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
30
31
  end
31
32
  EndMethods
32
33
  class_eval <<-EndMethods
@@ -37,7 +38,7 @@ class Redis
37
38
  else
38
39
  class_eval <<-EndMethods
39
40
  def #{name}
40
- @#{name} ||= Redis::Counter.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
41
+ @#{name} ||= Redis::Counter.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
41
42
  end
42
43
  EndMethods
43
44
  end
@@ -48,7 +49,7 @@ class Redis
48
49
  def get_counter(name, id=nil)
49
50
  verify_counter_defined!(name, id)
50
51
  initialize_counter!(name, id)
51
- redis.get(field_key(name, id)).to_i
52
+ redis.get(redis_field_key(name, id)).to_i
52
53
  end
53
54
 
54
55
  # Increment a counter with the specified name and id. Accepts a block
@@ -56,7 +57,7 @@ class Redis
56
57
  def increment_counter(name, id=nil, by=1, &block)
57
58
  verify_counter_defined!(name, id)
58
59
  initialize_counter!(name, id)
59
- value = redis.incrby(field_key(name, id), by).to_i
60
+ value = redis.incrby(redis_field_key(name, id), by).to_i
60
61
  block_given? ? rewindable_block(:decrement_counter, name, id, value, &block) : value
61
62
  end
62
63
 
@@ -65,7 +66,7 @@ class Redis
65
66
  def decrement_counter(name, id=nil, by=1, &block)
66
67
  verify_counter_defined!(name, id)
67
68
  initialize_counter!(name, id)
68
- value = redis.decrby(field_key(name, id), by).to_i
69
+ value = redis.decrby(redis_field_key(name, id), by).to_i
69
70
  block_given? ? rewindable_block(:increment_counter, name, id, value, &block) : value
70
71
  end
71
72
 
@@ -73,21 +74,25 @@ class Redis
73
74
  def reset_counter(name, id=nil, to=nil)
74
75
  verify_counter_defined!(name, id)
75
76
  to = @redis_objects[name][:start] if to.nil?
76
- redis.set(field_key(name, id), to.to_i)
77
+ redis.set(redis_field_key(name, id), to.to_i)
77
78
  true
78
79
  end
79
80
 
80
81
  private
81
82
 
82
83
  def verify_counter_defined!(name, id) #:nodoc:
83
- raise Redis::Objects::UndefinedCounter, "Undefined counter :#{name} for class #{self.name}" unless @redis_objects.has_key?(name)
84
+ raise Redis::Objects::UndefinedCounter, "Undefined counter :#{name} for class #{self.name}" unless counter_defined?(name)
84
85
  if id.nil? and !@redis_objects[name][:global]
85
86
  raise Redis::Objects::MissingID, "Missing ID for non-global counter #{self.name}##{name}"
86
87
  end
87
88
  end
88
89
 
90
+ def counter_defined?(name) #:nodoc:
91
+ @redis_objects && @redis_objects.has_key?(name)
92
+ end
93
+
89
94
  def initialize_counter!(name, id) #:nodoc:
90
- key = field_key(name, id)
95
+ key = redis_field_key(name, id)
91
96
  unless @initialized_counters[key]
92
97
  redis.setnx(key, @redis_objects[name][:start])
93
98
  end
@@ -116,14 +121,22 @@ class Redis
116
121
  # It is more efficient to use increment_[counter_name] directly.
117
122
  # This is mainly just for completeness to override ActiveRecord.
118
123
  def increment(name, by=1)
119
- send(name).increment(by)
124
+ if self.class.send("counter_defined?", name)
125
+ send(name).increment(by)
126
+ else
127
+ super
128
+ end
120
129
  end
121
130
 
122
131
  # Decrement a counter.
123
132
  # It is more efficient to use increment_[counter_name] directly.
124
133
  # This is mainly just for completeness to override ActiveRecord.
125
134
  def decrement(name, by=1)
126
- send(name).decrement(by)
135
+ if self.class.send("counter_defined?", name)
136
+ send(name).decrement(by)
137
+ else
138
+ super
139
+ end
127
140
  end
128
141
  end
129
142
  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
@@ -15,10 +15,11 @@ class Redis
15
15
  # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
16
  def hash_key(name, options={})
17
17
  @redis_objects[name.to_sym] = options.merge(:type => :dict)
18
+ klass_name = '::' + self.name
18
19
  if options[:global]
19
20
  instance_eval <<-EndMethods
20
21
  def #{name}
21
- @#{name} ||= Redis::Hash.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
22
+ @#{name} ||= Redis::HashKey.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
23
  end
23
24
  EndMethods
24
25
  class_eval <<-EndMethods
@@ -29,7 +30,7 @@ class Redis
29
30
  else
30
31
  class_eval <<-EndMethods
31
32
  def #{name}
32
- @#{name} ||= Redis::Hash.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
33
+ @#{name} ||= Redis::HashKey.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
33
34
  end
34
35
  EndMethods
35
36
  end
@@ -15,10 +15,11 @@ class Redis
15
15
  # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
16
  def list(name, options={})
17
17
  @redis_objects[name.to_sym] = options.merge(:type => :list)
18
+ klass_name = '::' + self.name
18
19
  if options[:global]
19
20
  instance_eval <<-EndMethods
20
21
  def #{name}
21
- @#{name} ||= Redis::List.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
22
+ @#{name} ||= Redis::List.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
23
  end
23
24
  EndMethods
24
25
  class_eval <<-EndMethods
@@ -29,7 +30,7 @@ class Redis
29
30
  else
30
31
  class_eval <<-EndMethods
31
32
  def #{name}
32
- @#{name} ||= Redis::List.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
33
+ @#{name} ||= Redis::List.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
33
34
  end
34
35
  EndMethods
35
36
  end
@@ -18,10 +18,11 @@ class Redis
18
18
  options[:timeout] ||= 5 # seconds
19
19
  lock_name = "#{name}_lock"
20
20
  @redis_objects[lock_name.to_sym] = options.merge(:type => :lock)
21
+ klass_name = '::' + self.name
21
22
  if options[:global]
22
23
  instance_eval <<-EndMethods
23
24
  def #{lock_name}(&block)
24
- @#{lock_name} ||= Redis::Lock.new(field_key(:#{lock_name}), redis, @redis_objects[:#{lock_name}])
25
+ @#{lock_name} ||= Redis::Lock.new(redis_field_key(:#{lock_name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{lock_name}])
25
26
  end
26
27
  EndMethods
27
28
  class_eval <<-EndMethods
@@ -32,7 +33,7 @@ class Redis
32
33
  else
33
34
  class_eval <<-EndMethods
34
35
  def #{lock_name}(&block)
35
- @#{lock_name} ||= Redis::Lock.new(field_key(:#{lock_name}), redis, self.class.redis_objects[:#{lock_name}])
36
+ @#{lock_name} ||= Redis::Lock.new(redis_field_key(:#{lock_name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{lock_name}])
36
37
  end
37
38
  EndMethods
38
39
  end
@@ -45,14 +46,14 @@ class Redis
45
46
  verify_lock_defined!(name)
46
47
  raise ArgumentError, "Missing block to #{self.name}.obtain_lock" unless block_given?
47
48
  lock_name = "#{name}_lock"
48
- Redis::Lock.new(field_key(lock_name, id), redis, @redis_objects[lock_name.to_sym]).lock(&block)
49
+ Redis::Lock.new(redis_field_key(lock_name, id), redis, @redis_objects[lock_name.to_sym]).lock(&block)
49
50
  end
50
51
 
51
52
  # Clear the lock. Use with care - usually only in an Admin page to clear
52
53
  # stale locks (a stale lock should only happen if a server crashes.)
53
54
  def clear_lock(name, id)
54
55
  verify_lock_defined!(name)
55
- redis.del(field_key("#{name}_lock", id))
56
+ redis.del(redis_field_key("#{name}_lock", id))
56
57
  end
57
58
 
58
59
  private
@@ -15,10 +15,11 @@ class Redis
15
15
  # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
16
  def set(name, options={})
17
17
  @redis_objects[name.to_sym] = options.merge(:type => :set)
18
+ klass_name = '::' + self.name
18
19
  if options[:global]
19
20
  instance_eval <<-EndMethods
20
21
  def #{name}
21
- @#{name} ||= Redis::Set.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
22
+ @#{name} ||= Redis::Set.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
23
  end
23
24
  EndMethods
24
25
  class_eval <<-EndMethods
@@ -29,7 +30,7 @@ class Redis
29
30
  else
30
31
  class_eval <<-EndMethods
31
32
  def #{name}
32
- @#{name} ||= Redis::Set.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
33
+ @#{name} ||= Redis::Set.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
33
34
  end
34
35
  EndMethods
35
36
  end
@@ -15,10 +15,11 @@ class Redis
15
15
  # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
16
  def sorted_set(name, options={})
17
17
  @redis_objects[name.to_sym] = options.merge(:type => :sorted_set)
18
+ klass_name = '::' + self.name
18
19
  if options[:global]
19
20
  instance_eval <<-EndMethods
20
21
  def #{name}
21
- @#{name} ||= Redis::SortedSet.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
22
+ @#{name} ||= Redis::SortedSet.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
23
  end
23
24
  EndMethods
24
25
  class_eval <<-EndMethods
@@ -29,7 +30,7 @@ class Redis
29
30
  else
30
31
  class_eval <<-EndMethods
31
32
  def #{name}
32
- @#{name} ||= Redis::SortedSet.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
33
+ @#{name} ||= Redis::SortedSet.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
33
34
  end
34
35
  EndMethods
35
36
  end
@@ -15,10 +15,11 @@ class Redis
15
15
  # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
16
  def value(name, options={})
17
17
  @redis_objects[name.to_sym] = options.merge(:type => :value)
18
+ klass_name = '::' + self.name
18
19
  if options[:global]
19
20
  instance_eval <<-EndMethods
20
21
  def #{name}
21
- @#{name} ||= Redis::Value.new(field_key(:#{name}), redis, @redis_objects[:#{name}])
22
+ @#{name} ||= Redis::Value.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
22
23
  end
23
24
  def #{name}=(value)
24
25
  #{name}.value = value
@@ -35,7 +36,7 @@ class Redis
35
36
  else
36
37
  class_eval <<-EndMethods
37
38
  def #{name}
38
- @#{name} ||= Redis::Value.new(field_key(:#{name}), redis, self.class.redis_objects[:#{name}])
39
+ @#{name} ||= Redis::Value.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
39
40
  end
40
41
  def #{name}=(value)
41
42
  #{name}.value = value
data/lib/redis/objects.rb CHANGED
@@ -76,32 +76,41 @@ class Redis
76
76
  module ClassMethods
77
77
  attr_accessor :redis, :redis_objects
78
78
 
79
- # Set the Redis prefix to use. Defaults to model_name
80
- def prefix=(prefix) @prefix = prefix end
81
- def prefix #:nodoc:
82
- @prefix ||= self.name.to_s.
79
+ # Set the Redis redis_prefix to use. Defaults to model_name
80
+ def redis_prefix=(redis_prefix) @redis_prefix = redis_prefix end
81
+ def redis_prefix(klass = self) #:nodoc:
82
+ @redis_prefix ||= klass.name.to_s.
83
83
  sub(%r{(.*::)}, '').
84
84
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
85
85
  gsub(/([a-z\d])([A-Z])/,'\1_\2').
86
86
  downcase
87
87
  end
88
88
 
89
- def field_key(name, id='') #:nodoc:
89
+ def redis_field_key(name, id='') #:nodoc:
90
+ klass = first_ancestor_with(name)
90
91
  # This can never ever ever ever change or upgrades will corrupt all data
91
- @redis_objects[name.to_sym][:key] || "#{prefix}:#{id}:#{name}"
92
+ klass.redis_objects[name.to_sym][:key] || "#{redis_prefix(klass)}:#{id}:#{name}"
93
+ end
94
+
95
+ def first_ancestor_with(name)
96
+ if redis_objects && redis_objects.key?(name.to_sym)
97
+ self
98
+ elsif superclass && superclass.respond_to?(:redis_objects)
99
+ superclass.first_ancestor_with(name)
100
+ end
92
101
  end
93
102
  end
94
103
 
95
104
  # Instance methods that appear in your class when you include Redis::Objects.
96
105
  module InstanceMethods
97
106
  def redis() self.class.redis end
98
- def field_key(name) #:nodoc:
99
- # This can never ever ever ever change or upgrades will corrupt all data
100
- if key = self.class.redis_objects[name.to_sym][:key]
107
+ def redis_field_key(name) #:nodoc:
108
+ klass = self.class.first_ancestor_with(name)
109
+ if key = klass.redis_objects[name.to_sym][:key]
101
110
  eval "%(#{key})"
102
111
  else
103
- # don't try to refactor into class field_key because fucks up eval context
104
- "#{self.class.prefix}:#{id}:#{name}"
112
+ # don't try to refactor into class redis_field_key because fucks up eval context
113
+ "#{klass.redis_prefix}:#{id}:#{name}"
105
114
  end
106
115
  end
107
116
  end
data/lib/redis/set.rb CHANGED
@@ -45,10 +45,10 @@ class Redis
45
45
  end
46
46
 
47
47
  # Delete if matches block
48
- def delete_if(&blk)
48
+ def delete_if(&block)
49
49
  res = false
50
50
  redis.smembers(key).each do |m|
51
- if blk.call(from_redis(m))
51
+ if block.call(from_redis(m))
52
52
  res = redis.srem(key, m)
53
53
  end
54
54
  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)
@@ -144,10 +148,10 @@ class Redis
144
148
  end
145
149
 
146
150
  # Delete element if it matches block
147
- def delete_if(&blocK)
151
+ def delete_if(&block)
148
152
  raise ArgumentError, "Missing block to SortedSet#delete_if" unless block_given?
149
153
  res = false
150
- redis.zrevrange(key, 0, -1).each do |m|
154
+ redis.zrange(key, 0, -1).each do |m|
151
155
  if block.call(from_redis(m))
152
156
  res = redis.zrem(key, m)
153
157
  end
@@ -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,7 +274,7 @@ 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)
@@ -278,11 +282,18 @@ class Redis
278
282
  alias_method :size, :length
279
283
 
280
284
  private
281
-
285
+
282
286
  def keys_from_objects(sets)
283
287
  raise ArgumentError, "Must pass in one or more set names" if sets.empty?
284
288
  sets.collect{|set| set.is_a?(Redis::SortedSet) ? set.key : set}
285
289
  end
286
-
290
+
291
+ def group_set_with_scores(set_with_scores)
292
+ ret = []
293
+ while k = set_with_scores.shift and v = set_with_scores.shift
294
+ ret << [k, v.to_f]
295
+ end
296
+ ret
297
+ end
287
298
  end
288
299
  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
@@ -0,0 +1,78 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{redis-objects}
8
+ s.version = "0.5.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nate Wiger"]
12
+ s.date = %q{2010-11-08}
13
+ s.description = %q{Map Redis types directly to Ruby objects. Works with any class or ORM.}
14
+ s.email = %q{nate@wiger.org}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "ATOMICITY.rdoc",
21
+ "CHANGELOG.rdoc",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/redis/base_object.rb",
26
+ "lib/redis/counter.rb",
27
+ "lib/redis/hash_key.rb",
28
+ "lib/redis/helpers/core_commands.rb",
29
+ "lib/redis/helpers/serialize.rb",
30
+ "lib/redis/list.rb",
31
+ "lib/redis/lock.rb",
32
+ "lib/redis/objects.rb",
33
+ "lib/redis/objects/counters.rb",
34
+ "lib/redis/objects/hashes.rb",
35
+ "lib/redis/objects/lists.rb",
36
+ "lib/redis/objects/locks.rb",
37
+ "lib/redis/objects/sets.rb",
38
+ "lib/redis/objects/sorted_sets.rb",
39
+ "lib/redis/objects/values.rb",
40
+ "lib/redis/set.rb",
41
+ "lib/redis/sorted_set.rb",
42
+ "lib/redis/value.rb",
43
+ "redis-objects.gemspec",
44
+ "spec/redis_namespace_compat_spec.rb",
45
+ "spec/redis_objects_instance_spec.rb",
46
+ "spec/redis_objects_model_spec.rb",
47
+ "spec/spec_helper.rb"
48
+ ]
49
+ s.homepage = %q{http://github.com/nateware/redis-objects}
50
+ s.rdoc_options = ["--charset=UTF-8"]
51
+ s.require_paths = ["lib"]
52
+ s.requirements = ["redis, v2.1.1 or greater"]
53
+ s.rubygems_version = %q{1.3.7}
54
+ s.summary = %q{Map Redis types directly to Ruby objects}
55
+ s.test_files = [
56
+ "spec/redis_namespace_compat_spec.rb",
57
+ "spec/redis_objects_instance_spec.rb",
58
+ "spec/redis_objects_model_spec.rb",
59
+ "spec/spec_helper.rb"
60
+ ]
61
+
62
+ if s.respond_to? :specification_version then
63
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
64
+ s.specification_version = 3
65
+
66
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
67
+ s.add_development_dependency(%q<bacon>, [">= 0"])
68
+ s.add_runtime_dependency(%q<redis>, [">= 2.1.1"])
69
+ else
70
+ s.add_dependency(%q<bacon>, [">= 0"])
71
+ s.add_dependency(%q<redis>, [">= 2.1.1"])
72
+ end
73
+ else
74
+ s.add_dependency(%q<bacon>, [">= 0"])
75
+ s.add_dependency(%q<redis>, [">= 2.1.1"])
76
+ end
77
+ end
78
+
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'redis/objects'
4
+ Redis::Objects.redis = $redis
5
+
6
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../redis-namespace/lib')
7
+ require 'redis/namespace'
8
+
9
+ describe 'Redis::Namespace compat' do
10
+ it "tests the compatibility of Hash and ::Hash conflicts" do
11
+ ns = Redis::Namespace.new("resque", :redis => $redis)
12
+ ns.instance_eval { rem_namespace({"resque:x" => nil}) }.should == {"x"=>nil}
13
+ class Foo
14
+ include Redis::Objects
15
+ end
16
+ ns.instance_eval { rem_namespace({"resque:x" => nil}) }.should == {"x"=>nil}
17
+ end
18
+ end
@@ -7,7 +7,7 @@ require 'redis/value'
7
7
  require 'redis/lock'
8
8
  require 'redis/set'
9
9
  require 'redis/sorted_set'
10
- require 'redis/hash'
10
+ require 'redis/hash_key'
11
11
 
12
12
  describe Redis::Value do
13
13
  before do
@@ -20,7 +20,7 @@ describe Redis::Value do
20
20
  @value.value = 'Trevor Hoffman'
21
21
  @value.should == 'Trevor Hoffman'
22
22
  @value.get.should == 'Trevor Hoffman'
23
- @value.del.should.be.true
23
+ @value.del.should == 1
24
24
  @value.should.be.nil
25
25
  end
26
26
 
@@ -40,7 +40,7 @@ describe Redis::Value do
40
40
  @value.value = [[1,2], {:t3 => 4}]
41
41
  @value.should == [[1,2], {:t3 => 4}]
42
42
  @value.get.should == [[1,2], {:t3 => 4}]
43
- @value.del.should.be.true
43
+ @value.del.should == 1
44
44
  @value.should.be.nil
45
45
  @value.options[:marshal] = false
46
46
  end
@@ -197,6 +197,9 @@ describe Redis::List do
197
197
  @list << [1,2,3,[4,5]]
198
198
  @list.last.should == [1,2,3,[4,5]]
199
199
  @list.shift.should == {:json => 'data'}
200
+ @list.size.should == 2
201
+ @list.delete(v2)
202
+ @list.size.should == 1
200
203
  @list.options[:marshal] = false
201
204
  end
202
205
 
@@ -356,12 +359,50 @@ describe Redis::Lock do
356
359
  end
357
360
 
358
361
 
359
- describe Redis::Hash do
362
+ describe Redis::HashKey do
360
363
  before do
361
- @hash = Redis::Hash.new('test_hash')
364
+ @hash = Redis::HashKey.new('test_hash')
362
365
  @hash.clear
363
366
  end
364
367
 
368
+ it "should handle complex marshaled values" do
369
+ @hash.options[:marshal] = true
370
+ @hash['abc'].should == nil
371
+ @hash['abc'] = {:json => 'data'}
372
+ @hash['abc'].should == {:json => 'data'}
373
+
374
+ # no marshaling
375
+ @hash.options[:marshal] = false
376
+ v = {:json => 'data'}
377
+ @hash['abc'] = v
378
+ @hash['abc'].should == v.to_s
379
+
380
+ @hash.options[:marshal] = true
381
+ @hash['abc'] = [[1,2], {:t3 => 4}]
382
+ @hash['abc'].should == [[1,2], {:t3 => 4}]
383
+ @hash.fetch('abc').should == [[1,2], {:t3 => 4}]
384
+ @hash.delete('abc').should == 1
385
+ @hash.fetch('abc').should.be.nil
386
+
387
+ @hash.options[:marshal] = true
388
+ @hash.bulk_set('abc' => [[1,2], {:t3 => 4}], 'def' => [[6,8], {:t4 => 8}])
389
+ hsh = @hash.bulk_get('abc', 'def', 'foo')
390
+ hsh['abc'].should == [[1,2], {:t3 => 4}]
391
+ hsh['def'].should == [[6,8], {:t4 => 8}]
392
+ hsh['foo'].should.be.nil
393
+
394
+ hsh = @hash.all
395
+ hsh['abc'].should == [[1,2], {:t3 => 4}]
396
+ hsh['def'].should == [[6,8], {:t4 => 8}]
397
+
398
+ @hash.values.should == [[[1,2], {:t3 => 4}], [[6,8], {:t4 => 8}]]
399
+
400
+ @hash.delete('def').should == 1
401
+ @hash.delete('abc').should == 1
402
+
403
+ @hash.options[:marshal] = false
404
+ end
405
+
365
406
  it "should get and set values" do
366
407
  @hash['foo'] = 'bar'
367
408
  @hash['foo'].should == 'bar'
@@ -406,7 +447,7 @@ describe Redis::Hash do
406
447
  end
407
448
 
408
449
  it "should respond to empty?" do
409
- @empty = Redis::Hash.new('test_empty_hash')
450
+ @empty = Redis::HashKey.new('test_empty_hash')
410
451
  @empty.respond_to?(:empty?).should == true
411
452
  end
412
453
 
@@ -501,6 +542,8 @@ describe Redis::Set do
501
542
  coll = @set.select{|st| st == 'c'}
502
543
  coll.should == ['c']
503
544
  @set.sort.should == ['a','b','c']
545
+ @set.delete_if{|m| m == 'c'}
546
+ @set.sort.should == ['a','b']
504
547
  end
505
548
 
506
549
  it "should handle set intersections, unions, and diffs" do
@@ -654,61 +697,11 @@ describe Redis::SortedSet do
654
697
  @set.delete('c')
655
698
  @set.length.should == 4
656
699
  @set.size.should == 4
700
+
701
+ @set.delete_if{|m| m == 'b'}
702
+ @set.size.should == 3
657
703
  end
658
704
 
659
- =begin
660
-
661
- # Not until Redis 1.3.5 with hashes
662
- it "Redis 1.3.5: should handle set intersections, unions, and diffs" do
663
- @set_1['a'] = 5
664
- @set_2['b'] = 18
665
- @set_2['c'] = 12
666
-
667
- @set_2['a'] = 10
668
- @set_2['b'] = 15
669
- @set_2['c'] = 15
670
-
671
- (@set_1 & @set_2).sort.should == ['c','d','e']
672
-
673
- @set_1 << 'a' << 'b' << 'c' << 'd' << 'e'
674
- @set_2 << 'c' << 'd' << 'e' << 'f' << 'g'
675
- @set_3 << 'a' << 'd' << 'g' << 'l' << 'm'
676
- @set_1.sort.should == %w(a b c d e)
677
- @set_2.sort.should == %w(c d e f g)
678
- @set_3.sort.should == %w(a d g l m)
679
- (@set_1 & @set_2).sort.should == ['c','d','e']
680
- @set_1.intersection(@set_2).sort.should == ['c','d','e']
681
- @set_1.intersection(@set_2, @set_3).sort.should == ['d']
682
- @set_1.intersect(@set_2).sort.should == ['c','d','e']
683
- @set_1.inter(@set_2, @set_3).sort.should == ['d']
684
- @set_1.interstore(INTERSTORE_KEY, @set_2).should == 3
685
- @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['c','d','e']
686
- @set_1.interstore(INTERSTORE_KEY, @set_2, @set_3).should == 1
687
- @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['d']
688
-
689
- (@set_1 | @set_2).sort.should == ['a','b','c','d','e','f','g']
690
- (@set_1 + @set_2).sort.should == ['a','b','c','d','e','f','g']
691
- @set_1.union(@set_2).sort.should == ['a','b','c','d','e','f','g']
692
- @set_1.union(@set_2, @set_3).sort.should == ['a','b','c','d','e','f','g','l','m']
693
- @set_1.unionstore(UNIONSTORE_KEY, @set_2).should == 7
694
- @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g']
695
- @set_1.unionstore(UNIONSTORE_KEY, @set_2, @set_3).should == 9
696
- @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g','l','m']
697
-
698
- (@set_1 ^ @set_2).sort.should == ["a", "b"]
699
- (@set_1 - @set_2).sort.should == ["a", "b"]
700
- (@set_2 - @set_1).sort.should == ["f", "g"]
701
- @set_1.difference(@set_2).sort.should == ["a", "b"]
702
- @set_1.diff(@set_2).sort.should == ["a", "b"]
703
- @set_1.difference(@set_2, @set_3).sort.should == ['b']
704
- @set_1.diffstore(DIFFSTORE_KEY, @set_2).should == 2
705
- @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['a','b']
706
- @set_1.diffstore(DIFFSTORE_KEY, @set_2, @set_3).should == 1
707
- @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['b']
708
- end
709
-
710
- =end
711
-
712
705
  it "should support renaming sets" do
713
706
  @set.should.be.empty
714
707
  @set['zynga'] = 151
@@ -35,6 +35,33 @@ class Roster
35
35
  def max_pitchers; 3; end
36
36
  end
37
37
 
38
+ class VanillaRoster < Roster
39
+ # No explicit Redis::Objects
40
+ end
41
+
42
+ class CustomRoster < Roster
43
+ include Redis::Objects
44
+
45
+ counter :basic # Override
46
+ counter :special # New
47
+ end
48
+
49
+ class MethodRoster
50
+ def increment(attribute, by=1)
51
+ 42
52
+ end
53
+
54
+ def initialize(id=1) @id = id end
55
+ def id; @id; end
56
+ end
57
+
58
+ class CustomMethodRoster < MethodRoster
59
+ include Redis::Objects
60
+
61
+ attr_accessor :counter
62
+ counter :basic
63
+ end
64
+
38
65
  describe Redis::Objects do
39
66
  before do
40
67
  @roster = Roster.new
@@ -44,6 +71,9 @@ describe Redis::Objects do
44
71
  @roster_2 = Roster.new(2)
45
72
  @roster_3 = Roster.new(3)
46
73
 
74
+ @vanilla_roster = VanillaRoster.new
75
+ @custom_roster = CustomRoster.new
76
+
47
77
  @roster.available_slots.reset
48
78
  @roster.pitchers.reset
49
79
  @roster.basic.reset
@@ -69,6 +99,9 @@ describe Redis::Objects do
69
99
  @roster.all_player_stats.clear
70
100
  @roster.total_wins.clear
71
101
  @roster.my_rank.clear
102
+
103
+ @custom_roster.basic.reset
104
+ @custom_roster.special.reset
72
105
  end
73
106
 
74
107
  it "should provide a connection method" do
@@ -345,7 +378,7 @@ describe Redis::Objects do
345
378
  @roster.starting_pitcher.get.should == 'Trevor Hoffman'
346
379
  @roster.starting_pitcher = 'Tom Selleck'
347
380
  @roster.starting_pitcher.should == 'Tom Selleck'
348
- @roster.starting_pitcher.del.should.be.true
381
+ @roster.starting_pitcher.del.should == 1
349
382
  @roster.starting_pitcher.should.be.nil
350
383
  end
351
384
 
@@ -354,7 +387,7 @@ describe Redis::Objects do
354
387
  @roster.starting_pitcher = {:json => 'data'}
355
388
  @roster.starting_pitcher.should == {:json => 'data'}
356
389
  @roster.starting_pitcher.get.should == {:json => 'data'}
357
- @roster.starting_pitcher.del.should.be.true
390
+ @roster.starting_pitcher.del.should == 1
358
391
  @roster.starting_pitcher.should.be.nil
359
392
  end
360
393
 
@@ -612,7 +645,7 @@ describe Redis::Objects do
612
645
  Roster.last_player.get.should == 'Trevor Hoffman'
613
646
  Roster.last_player = 'Tom Selleck'
614
647
  Roster.last_player.should == 'Tom Selleck'
615
- Roster.last_player.del.should.be.true
648
+ Roster.last_player.del.should == 1
616
649
  Roster.last_player.should.be.nil
617
650
  end
618
651
 
@@ -646,7 +679,7 @@ describe Redis::Objects do
646
679
  @roster2.last_player.get.should == 'Trevor Hoffman'
647
680
  @roster2.last_player = 'Tom Selleck'
648
681
  @roster.last_player.should == 'Tom Selleck'
649
- @roster.last_player.del.should.be.true
682
+ @roster.last_player.del.should == 1
650
683
  @roster.last_player.should.be.nil
651
684
  @roster2.last_player.should.be.nil
652
685
  end
@@ -690,4 +723,54 @@ describe Redis::Objects do
690
723
  error.should.not.be.nil
691
724
  error.should.be.kind_of(Redis::Lock::LockTimeout)
692
725
  end
726
+
727
+ it "should pick up objects from superclass automatically" do
728
+ @vanilla_roster.available_slots.should.be.kind_of(Redis::Counter)
729
+ @vanilla_roster.pitchers.should.be.kind_of(Redis::Counter)
730
+ @vanilla_roster.basic.should.be.kind_of(Redis::Counter)
731
+ @vanilla_roster.resort_lock.should.be.kind_of(Redis::Lock)
732
+ @vanilla_roster.starting_pitcher.should.be.kind_of(Redis::Value)
733
+ @vanilla_roster.player_stats.should.be.kind_of(Redis::List)
734
+ @vanilla_roster.outfielders.should.be.kind_of(Redis::Set)
735
+ @vanilla_roster.rank.should.be.kind_of(Redis::SortedSet)
736
+
737
+ # custom keys
738
+ @vanilla_roster.player_totals.should.be.kind_of(Redis::Counter)
739
+ @vanilla_roster.all_player_stats.should.be.kind_of(Redis::List)
740
+ @vanilla_roster.total_wins.should.be.kind_of(Redis::Set)
741
+ @vanilla_roster.my_rank.should.be.kind_of(Redis::Value)
742
+ @vanilla_roster.weird_key.should.be.kind_of(Redis::Value)
743
+
744
+ # globals via class
745
+ @vanilla_roster.total_players_online.should.be.kind_of(Redis::Counter)
746
+ @vanilla_roster.all_player_stats.should.be.kind_of(Redis::List)
747
+ @vanilla_roster.all_players_online.should.be.kind_of(Redis::Set)
748
+ @vanilla_roster.last_player.should.be.kind_of(Redis::Value)
749
+
750
+ VanillaRoster.total_players_online.should.be.kind_of(Redis::Counter)
751
+ VanillaRoster.all_player_stats.should.be.kind_of(Redis::List)
752
+ VanillaRoster.all_players_online.should.be.kind_of(Redis::Set)
753
+ VanillaRoster.last_player.should.be.kind_of(Redis::Value)
754
+ end
755
+
756
+ it "should allow subclass overrides of the same redis object" do
757
+ @roster.basic.should == 0
758
+ @custom_roster.basic.increment.should == 1
759
+ @roster2.basic.should == 0
760
+ CustomRoster.new.basic.should == 1
761
+ end
762
+
763
+ it "should handle new subclass objects" do
764
+ @custom_roster.special.increment.should == 1
765
+ end
766
+
767
+ it "should allow passing of increment/decrement to super class" do
768
+ @custom_method_roster = CustomMethodRoster.new
769
+ @custom_method_roster.counter.should.be.nil
770
+
771
+ @custom_method_roster.increment(:counter).should == 42
772
+
773
+ @custom_method_roster.increment(:basic).should == 1
774
+ @custom_method_roster.basic.should.be.kind_of(Redis::Counter)
775
+ end
693
776
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,8 @@
1
- $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
1
+ require 'rubygems' # poor people still on 1.8
2
+ gem 'redis', '>= 2.1.1'
2
3
  require 'redis'
3
4
 
4
- require 'rubygems' # poor people still on 1.8
5
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
5
6
  require 'bacon'
6
7
  Bacon.summary_at_exit
7
8
 
@@ -10,3 +11,4 @@ $redis = Redis.new(:host => ENV['REDIS_HOST'], :port => ENV['REDIS_PORT'])
10
11
  UNIONSTORE_KEY = 'test:unionstore'
11
12
  INTERSTORE_KEY = 'test:interstore'
12
13
  DIFFSTORE_KEY = 'test:diffstore'
14
+
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
7
+ - 5
8
8
  - 0
9
- version: 0.4.0
9
+ version: 0.5.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Nate Wiger
@@ -14,23 +14,37 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-11 00:00:00 -07:00
17
+ date: 2010-11-08 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: redis
21
+ name: bacon
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ">="
26
27
  - !ruby/object:Gem::Version
27
28
  segments:
28
- - 2
29
29
  - 0
30
- - 4
31
- version: 2.0.4
32
- type: :runtime
30
+ version: "0"
31
+ type: :development
33
32
  version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: redis
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 1
44
+ - 1
45
+ version: 2.1.1
46
+ type: :runtime
47
+ version_requirements: *id002
34
48
  description: Map Redis types directly to Ruby objects. Works with any class or ORM.
35
49
  email: nate@wiger.org
36
50
  executables: []
@@ -38,18 +52,22 @@ executables: []
38
52
  extensions: []
39
53
 
40
54
  extra_rdoc_files:
55
+ - README.rdoc
56
+ files:
57
+ - .gitignore
41
58
  - ATOMICITY.rdoc
42
59
  - CHANGELOG.rdoc
43
- - Rakefile
44
60
  - README.rdoc
45
- files:
61
+ - Rakefile
62
+ - VERSION
46
63
  - lib/redis/base_object.rb
47
64
  - lib/redis/counter.rb
48
- - lib/redis/hash.rb
65
+ - lib/redis/hash_key.rb
49
66
  - lib/redis/helpers/core_commands.rb
50
67
  - lib/redis/helpers/serialize.rb
51
68
  - lib/redis/list.rb
52
69
  - lib/redis/lock.rb
70
+ - lib/redis/objects.rb
53
71
  - lib/redis/objects/counters.rb
54
72
  - lib/redis/objects/hashes.rb
55
73
  - lib/redis/objects/lists.rb
@@ -57,28 +75,25 @@ files:
57
75
  - lib/redis/objects/sets.rb
58
76
  - lib/redis/objects/sorted_sets.rb
59
77
  - lib/redis/objects/values.rb
60
- - lib/redis/objects.rb
61
78
  - lib/redis/set.rb
62
79
  - lib/redis/sorted_set.rb
63
80
  - lib/redis/value.rb
81
+ - redis-objects.gemspec
82
+ - spec/redis_namespace_compat_spec.rb
64
83
  - spec/redis_objects_instance_spec.rb
65
84
  - spec/redis_objects_model_spec.rb
66
85
  - spec/spec_helper.rb
67
- - ATOMICITY.rdoc
68
- - CHANGELOG.rdoc
69
- - Rakefile
70
- - README.rdoc
71
86
  has_rdoc: true
72
87
  homepage: http://github.com/nateware/redis-objects
73
88
  licenses: []
74
89
 
75
90
  post_install_message:
76
91
  rdoc_options:
77
- - --title
78
- - Redis::Objects -- Use Redis types as Ruby objects
92
+ - --charset=UTF-8
79
93
  require_paths:
80
94
  - lib
81
95
  required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
82
97
  requirements:
83
98
  - - ">="
84
99
  - !ruby/object:Gem::Version
@@ -86,6 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
101
  - 0
87
102
  version: "0"
88
103
  required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
89
105
  requirements:
90
106
  - - ">="
91
107
  - !ruby/object:Gem::Version
@@ -93,11 +109,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
109
  - 0
94
110
  version: "0"
95
111
  requirements:
96
- - redis, v2.0.4 or greater
97
- rubyforge_project: redis-objects
98
- rubygems_version: 1.3.6
112
+ - redis, v2.1.1 or greater
113
+ rubyforge_project:
114
+ rubygems_version: 1.3.7
99
115
  signing_key:
100
116
  specification_version: 3
101
- summary: Maps Redis types to Ruby objects
102
- test_files: []
103
-
117
+ summary: Map Redis types directly to Ruby objects
118
+ test_files:
119
+ - spec/redis_namespace_compat_spec.rb
120
+ - spec/redis_objects_instance_spec.rb
121
+ - spec/redis_objects_model_spec.rb
122
+ - spec/spec_helper.rb