redis-objects 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|