redis-objects 0.4.0 → 0.4.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/.gitignore +2 -0
- data/CHANGELOG.rdoc +10 -0
- data/Rakefile +57 -4
- data/VERSION +1 -0
- data/lib/redis/hash.rb +6 -6
- data/lib/redis/objects.rb +20 -11
- data/lib/redis/objects/counters.rb +8 -7
- data/lib/redis/objects/hashes.rb +3 -2
- data/lib/redis/objects/lists.rb +3 -2
- data/lib/redis/objects/locks.rb +5 -4
- data/lib/redis/objects/sets.rb +3 -2
- data/lib/redis/objects/sorted_sets.rb +3 -2
- data/lib/redis/objects/values.rb +3 -2
- data/lib/redis/set.rb +2 -2
- data/lib/redis/sorted_set.rb +2 -2
- data/spec/redis_objects_instance_spec.rb +5 -53
- data/spec/redis_objects_model_spec.rb +58 -0
- data/spec/spec_helper.rb +2 -1
- metadata +41 -19
data/.gitignore
ADDED
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
= Changelog for Redis::Objects
|
2
2
|
|
3
|
+
== 0.4.1 [Final] (23 August 2010)
|
4
|
+
|
5
|
+
* Fixes for Ruby 1.8 failures due to missing flatten() [Gabe da Silveira]
|
6
|
+
|
7
|
+
* Enable subclasses of classes mixing in Redis::Objects to automatically pick up objects from their superclasses [Gabe da Silveira]
|
8
|
+
|
9
|
+
* Renamed prefix() and field_key() to redis_prefix() and redis_field_key() to prevent gem conflicts [Jason Meinzer]
|
10
|
+
|
11
|
+
* Fixed a typo in delete_if and added missing test coverage [Julio Capote, Nate Wiger]
|
12
|
+
|
3
13
|
== 0.4.0 [Final] (11 August 2010)
|
4
14
|
|
5
15
|
* Full support for redis hashes via new Redis::Hash class [Julio Capote, Nate Wiger]
|
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.0.4 or greater'
|
15
|
+
gem.add_dependency('redis', '>= 2.0.4')
|
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
|
-
|
4
|
-
|
5
|
-
|
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
|
-
|
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.4.1
|
data/lib/redis/hash.rb
CHANGED
@@ -11,7 +11,7 @@ class Redis
|
|
11
11
|
include Redis::Helpers::Serialize
|
12
12
|
|
13
13
|
attr_reader :key, :redis
|
14
|
-
|
14
|
+
|
15
15
|
# Needed since Redis::Hash masks bare Hash in redis.rb
|
16
16
|
def self.[](*args)
|
17
17
|
::Hash[*args]
|
@@ -71,7 +71,7 @@ class Redis
|
|
71
71
|
def each(&block)
|
72
72
|
all.each(&block)
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
# Enumerate through each keys. Redis: HKEYS
|
76
76
|
def each_key(&block)
|
77
77
|
keys.each(&block)
|
@@ -102,9 +102,9 @@ class Redis
|
|
102
102
|
# Set keys in bulk, takes a hash of field/values {'field1' => 'val1'}. Redis: HMSET
|
103
103
|
def bulk_set(*args)
|
104
104
|
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.
|
105
|
+
redis.hmset(key, *args.last.inject([]){ |arr,kv| arr + kv })
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
# Get keys in bulk, takes an array of fields as arguments. Redis: HMGET
|
109
109
|
def bulk_get(*fields)
|
110
110
|
hsh = {}
|
@@ -114,12 +114,12 @@ class Redis
|
|
114
114
|
end
|
115
115
|
hsh
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
# Increment value by integer at field. Redis: HINCRBY
|
119
119
|
def incrby(field, val = 1)
|
120
120
|
redis.hincrby(key, field, val).to_i
|
121
121
|
end
|
122
|
-
alias_method :incr, :incrby
|
122
|
+
alias_method :incr, :incrby
|
123
123
|
|
124
124
|
end
|
125
125
|
end
|
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
|
80
|
-
def
|
81
|
-
def
|
82
|
-
@
|
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
|
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
|
-
|
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
|
99
|
-
|
100
|
-
if 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
|
104
|
-
"#{
|
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
|
@@ -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(
|
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(
|
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(
|
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(
|
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(
|
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,7 +74,7 @@ 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(
|
77
|
+
redis.set(redis_field_key(name, id), to.to_i)
|
77
78
|
true
|
78
79
|
end
|
79
80
|
|
@@ -87,7 +88,7 @@ class Redis
|
|
87
88
|
end
|
88
89
|
|
89
90
|
def initialize_counter!(name, id) #:nodoc:
|
90
|
-
key =
|
91
|
+
key = redis_field_key(name, id)
|
91
92
|
unless @initialized_counters[key]
|
92
93
|
redis.setnx(key, @redis_objects[name][:start])
|
93
94
|
end
|
data/lib/redis/objects/hashes.rb
CHANGED
@@ -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(
|
22
|
+
@#{name} ||= Redis::Hash.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(
|
33
|
+
@#{name} ||= Redis::Hash.new(redis_field_key(:#{name}), #{klass_name}.redis, #{klass_name}.redis_objects[:#{name}])
|
33
34
|
end
|
34
35
|
EndMethods
|
35
36
|
end
|
data/lib/redis/objects/lists.rb
CHANGED
@@ -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(
|
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(
|
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
|
data/lib/redis/objects/locks.rb
CHANGED
@@ -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(
|
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(
|
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(
|
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(
|
56
|
+
redis.del(redis_field_key("#{name}_lock", id))
|
56
57
|
end
|
57
58
|
|
58
59
|
private
|
data/lib/redis/objects/sets.rb
CHANGED
@@ -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(
|
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(
|
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(
|
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(
|
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
|
data/lib/redis/objects/values.rb
CHANGED
@@ -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(
|
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(
|
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/set.rb
CHANGED
@@ -45,10 +45,10 @@ class Redis
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# Delete if matches block
|
48
|
-
def delete_if(&
|
48
|
+
def delete_if(&block)
|
49
49
|
res = false
|
50
50
|
redis.smembers(key).each do |m|
|
51
|
-
if
|
51
|
+
if block.call(from_redis(m))
|
52
52
|
res = redis.srem(key, m)
|
53
53
|
end
|
54
54
|
end
|
data/lib/redis/sorted_set.rb
CHANGED
@@ -144,10 +144,10 @@ class Redis
|
|
144
144
|
end
|
145
145
|
|
146
146
|
# Delete element if it matches block
|
147
|
-
def delete_if(&
|
147
|
+
def delete_if(&block)
|
148
148
|
raise ArgumentError, "Missing block to SortedSet#delete_if" unless block_given?
|
149
149
|
res = false
|
150
|
-
redis.
|
150
|
+
redis.zrange(key, 0, -1).each do |m|
|
151
151
|
if block.call(from_redis(m))
|
152
152
|
res = redis.zrem(key, m)
|
153
153
|
end
|
@@ -501,6 +501,8 @@ describe Redis::Set do
|
|
501
501
|
coll = @set.select{|st| st == 'c'}
|
502
502
|
coll.should == ['c']
|
503
503
|
@set.sort.should == ['a','b','c']
|
504
|
+
@set.delete_if{|m| m == 'c'}
|
505
|
+
@set.sort.should == ['a','b']
|
504
506
|
end
|
505
507
|
|
506
508
|
it "should handle set intersections, unions, and diffs" do
|
@@ -654,61 +656,11 @@ describe Redis::SortedSet do
|
|
654
656
|
@set.delete('c')
|
655
657
|
@set.length.should == 4
|
656
658
|
@set.size.should == 4
|
659
|
+
|
660
|
+
@set.delete_if{|m| m == 'b'}
|
661
|
+
@set.size.should == 3
|
657
662
|
end
|
658
663
|
|
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
664
|
it "should support renaming sets" do
|
713
665
|
@set.should.be.empty
|
714
666
|
@set['zynga'] = 151
|
@@ -35,6 +35,18 @@ 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
|
+
|
38
50
|
describe Redis::Objects do
|
39
51
|
before do
|
40
52
|
@roster = Roster.new
|
@@ -44,6 +56,9 @@ describe Redis::Objects do
|
|
44
56
|
@roster_2 = Roster.new(2)
|
45
57
|
@roster_3 = Roster.new(3)
|
46
58
|
|
59
|
+
@vanilla_roster = VanillaRoster.new
|
60
|
+
@custom_roster = CustomRoster.new
|
61
|
+
|
47
62
|
@roster.available_slots.reset
|
48
63
|
@roster.pitchers.reset
|
49
64
|
@roster.basic.reset
|
@@ -69,6 +84,9 @@ describe Redis::Objects do
|
|
69
84
|
@roster.all_player_stats.clear
|
70
85
|
@roster.total_wins.clear
|
71
86
|
@roster.my_rank.clear
|
87
|
+
|
88
|
+
@custom_roster.basic.reset
|
89
|
+
@custom_roster.special.reset
|
72
90
|
end
|
73
91
|
|
74
92
|
it "should provide a connection method" do
|
@@ -690,4 +708,44 @@ describe Redis::Objects do
|
|
690
708
|
error.should.not.be.nil
|
691
709
|
error.should.be.kind_of(Redis::Lock::LockTimeout)
|
692
710
|
end
|
711
|
+
|
712
|
+
it "should pick up objects from superclass automatically" do
|
713
|
+
@vanilla_roster.available_slots.should.be.kind_of(Redis::Counter)
|
714
|
+
@vanilla_roster.pitchers.should.be.kind_of(Redis::Counter)
|
715
|
+
@vanilla_roster.basic.should.be.kind_of(Redis::Counter)
|
716
|
+
@vanilla_roster.resort_lock.should.be.kind_of(Redis::Lock)
|
717
|
+
@vanilla_roster.starting_pitcher.should.be.kind_of(Redis::Value)
|
718
|
+
@vanilla_roster.player_stats.should.be.kind_of(Redis::List)
|
719
|
+
@vanilla_roster.outfielders.should.be.kind_of(Redis::Set)
|
720
|
+
@vanilla_roster.rank.should.be.kind_of(Redis::SortedSet)
|
721
|
+
|
722
|
+
# custom keys
|
723
|
+
@vanilla_roster.player_totals.should.be.kind_of(Redis::Counter)
|
724
|
+
@vanilla_roster.all_player_stats.should.be.kind_of(Redis::List)
|
725
|
+
@vanilla_roster.total_wins.should.be.kind_of(Redis::Set)
|
726
|
+
@vanilla_roster.my_rank.should.be.kind_of(Redis::Value)
|
727
|
+
@vanilla_roster.weird_key.should.be.kind_of(Redis::Value)
|
728
|
+
|
729
|
+
# globals via class
|
730
|
+
@vanilla_roster.total_players_online.should.be.kind_of(Redis::Counter)
|
731
|
+
@vanilla_roster.all_player_stats.should.be.kind_of(Redis::List)
|
732
|
+
@vanilla_roster.all_players_online.should.be.kind_of(Redis::Set)
|
733
|
+
@vanilla_roster.last_player.should.be.kind_of(Redis::Value)
|
734
|
+
|
735
|
+
VanillaRoster.total_players_online.should.be.kind_of(Redis::Counter)
|
736
|
+
VanillaRoster.all_player_stats.should.be.kind_of(Redis::List)
|
737
|
+
VanillaRoster.all_players_online.should.be.kind_of(Redis::Set)
|
738
|
+
VanillaRoster.last_player.should.be.kind_of(Redis::Value)
|
739
|
+
end
|
740
|
+
|
741
|
+
it "should allow subclass overrides of the same redis object" do
|
742
|
+
@roster.basic.should == 0
|
743
|
+
@custom_roster.basic.increment.should == 1
|
744
|
+
@roster2.basic.should == 0
|
745
|
+
CustomRoster.new.basic.should == 1
|
746
|
+
end
|
747
|
+
|
748
|
+
it "should handle new subclass objects" do
|
749
|
+
@custom_roster.special.increment.should == 1
|
750
|
+
end
|
693
751
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-objects
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 13
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 4
|
8
|
-
-
|
9
|
-
version: 0.4.
|
9
|
+
- 1
|
10
|
+
version: 0.4.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Nate Wiger
|
@@ -14,23 +15,39 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-23 00:00:00 -07:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
+
name: bacon
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: redis
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
24
40
|
requirements:
|
25
41
|
- - ">="
|
26
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 7
|
27
44
|
segments:
|
28
45
|
- 2
|
29
46
|
- 0
|
30
47
|
- 4
|
31
48
|
version: 2.0.4
|
32
49
|
type: :runtime
|
33
|
-
version_requirements: *
|
50
|
+
version_requirements: *id002
|
34
51
|
description: Map Redis types directly to Ruby objects. Works with any class or ORM.
|
35
52
|
email: nate@wiger.org
|
36
53
|
executables: []
|
@@ -38,11 +55,14 @@ executables: []
|
|
38
55
|
extensions: []
|
39
56
|
|
40
57
|
extra_rdoc_files:
|
58
|
+
- README.rdoc
|
59
|
+
files:
|
60
|
+
- .gitignore
|
41
61
|
- ATOMICITY.rdoc
|
42
62
|
- CHANGELOG.rdoc
|
43
|
-
- Rakefile
|
44
63
|
- README.rdoc
|
45
|
-
|
64
|
+
- Rakefile
|
65
|
+
- VERSION
|
46
66
|
- lib/redis/base_object.rb
|
47
67
|
- lib/redis/counter.rb
|
48
68
|
- lib/redis/hash.rb
|
@@ -50,6 +70,7 @@ files:
|
|
50
70
|
- lib/redis/helpers/serialize.rb
|
51
71
|
- lib/redis/list.rb
|
52
72
|
- lib/redis/lock.rb
|
73
|
+
- lib/redis/objects.rb
|
53
74
|
- lib/redis/objects/counters.rb
|
54
75
|
- lib/redis/objects/hashes.rb
|
55
76
|
- lib/redis/objects/lists.rb
|
@@ -57,47 +78,48 @@ files:
|
|
57
78
|
- lib/redis/objects/sets.rb
|
58
79
|
- lib/redis/objects/sorted_sets.rb
|
59
80
|
- lib/redis/objects/values.rb
|
60
|
-
- lib/redis/objects.rb
|
61
81
|
- lib/redis/set.rb
|
62
82
|
- lib/redis/sorted_set.rb
|
63
83
|
- lib/redis/value.rb
|
84
|
+
- redis-objects.gemspec
|
64
85
|
- spec/redis_objects_instance_spec.rb
|
65
86
|
- spec/redis_objects_model_spec.rb
|
66
87
|
- spec/spec_helper.rb
|
67
|
-
- ATOMICITY.rdoc
|
68
|
-
- CHANGELOG.rdoc
|
69
|
-
- Rakefile
|
70
|
-
- README.rdoc
|
71
88
|
has_rdoc: true
|
72
89
|
homepage: http://github.com/nateware/redis-objects
|
73
90
|
licenses: []
|
74
91
|
|
75
92
|
post_install_message:
|
76
93
|
rdoc_options:
|
77
|
-
- --
|
78
|
-
- Redis::Objects -- Use Redis types as Ruby objects
|
94
|
+
- --charset=UTF-8
|
79
95
|
require_paths:
|
80
96
|
- lib
|
81
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
82
99
|
requirements:
|
83
100
|
- - ">="
|
84
101
|
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
85
103
|
segments:
|
86
104
|
- 0
|
87
105
|
version: "0"
|
88
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
89
108
|
requirements:
|
90
109
|
- - ">="
|
91
110
|
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
92
112
|
segments:
|
93
113
|
- 0
|
94
114
|
version: "0"
|
95
115
|
requirements:
|
96
116
|
- redis, v2.0.4 or greater
|
97
|
-
rubyforge_project:
|
98
|
-
rubygems_version: 1.3.
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.3.7
|
99
119
|
signing_key:
|
100
120
|
specification_version: 3
|
101
|
-
summary:
|
102
|
-
test_files:
|
103
|
-
|
121
|
+
summary: Map Redis types directly to Ruby objects
|
122
|
+
test_files:
|
123
|
+
- spec/redis_objects_instance_spec.rb
|
124
|
+
- spec/redis_objects_model_spec.rb
|
125
|
+
- spec/spec_helper.rb
|