redis-objects-legacy 1.6.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.
@@ -0,0 +1,155 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Counters"
2
+ # For the object itself, see "Redis::Counter"
3
+ require 'redis/counter'
4
+ class Redis
5
+ module Objects
6
+ class UndefinedCounter < StandardError; end #:nodoc:
7
+ class MissingID < StandardError; end #:nodoc:
8
+
9
+ module Counters
10
+ def self.included(klass)
11
+ klass.instance_variable_set('@initialized_counters', {})
12
+ klass.send :include, InstanceMethods
13
+ klass.extend ClassMethods
14
+ end
15
+
16
+ # Class methods that appear in your class when you include Redis::Objects.
17
+ module ClassMethods
18
+ attr_reader :initialized_counters
19
+
20
+ # Define a new counter. It will function like a regular instance
21
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
22
+ def counter(name, options={})
23
+ options[:start] ||= 0
24
+ options[:type] ||= options[:start] == 0 ? :increment : :decrement
25
+ redis_objects[name.to_sym] = options.merge(:type => :counter)
26
+ ivar_name = :"@#{name}"
27
+
28
+ mod = Module.new do
29
+ define_method(name) do
30
+ instance_variable_get(ivar_name) or
31
+ instance_variable_set(ivar_name,
32
+ Redis::Counter.new(
33
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
34
+ )
35
+ )
36
+ end
37
+ end
38
+
39
+ if options[:global]
40
+ extend mod
41
+
42
+ # dispatch to class methods
43
+ define_method(name) do
44
+ self.class.public_send(name)
45
+ end
46
+ else
47
+ include mod
48
+ end
49
+ end
50
+
51
+ # Get the current value of the counter. It is more efficient
52
+ # to use the instance method if possible.
53
+ def get_counter(name, id=nil)
54
+ verify_counter_defined!(name, id)
55
+ initialize_counter!(name, id)
56
+ redis.get(redis_field_key(name, id)).to_i
57
+ end
58
+
59
+ # Increment a counter with the specified name and id. Accepts a block
60
+ # like the instance method. See Redis::Objects::Counter for details.
61
+ def increment_counter(name, id=nil, by=1, &block)
62
+ name = name.to_sym
63
+ return super(name, id) unless counter_defined?(name)
64
+ verify_counter_defined!(name, id)
65
+ initialize_counter!(name, id)
66
+ value = redis.incrby(redis_field_key(name, id), by).to_i
67
+ block_given? ? rewindable_block(:decrement_counter, name, id, by, value, &block) : value
68
+ end
69
+
70
+ # Decrement a counter with the specified name and id. Accepts a block
71
+ # like the instance method. See Redis::Objects::Counter for details.
72
+ def decrement_counter(name, id=nil, by=1, &block)
73
+ name = name.to_sym
74
+ return super(name, id) unless counter_defined?(name)
75
+ verify_counter_defined!(name, id)
76
+ initialize_counter!(name, id)
77
+ value = redis.decrby(redis_field_key(name, id), by).to_i
78
+ block_given? ? rewindable_block(:increment_counter, name, id, by, value, &block) : value
79
+ end
80
+
81
+ # Reset a counter to its starting value.
82
+ def reset_counter(name, id=nil, to=nil)
83
+ verify_counter_defined!(name, id)
84
+ to = redis_objects[name][:start] if to.nil?
85
+ redis.set(redis_field_key(name, id), to.to_i)
86
+ true
87
+ end
88
+
89
+ # Set a counter to its starting value and return the old value.
90
+ def getset_counter(name, id=nil, to=nil)
91
+ verify_counter_defined!(name, id)
92
+ to = redis_objects[name][:start] if to.nil?
93
+ redis.getset(redis_field_key(name, id), to.to_i).to_i
94
+ end
95
+
96
+ def counter_defined?(name) #:nodoc:
97
+ redis_objects && redis_objects.has_key?(name.to_sym)
98
+ end
99
+
100
+ private
101
+
102
+ def verify_counter_defined!(name, id) #:nodoc:
103
+ raise NoMethodError, "Undefined counter :#{name} for class #{self.name}" unless counter_defined?(name)
104
+ if id.nil? and !redis_objects[name][:global]
105
+ raise Redis::Objects::MissingID, "Missing ID for non-global counter #{self.name}##{name}"
106
+ end
107
+ end
108
+
109
+ def initialize_counter!(name, id) #:nodoc:
110
+ key = redis_field_key(name, id)
111
+ unless @initialized_counters[key]
112
+ redis.setnx(key, redis_objects[name][:start])
113
+ end
114
+ @initialized_counters[key] = true
115
+ end
116
+
117
+ # Implements increment/decrement blocks on a class level
118
+ def rewindable_block(rewind, name, id, by, value, &block) #:nodoc:
119
+ # Unfortunately this is almost exactly duplicated from Redis::Counter
120
+ raise ArgumentError, "Missing block to rewindable_block somehow" unless block_given?
121
+ ret = nil
122
+ begin
123
+ ret = yield value
124
+ rescue
125
+ send(rewind, name, id, by)
126
+ raise
127
+ end
128
+ send(rewind, name, id, by) if ret.nil?
129
+ ret
130
+ end
131
+ end
132
+
133
+ # Instance methods that appear in your class when you include Redis::Objects.
134
+ module InstanceMethods
135
+ # Increment a counter. Called mainly in the context of :counter_cache
136
+ def increment(name, by=1)
137
+ if self.class.counter_defined?(name)
138
+ send(name).increment(by)
139
+ else
140
+ super # ActiveRecord
141
+ end
142
+ end
143
+
144
+ # Decrement a counter. Called mainly in the context of :counter_cache
145
+ def decrement(name, by=1)
146
+ if self.class.counter_defined?(name)
147
+ send(name).decrement(by)
148
+ else
149
+ super # ActiveRecord
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,60 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Hashes"
2
+ # For the object itself, see "Redis::Hash"
3
+ require 'redis/hash_key'
4
+ class Redis
5
+ module Objects
6
+ module Hashes
7
+ def self.included(klass)
8
+ klass.send :include, InstanceMethods
9
+ klass.extend ClassMethods
10
+ end
11
+
12
+ # Class methods that appear in your class when you include Redis::Objects.
13
+ module ClassMethods
14
+ # Define a new hash key. It will function like a regular instance
15
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
+ def hash_key(name, options={})
17
+ redis_objects[name.to_sym] = options.merge(:type => :dict)
18
+ ivar_name = :"@#{name}"
19
+
20
+ mod = Module.new do
21
+ define_method(name) do
22
+ instance_variable_get(ivar_name) or
23
+ instance_variable_set(ivar_name,
24
+ Redis::HashKey.new(
25
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
26
+ )
27
+ )
28
+ end
29
+
30
+ define_method(:"#{name}=") do |values|
31
+ hash_key = public_send(name)
32
+
33
+ redis.pipelined do
34
+ hash_key.clear
35
+ hash_key.bulk_set(values)
36
+ end
37
+ end
38
+ end
39
+
40
+ if options[:global]
41
+ extend mod
42
+
43
+ # dispatch to class methods
44
+ define_method(name) do
45
+ self.class.public_send(name)
46
+ end
47
+ else
48
+ include mod
49
+ end
50
+ end
51
+ end
52
+
53
+ # Instance methods that appear in your class when you include Redis::Objects.
54
+ module InstanceMethods
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+
@@ -0,0 +1,58 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Lists"
2
+ # For the object itself, see "Redis::List"
3
+ require 'redis/list'
4
+ class Redis
5
+ module Objects
6
+ module Lists
7
+ def self.included(klass)
8
+ klass.send :include, InstanceMethods
9
+ klass.extend ClassMethods
10
+ end
11
+
12
+ # Class methods that appear in your class when you include Redis::Objects.
13
+ module ClassMethods
14
+ # Define a new list. It will function like a regular instance
15
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
+ def list(name, options={})
17
+ redis_objects[name.to_sym] = options.merge(:type => :list)
18
+ ivar_name = :"@#{name}"
19
+
20
+ mod = Module.new do
21
+ define_method(name) do
22
+ instance_variable_get(ivar_name) or
23
+ instance_variable_set(ivar_name,
24
+ Redis::List.new(
25
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
26
+ )
27
+ )
28
+ end
29
+
30
+ define_method(:"#{name}=") do |values|
31
+ list = public_send(name)
32
+
33
+ redis.pipelined do
34
+ list.clear
35
+ list.push(*values)
36
+ end
37
+ end
38
+ end
39
+
40
+ if options[:global]
41
+ extend mod
42
+
43
+ # dispatch to class methods
44
+ define_method(name) do
45
+ self.class.public_send(name)
46
+ end
47
+ else
48
+ include mod
49
+ end
50
+ end
51
+ end
52
+
53
+ # Instance methods that appear in your class when you include Redis::Objects.
54
+ module InstanceMethods
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,73 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Locks"
2
+ # For the object itself, see "Redis::Lock"
3
+ require 'redis/lock'
4
+ class Redis
5
+ module Objects
6
+ class UndefinedLock < StandardError; end #:nodoc:
7
+ module Locks
8
+ def self.included(klass)
9
+ klass.send :include, InstanceMethods
10
+ klass.extend ClassMethods
11
+ end
12
+
13
+ # Class methods that appear in your class when you include Redis::Objects.
14
+ module ClassMethods
15
+ # Define a new lock. It will function like a model attribute,
16
+ # so it can be used alongside ActiveRecord/DataMapper, etc.
17
+ def lock(name, options={})
18
+ options[:timeout] ||= 5 # seconds
19
+ lock_name = "#{name}_lock"
20
+ redis_objects[lock_name.to_sym] = options.merge(:type => :lock)
21
+ ivar_name = :"@#{lock_name}"
22
+
23
+ mod = Module.new do
24
+ define_method(lock_name) do |&block|
25
+ instance_variable_get(ivar_name) or
26
+ instance_variable_set(ivar_name,
27
+ Redis::Lock.new(
28
+ redis_field_key(lock_name), redis_field_redis(lock_name), redis_objects[lock_name.to_sym]
29
+ )
30
+ )
31
+ end
32
+ end
33
+
34
+ if options[:global]
35
+ extend mod
36
+
37
+ # dispatch to class methods
38
+ define_method(lock_name) do |&block|
39
+ self.class.public_send(lock_name, &block)
40
+ end
41
+ else
42
+ include mod
43
+ end
44
+ end
45
+
46
+ # Obtain a lock, and execute the block synchronously. Any other code
47
+ # (on any server) will spin waiting for the lock up to the :timeout
48
+ # that was specified when the lock was defined.
49
+ def obtain_lock(name, id, &block)
50
+ verify_lock_defined!(name)
51
+ raise ArgumentError, "Missing block to #{self.name}.obtain_lock" unless block_given?
52
+ lock_name = "#{name}_lock"
53
+ Redis::Lock.new(redis_field_key(lock_name, id), redis_field_redis(lock_name), redis_objects[lock_name.to_sym]).lock(&block)
54
+ end
55
+
56
+ # Clear the lock. Use with care - usually only in an Admin page to clear
57
+ # stale locks (a stale lock should only happen if a server crashes.)
58
+ def clear_lock(name, id)
59
+ verify_lock_defined!(name)
60
+ redis.del(redis_field_key("#{name}_lock", id))
61
+ end
62
+
63
+ private
64
+
65
+ def verify_lock_defined!(name)
66
+ unless redis_objects.has_key?("#{name}_lock".to_sym)
67
+ raise Redis::Objects::UndefinedLock, "Undefined lock :#{name} for class #{self.name}"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Sets"
2
+ # For the object itself, see "Redis::Set"
3
+ require 'redis/set'
4
+ class Redis
5
+ module Objects
6
+ module Sets
7
+ def self.included(klass)
8
+ klass.send :include, InstanceMethods
9
+ klass.extend ClassMethods
10
+ end
11
+
12
+ # Class methods that appear in your class when you include Redis::Objects.
13
+ module ClassMethods
14
+ # Define a new list. It will function like a regular instance
15
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
+ def set(name, options={})
17
+ redis_objects[name.to_sym] = options.merge(:type => :set)
18
+ ivar_name = :"@#{name}"
19
+
20
+ mod = Module.new do
21
+ define_method(name) do
22
+ instance_variable_get(ivar_name) or
23
+ instance_variable_set(ivar_name,
24
+ Redis::Set.new(
25
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
26
+ )
27
+ )
28
+ end
29
+
30
+ define_method(:"#{name}=") do |values|
31
+ set = public_send(name)
32
+
33
+ redis.pipelined do
34
+ set.clear
35
+ set.merge(*values)
36
+ end
37
+ end
38
+ end
39
+
40
+ if options[:global]
41
+ extend mod
42
+
43
+ # dispatch to class methods
44
+ define_method(name) do
45
+ self.class.public_send(name)
46
+ end
47
+ else
48
+ include mod
49
+ end
50
+ end
51
+ end
52
+
53
+ # Instance methods that appear in your class when you include Redis::Objects.
54
+ module InstanceMethods
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Sets"
2
+ # For the object itself, see "Redis::Set"
3
+ require 'redis/sorted_set'
4
+ class Redis
5
+ module Objects
6
+ module SortedSets
7
+ def self.included(klass)
8
+ klass.send :include, InstanceMethods
9
+ klass.extend ClassMethods
10
+ end
11
+
12
+ # Class methods that appear in your class when you include Redis::Objects.
13
+ module ClassMethods
14
+ # Define a new list. It will function like a regular instance
15
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
+ def sorted_set(name, options={})
17
+ redis_objects[name.to_sym] = options.merge(:type => :sorted_set)
18
+ ivar_name = :"@#{name}"
19
+
20
+ mod = Module.new do
21
+ define_method(name) do
22
+ instance_variable_get(ivar_name) or
23
+ instance_variable_set(ivar_name,
24
+ Redis::SortedSet.new(
25
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
26
+ )
27
+ )
28
+ end
29
+ end
30
+
31
+ if options[:global]
32
+ extend mod
33
+
34
+ # dispatch to class methods
35
+ define_method(name) do
36
+ self.class.public_send(name)
37
+ end
38
+ else
39
+ include mod
40
+ end
41
+ end
42
+ end
43
+
44
+ # Instance methods that appear in your class when you include Redis::Objects.
45
+ module InstanceMethods
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,64 @@
1
+ # This is the class loader, for use as "include Redis::Objects::Values"
2
+ # For the object itself, see "Redis::Value"
3
+ require 'redis/value'
4
+ class Redis
5
+ module Objects
6
+ module Values
7
+ def self.included(klass)
8
+ klass.send :include, InstanceMethods
9
+ klass.extend ClassMethods
10
+ end
11
+
12
+ # Class methods that appear in your class when you include Redis::Objects.
13
+ module ClassMethods
14
+ # Define a new simple value. It will function like a regular instance
15
+ # method, so it can be used alongside ActiveRecord, DataMapper, etc.
16
+ def value(name, options={})
17
+ redis_objects[name.to_sym] = options.merge(:type => :value)
18
+ ivar_name = :"@#{name}"
19
+
20
+ mod = Module.new do
21
+ define_method(name) do
22
+ instance_variable_get(ivar_name) or
23
+ instance_variable_set(ivar_name,
24
+ Redis::Value.new(
25
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
26
+ )
27
+ )
28
+ end
29
+ define_method("#{name}=") do |value|
30
+ public_send(name).value = value
31
+ end
32
+ end
33
+
34
+ if options[:global]
35
+ extend mod
36
+
37
+ # dispatch to class methods
38
+ define_method(name) do
39
+ self.class.public_send(name)
40
+ end
41
+ define_method("#{name}=") do |value|
42
+ self.class.public_send("#{name}=", value)
43
+ end
44
+ else
45
+ include mod
46
+ end
47
+ end
48
+
49
+ def mget(name, objects = [])
50
+ return [] if objects.nil? || objects.empty?
51
+ raise "Field name Error" if !redis_objects.keys.include?(name.to_sym)
52
+
53
+ keys = objects.map{ |obj| obj.redis_field_key name.to_sym }
54
+
55
+ self.redis.mget keys
56
+ end
57
+ end
58
+
59
+ # Instance methods that appear in your class when you include Redis::Objects.
60
+ module InstanceMethods
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ class Redis
2
+ module Objects
3
+ VERSION = "1.6.0"
4
+ end
5
+ end