redis-roc 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/lib/redis-roc.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'roc/store'
2
+ require 'roc/objects'
@@ -0,0 +1,20 @@
1
+ class Redis
2
+
3
+ def zrevrangebyscore(key, max, min, options = {})
4
+ command = CommandOptions.new(options) do |c|
5
+ c.splat :limit
6
+ c.bool :with_scores
7
+ end
8
+
9
+ @client.call(:zrevrangebyscore, key, max, min, *command.to_a)
10
+ end
11
+
12
+ def del(*keys)
13
+ _bool @client.call(:del, *keys)
14
+ end
15
+
16
+ def hdel(key, field)
17
+ _bool @client.call(:hdel, key, field)
18
+ end
19
+
20
+ end
@@ -0,0 +1,81 @@
1
+ if RUBY_VERSION.match(/^1\.8/)
2
+ require 'rubygems'
3
+ end
4
+ require 'cim_attributes'
5
+
6
+ require 'roc/types/all_types'
7
+
8
+ module ROC
9
+ class Base
10
+ include ROC::Types::AllTypes
11
+ include CIMAttributes
12
+
13
+ attr_reader :key, :options
14
+
15
+ cim_attr_accessor :storage
16
+
17
+ # key, [storage], [seed_data], [opts]
18
+ def initialize(key, *args)
19
+ @key = key
20
+
21
+ if args.last.is_a?(Hash)
22
+ @options = args.pop
23
+ end
24
+
25
+ if args.first.is_a?(ROC::Store::ROCStore)
26
+ @storage = args.shift
27
+ end
28
+
29
+ if !self.storage
30
+ raise ArgumentError, 'no class-level storage set, so must initialize with a Store'
31
+ end
32
+
33
+ if args.size > 1
34
+ raise ArgumentError, 'new(key, [storage], [seed_data], [opts])'
35
+ end
36
+
37
+ if !(seed_data = args.pop).nil?
38
+ seed(seed_data)
39
+ end
40
+ end
41
+
42
+ def seed(data)
43
+ if self.exists?
44
+ raise "#{self.key} already exists -- can't seed it"
45
+ else
46
+ self.clobber(data)
47
+ end
48
+ end
49
+
50
+ def clobber(data)
51
+ raise "clobber must be overriden in subclasses"
52
+ end
53
+
54
+ def self.delegate_methods(options)
55
+ raise ":on and :to required to delegate methods" unless options.has_key?(:on) && options.has_key?(:to)
56
+ self.const_set('DELEGATE_OPTIONS', options)
57
+ end
58
+
59
+ def respond_to?(method_name)
60
+ self.methods.include?(method_name) || (self.class.const_get('DELEGATE_OPTIONS') && self.class.const_get('DELEGATE_OPTIONS')[:on].respond_to?(method_name))
61
+ end
62
+
63
+ def method_missing(method_name, *args, &block)
64
+ if self.class.const_get('DELEGATE_OPTIONS') &&
65
+ (delegate_type = self.class.const_get('DELEGATE_OPTIONS')[:on]) &&
66
+ delegate_type.respond_to?(method_name) &&
67
+ !['!', '='].include?(method_name.to_s[method_name.to_s.length - 1]) # we won't delegate modifying methods
68
+ self.send(self.class.const_get('DELEGATE_OPTIONS')[:to]).send(method_name, *args, &block)
69
+ else
70
+ super(method_name, *args, &block)
71
+ end
72
+ end
73
+
74
+ protected
75
+
76
+ def call(remote_method_name, *args)
77
+ self.storage.call(remote_method_name, self.key, *args)
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ require 'roc/objects/base'
2
+ module ROC
3
+ class Float < Base
4
+ include ROC::Types::ScalarType
5
+
6
+ delegate_methods :on => 0.0, :to => :value
7
+
8
+ def to_float
9
+ self.value.to_f
10
+ end
11
+ alias to_f to_float
12
+
13
+ ## implementing scalar type required methods ##
14
+
15
+ def serialize(val)
16
+ val.to_s
17
+ end
18
+
19
+ def deserialize(val)
20
+ if val.nil?
21
+ nil
22
+ elsif 'Infinity' == val
23
+ 1.0 / 0
24
+ elsif '-Infinity' == val
25
+ -1.0 / 0
26
+ else
27
+ val.to_f
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,134 @@
1
+ require 'roc/objects/base'
2
+ module ROC
3
+ class Hash < Base
4
+ extend ROC::Types::MethodGenerators
5
+
6
+ delegate_methods :on => {}, :to => :to_hash
7
+
8
+ nonserializing_method :hdel
9
+
10
+ nonserializing_method :hexists
11
+ alias key? hexists
12
+ alias has_key? hexists
13
+ alias member? hexists
14
+ alias include? hexists
15
+
16
+ nonserializing_method :hget
17
+ alias get hget
18
+ alias [] hget
19
+
20
+ zero_arg_method :hgetall
21
+ alias getall hgetall
22
+
23
+ def hincrby(field, increment)
24
+ self.call :hincrby, field, increment
25
+ end
26
+ alias incrby hincrby
27
+
28
+ zero_arg_method :hkeys
29
+ alias keys hkeys
30
+
31
+ zero_arg_method :hlen
32
+ alias len hlen
33
+ alias length hlen
34
+ alias size hlen
35
+
36
+ def hmget(*fields)
37
+ self.call :hmget, *fields
38
+ end
39
+ alias mget hmget
40
+
41
+ def hmset(*pairs)
42
+ self.call :hmset, *pairs
43
+ end
44
+ alias mset hmset
45
+
46
+ def hset(field, val)
47
+ self.call :hset, field, val
48
+ end
49
+ alias set hset
50
+ alias []= hset
51
+ alias store hset
52
+
53
+ def hsetnx(field, val)
54
+ self.call :hsetnx, field, val
55
+ end
56
+ alias setnx hsetnx
57
+
58
+ zero_arg_method :hvals
59
+ alias vals hvals
60
+ alias values hvals
61
+
62
+ # shortcuts/helpers
63
+
64
+ alias values_at hmget
65
+
66
+ def has_value?(val)
67
+ self.values.include?(val)
68
+ end
69
+ alias value? has_value?
70
+
71
+ def empty?
72
+ 0 == self.hlen
73
+ end
74
+
75
+ def decrby(field, by)
76
+ self.hincrby field, -by
77
+ end
78
+
79
+ def increment(field, by=nil)
80
+ self.hincrby field, (by || 1)
81
+ end
82
+
83
+ def decrement(field, by=nil)
84
+ self.hincrby field, -(by || 1)
85
+ end
86
+
87
+ ## implement (if posible) destructive methods that would otherwise raise
88
+
89
+ def merge!(hsh)
90
+ raise ArgumentError, 'block version not supported' if block_given?
91
+ self.hmset(*hsh.to_a.flatten)
92
+ self
93
+ end
94
+ alias update merge!
95
+
96
+ def delete(field)
97
+ val = self.hget(field)
98
+ self.hdel(field)
99
+ val
100
+ end
101
+
102
+ def replace(hsh)
103
+ self.clobber(hsh)
104
+ self
105
+ end
106
+
107
+ def clear
108
+ self.replace({})
109
+ end
110
+
111
+ def delete_if
112
+ raise NotImplementedError
113
+ end
114
+
115
+ def shift
116
+ raise NotImplementedError
117
+ end
118
+
119
+ ## implementing for delegate
120
+
121
+ alias to_hash getall
122
+ alias to_h getall
123
+
124
+ def clobber(data)
125
+ self.storage.multi do
126
+ self.forget
127
+ if data.size > 0
128
+ self.merge!(data)
129
+ end
130
+ end
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,51 @@
1
+ require 'roc/objects/base'
2
+ module ROC
3
+ class Integer < Base
4
+ include ROC::Types::ScalarType
5
+
6
+ delegate_methods :on => 0, :to => :value
7
+
8
+ def to_integer
9
+ self.value.to_i
10
+ end
11
+ alias to_int to_integer
12
+ alias to_i to_integer
13
+
14
+ ## implemeting redis methods ##
15
+
16
+ def increment(by=nil)
17
+ if by.nil?
18
+ self.call :incr
19
+ else
20
+ self.call :incrby, by
21
+ end
22
+ end
23
+ alias incr increment
24
+ alias incrby increment
25
+
26
+ def decrement(by=nil)
27
+ if by.nil?
28
+ self.call :decr
29
+ else
30
+ self.call :decrby, by
31
+ end
32
+ end
33
+ alias decr decrement
34
+ alias decrby decrement
35
+
36
+ ## implementing scalar type required methods ##
37
+
38
+ def serialize(val)
39
+ val.to_s
40
+ end
41
+
42
+ def deserialize(val)
43
+ if val.nil?
44
+ nil
45
+ else
46
+ val.to_i
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,204 @@
1
+ require 'roc/objects/base'
2
+ require 'roc/types/array_type'
3
+ require 'roc/types/sortable_type'
4
+
5
+ module ROC
6
+ class List < Base
7
+ include ROC::Types::ArrayType
8
+ include ROC::Types::SortableType
9
+ extend ROC::Types::MethodGenerators
10
+
11
+ def lrange(start_index, stop_index)
12
+ self.call :lrange, start_index, stop_index
13
+ end
14
+ alias range lrange
15
+
16
+ zero_arg_method :llen
17
+ alias len llen
18
+
19
+ nonserializing_method :rpush
20
+
21
+ nonserializing_method :rpushx
22
+ alias pushx rpushx
23
+
24
+ nonserializing_method :lpush
25
+
26
+ nonserializing_method :lpushx
27
+ alias unshiftx lpushx
28
+
29
+ zero_arg_method :rpop
30
+
31
+ zero_arg_method :lpop
32
+
33
+ def lset(index, val)
34
+ self.call :lset, index, val
35
+ end
36
+ alias set lset
37
+
38
+ nonserializing_method :lindex
39
+ alias index lindex
40
+
41
+ def lrem(count, val)
42
+ self.call :lrem, count, val
43
+ end
44
+ alias rem lrem
45
+
46
+ def ltrim(start_index, stop_index)
47
+ self.call :ltrim, start_index, stop_index
48
+ end
49
+ alias trim ltrim
50
+
51
+ def rpoplpush(other_list=self)
52
+ self.call :rpoplpush, other_list.key
53
+ end
54
+
55
+ def linsert(where, pivot, value)
56
+ self.call :linsert, where, pivot, value
57
+ end
58
+
59
+ def linsert_before(pivot, value)
60
+ self.linsert('before', pivot, value)
61
+ end
62
+ alias insert_before linsert_before
63
+
64
+ def linsert_after(pivot, value)
65
+ self.linsert('after', pivot, value)
66
+ end
67
+ alias insert_after linsert_after
68
+
69
+
70
+ ## shortcut methods
71
+
72
+ def [](range_or_num, num=nil)
73
+ if range_or_num.is_a?(::Integer)
74
+ if num.nil?
75
+ self.lindex(range_or_num)
76
+ elsif num >= 0
77
+ self.lrange(range_or_num, range_or_num + num - 1)
78
+ else
79
+ raise ArgumentError, 'second arg to [] must be a non-neg integer'
80
+ end
81
+ elsif range_or_num.is_a?(Range)
82
+ self.lrange(range_or_num.first, (range_or_num.exclude_end? ? range_or_num.last - 1 : range_or_num.last))
83
+ else
84
+ if num.nil?
85
+ self.values.slice(range_or_num)
86
+ else
87
+ self.values.slice(range_or_num, num)
88
+ end
89
+ end
90
+ end
91
+ alias slice []
92
+
93
+ def first
94
+ self.lindex(0)
95
+ end
96
+
97
+ def last
98
+ self.lindex(-1)
99
+ end
100
+
101
+ def []=(*args)
102
+ case args.size
103
+ when 1
104
+ raise ArgumentError, 'index required'
105
+ when 2
106
+ if args[0].is_a?(::Integer)
107
+ self.lset(*args)
108
+ else
109
+ raise ArgumentError, 'range assignment not supported in []='
110
+ end
111
+ when 3
112
+ raise ArgumentError, 'multiple index assignment not supported in []='
113
+ else
114
+ raise ArgumentError, 'wrong number of args'
115
+ end
116
+ end
117
+
118
+ ## implement (if posible) destructive methods that would otherwise raise
119
+
120
+ def delete(val)
121
+ count = self.lrem(0, val)
122
+ if count > 0
123
+ val
124
+ else
125
+ nil
126
+ end
127
+ end
128
+
129
+ def push(*objs)
130
+ if 1 == objs.size
131
+ self.rpush(objs[0])
132
+ elsif objs.size > 1
133
+ self.storage.multi do
134
+ objs.each do |obj|
135
+ self.rpush(obj)
136
+ end
137
+ end
138
+ end
139
+ self
140
+ end
141
+
142
+ def <<(obj)
143
+ self.push(obj)
144
+ end
145
+
146
+ def unshift(*objs)
147
+ if 1 == objs.size
148
+ self.lpush(objs[0])
149
+ elsif objs.size > 1
150
+ self.storage.multi do
151
+ objs.reverse.each do |obj|
152
+ self.lpush(obj)
153
+ end
154
+ end
155
+ end
156
+ self
157
+ end
158
+
159
+ def pop(*args)
160
+ if 0 == args.size
161
+ self.rpop
162
+ elsif 1 == args.size
163
+ (self.storage.multi do
164
+ args[0].times do
165
+ self.rpop
166
+ end
167
+ end).reverse
168
+ else
169
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)"
170
+ end
171
+ end
172
+
173
+ def shift(*args)
174
+ if 0 == args.size
175
+ self.lpop
176
+ elsif 1 == args.size
177
+ (self.storage.multi do
178
+ args[0].times do
179
+ self.lpop
180
+ end
181
+ end).reverse
182
+ else
183
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)"
184
+ end
185
+ end
186
+
187
+ ## implementing ArrayType ##
188
+
189
+ def clobber(vals)
190
+ self.storage.multi do
191
+ self.forget
192
+ vals.each{|v| self << v}
193
+ end
194
+ end
195
+
196
+ def values
197
+ self.lrange(0, -1)
198
+ end
199
+
200
+ alias size llen
201
+ alias length llen
202
+
203
+ end
204
+ end
@@ -0,0 +1,53 @@
1
+ module ROC
2
+ class Lock < Time
3
+
4
+ def lock(expires_time)
5
+ aquired_lock = false
6
+ if self.setnx(expires_time)
7
+ aquired_lock = true
8
+ else
9
+ locked_until = self.value
10
+ if locked_until.nil? || (locked_until < ::Time.now) ##ttl of 0 is not yet expired
11
+ # only say we got the lock if we manage to update it first
12
+ if self.getset(expires_time) == locked_until
13
+ aquired_lock = true
14
+ end
15
+ end
16
+ end
17
+ aquired_lock
18
+ end
19
+
20
+ def locked?
21
+ locked_until = self.value
22
+ !locked_until.nil? && (locked_until >= ::Time.now) ##ttl of 0 is not yet expired
23
+ end
24
+
25
+ def unlock
26
+ self.forget
27
+ end
28
+
29
+ def when_locked(expires_time, poll_ms=100)
30
+ until self.lock(expires_time)
31
+ sleep(poll_ms.to_f / 1000)
32
+ end
33
+ begin
34
+ yield
35
+ ensure
36
+ self.unlock
37
+ end
38
+ end
39
+
40
+ def locking_if_necessary(expires_time)
41
+ obtained_lock = self.lock(expires_time)
42
+ begin
43
+ yield
44
+ ensure
45
+ if obtained_lock
46
+ self.unlock
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+