redis-objects-legacy 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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