multi_redis 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61930ec26bd7e401367fff65403353e02a6d9c7f
4
- data.tar.gz: b9ac5d3857fea25471585dda965067e5509bfee6
3
+ metadata.gz: 679e1a349b9f03a3c6c16634f9a5e8b2051ae5ca
4
+ data.tar.gz: 940d7c657fa3dd83977a536e78e44d366c910072
5
5
  SHA512:
6
- metadata.gz: a1b888ede24eea2c0efb87dfc3db0e4b0cebdad0bd4114c101af9d34afe7d428976b38148d6bba12da701546f8083ad3d898ac0211d273adcc7f85ca8162a1d9
7
- data.tar.gz: 39bee42c79812c41203c46029cfdebb3bbb07f6754bc47188f08a0065ee57ec804ad14e37cbefed9714123835fc9bd2ff83e1c981ffd5de6fa58adb53392c088
6
+ metadata.gz: 5b47def10a775566a8c70cd4b3bbddef629349ebdfe197c2daf6170df572f872a9d7b090fd24d6e530eaf9ffe0067d8314a915aff6d9a8d0ad9eb77374c96e16
7
+ data.tar.gz: ceeca19ecbd97dd7a51ab6dd9d5f4d5b30391bdc8980e0c7eced2f7f45c3c1ebc7e074b74664bf5bb1066eb79378e20c96c6e5aaab1d275853f27beb21d0ae29
data/Gemfile CHANGED
@@ -2,15 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gem 'redis', '~> 3.0'
4
4
 
5
- # Add dependencies to develop your gem here.
6
- # Include everything needed to run rake, tests, features, etc.
7
5
  group :development do
8
- gem 'bundler'
9
- gem 'rake'
10
- gem 'rspec'
11
- gem 'jeweler'
12
- gem 'gem-release'
13
- gem 'rake-version'
14
- gem 'simplecov'
15
- gem 'coveralls', require: false
6
+ gem 'bundler', '~> 1.5'
7
+ gem 'rake', '~> 10.1'
8
+ gem 'rspec', '~> 2.14'
9
+ gem 'jeweler', '~> 2.0'
10
+ gem 'rake-version', '~> 0.4'
11
+ gem 'simplecov', '~> 0.8'
12
+ gem 'coveralls', '~> 0.7', require: false
16
13
  end
data/README.md CHANGED
@@ -25,48 +25,46 @@ Assume you have two separate methods that call redis:
25
25
  $redis = Redis.new
26
26
  $redis.set 'key1', 'foo'
27
27
  $redis.set 'key2', 'bar'
28
- $redis.set 'key3', 'baz'
29
28
 
30
29
  class MyRedisClass
31
30
 
32
31
  def do_stuff
33
-
34
- # run two calls atomically in a MULTI/EXEC
35
- values = $redis.multi do
36
- $redis.get 'key1'
37
- $redis.getset 'key2', 'newvalue'
38
- end
39
-
40
- "value 1 is #{values[0]}, value 2 is #{values[1]}"
32
+ $redis.get 'key1'
41
33
  end
42
34
 
43
35
  def do_other_stuff
44
- value = $redis.get 'key3'
45
- "hey #{value}"
36
+ $redis.get 'key2'
46
37
  end
47
38
  end
48
39
 
49
40
  o = MyRedisClass.new
50
- o.do_stuff #=> "value 1 is foo, value 2 is bar"
51
- o.do_other_stuff #=> "hey baz"
41
+ o.do_stuff #=> "foo"
42
+ o.do_other_stuff #=> "bar"
52
43
  ```
53
44
 
54
- This works, but the redis client executes two separate requests to the server:
45
+ This works, but the redis client executes two separate requests to the server, and waits for the result of the first one to start the second one:
55
46
 
56
47
  ```
57
48
  Request 1:
58
- - MULTI
59
- - GET foo
60
- - GETSET bar newvalue
61
- - EXEC
49
+ - GET key1
62
50
 
63
51
  Request 2:
64
- - GET baz
52
+ - GET key2
53
+ ```
54
+
55
+ `redis-rb` allows you to run both in the same command pipeline:
56
+
57
+ ```rb
58
+ results = $redis.pipelined do
59
+ $redis.get 'key1'
60
+ $redis.get 'key2'
61
+ end
62
+
63
+ results[0] #=> "foo"
64
+ results[1] #=> "bar"
65
65
  ```
66
66
 
67
- The client will wait for the response from the first request before starting the second one.
68
- One round trip could be saved by executing the second request in the same MULTI/EXEC block.
69
- But it would be hard to refactor these two methods to do that while still keeping them separate.
67
+ But it would be hard to refactor the two methods to use a pipeline while still keeping them separate.
70
68
 
71
69
  Multi Redis provides a pattern to structure this code so that your separate redis calls may be executed together in one request when needed.
72
70
 
@@ -74,42 +72,39 @@ Multi Redis provides a pattern to structure this code so that your separate redi
74
72
  $redis = Redis.new
75
73
  $redis.set 'key1', 'foo'
76
74
  $redis.set 'key2', 'bar'
77
- $redis.set 'key3', 'baz'
78
75
 
79
- # Create a redis operation, i.e. an operation that performs redis calls.
76
+ # Create a redis operation, i.e. an operation that performs redis calls, for the first method.
80
77
  do_stuff = MultiRedis::Operation.new do
81
78
 
82
- # Multi blocks will be run atomically in a MULTI/EXEC.
79
+ # Pipelined blocks will be run in a command pipeline.
83
80
  # All redis commands will return futures inside this block, so you can't use the values immediately.
84
- # Store futures in the provided data object for later use.
85
- multi do |mr|
86
- mr.data.value1 = $redis.get 'key1'
87
- mr.data.value2 = $redis.getset 'key2', 'newvalue'
81
+ pipelined do |mr|
82
+ $redis.get 'key1'
88
83
  end
89
84
 
90
- # Run blocks are executed after the previous multi block (or blocks) are completed and all futures have been resolved.
91
- # The data object now contains the values of the futures you stored.
85
+ # This run block will be executed after the pipelined block is completed and all futures have been resolved.
86
+ # The #last_replies method of the Multi Redis context will return the results of all redis calls in the pipelined block.
92
87
  run do |mr|
93
- "value 1 is #{mr.data.value1}, value 2 is #{mr.data.value2}"
88
+ mr.last_replies[0] # => "foo"
94
89
  end
95
90
  end
96
91
 
97
- # The return value of the operation is that of the last run block.
98
- result = do_stuff.execute #=> "value 1 is foo, value 2 is bar"
92
+ # The return value of the operation is that of the last block.
93
+ result = do_stuff.execute #=> "foo"
99
94
 
100
- # Create the other redis operation.
95
+ # Create the redis operation for the other method.
101
96
  do_other_stuff = MultiRedis::Operation.new do
102
97
 
103
98
  multi do |mr|
104
- mr.data.value = $redis.get 'key3'
99
+ $redis.get 'key2'
105
100
  end
106
101
 
107
102
  run do |mr|
108
- "hey #{mr.data.value}"
103
+ mr.last_replies[0] #=> "bar"
109
104
  end
110
105
  end
111
106
 
112
- result = do_other_stuff.execute #=> "hey baz"
107
+ result = do_other_stuff.execute #=> "bar"
113
108
  ```
114
109
 
115
110
  The two operations can still be executed separately like before, but they can also be combined through Multi Redis:
@@ -118,21 +113,18 @@ The two operations can still be executed separately like before, but they can al
118
113
  MultiRedis.execute do_stuff, do_other_stuff
119
114
  ```
120
115
 
121
- All redis calls get grouped into the same MULTI/EXEC:
116
+ Both redis calls get grouped into the same command pipeline:
122
117
 
123
118
  ```
124
119
  One request:
125
- - MULTI
126
120
  - GET foo
127
- - GETSET bar newvalue
128
- - GET baz
129
- - EXEC
121
+ - GET bar
130
122
  ```
131
123
 
132
- The array of results is also returned by the `execute` call:
124
+ The array of results is returned by the `execute` call:
133
125
 
134
126
  ```rb
135
- MultiRedis.execute do_stuff, do_other_stuff #=> [ 'value 1 is foo, value 2 is bar', 'hey baz' ]
127
+ MultiRedis.execute do_stuff, do_other_stuff #=> [ "foo", "bar" ]
136
128
  ```
137
129
 
138
130
  ## Meta
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -1,179 +1,39 @@
1
- require 'ostruct'
2
1
  require 'redis'
3
- require 'thread'
4
2
 
5
3
  module MultiRedis
6
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
7
5
 
8
- @redis = nil
9
- @mutex = Mutex.new
10
- @executing = false
11
- @operations = []
12
- @arguments = []
13
-
14
- def self.redis= redis
15
- @redis = redis
16
- end
17
-
18
- def self.redis
19
- @redis
6
+ class << self
7
+ attr_accessor :redis
20
8
  end
21
9
 
22
10
  def self.execute *args, &block
23
11
 
24
- operations, arguments = @mutex.synchronize do
25
- @operations = args.dup
26
- @arguments = []
27
- @executing = true
28
- yield if block_given?
29
- @executing = false
30
- [ @operations.dup.tap{ |ops| @operations.clear }, @arguments ]
31
- end
32
-
33
- Executor.new(operations, args: arguments).execute
34
- end
35
-
36
- def self.executing?
37
- @executing
38
- end
12
+ options = args.last.kind_of?(Hash) ? args.pop : {}
39
13
 
40
- def self.register_operation op, *args
41
- op.tap do |op|
42
- @operations << op
43
- @arguments << args
14
+ executor = nil
15
+ @mutex.synchronize do
16
+ @executor = Executor.new options
17
+ args.each{ |op| @executor.add op }
18
+ yield if block_given?
19
+ executor = @executor
20
+ @executor = nil
44
21
  end
45
- end
46
-
47
- module Extension
48
22
 
49
- def multi_redis_operation symbol, options = {}, &block
50
- op = Operation.new self, options, &block
51
- define_method symbol do |*args|
52
- op.execute *args
53
- end
54
- self
55
- end
23
+ executor.execute
56
24
  end
57
25
 
58
- class Executor
59
-
60
- def initialize operations, options = {}
61
- @operations = operations
62
- @arguments = options[:args] || []
63
- @redis = options[:redis]
64
- end
65
-
66
- def execute options = {}
67
-
68
- redis = @redis || MultiRedis.redis
69
- contexts = Array.new(@operations.length){ |i| Context.new redis }
70
- stacks = @operations.collect{ |op| op.steps.dup }
71
- args = stacks.collect.with_index{ |a,i| @arguments[i] || [] }
72
- final_results = Array.new @operations.length
26
+ private
73
27
 
74
- while stacks.any? &:any?
75
-
76
- # execute all non-multi steps
77
- stacks.each_with_index do |steps,i|
78
- final_results[i] = steps.shift.execute(contexts[i], args[i]) while steps.first && !steps.first.multi_type
79
- end
80
-
81
- # execute all pipelined steps, if any
82
- pipelined_steps = stacks.collect{ |steps| steps.first && steps.first.multi_type == :pipelined ? steps.shift : nil }
83
- if pipelined_steps.any?
84
- results = []
85
- redis.pipelined do
86
- pipelined_steps.each_with_index do |step,i|
87
- if step
88
- final_results[i] = step.execute(contexts[i], args[i])
89
- contexts[i].last_results = redis.client.futures[results.length, redis.client.futures.length]
90
- results += contexts[i].last_results
91
- end
92
- end
93
- end
94
- pipelined_steps.each_with_index{ |step,i| contexts[i].resolve_futures! if step }
95
- end
96
-
97
- # execute all multi steps, if any
98
- multi_steps = stacks.collect{ |steps| steps.first && steps.first.multi_type == :multi ? steps.shift : nil }
99
- if multi_steps.any?
100
- results = []
101
- redis.multi do
102
- multi_steps.each_with_index do |step,i|
103
- if step
104
- final_results[i] = step.execute(contexts[i], args[i])
105
- contexts[i].last_results = redis.client.futures[results.length, redis.client.futures.length]
106
- results += contexts[i].last_results
107
- end
108
- end
109
- end
110
- multi_steps.each_with_index{ |step,i| contexts[i].resolve_futures! if step }
111
- end
112
- end
113
-
114
- final_results
115
- end
116
- end
117
-
118
- class Operation
119
- attr_reader :steps
120
-
121
- def initialize *args, &block
122
-
123
- options = args.last.kind_of?(Hash) ? args.pop : {}
124
-
125
- @target = args.shift || options[:target] || self
126
- @redis = options[:redis]
127
- @steps = []
128
-
129
- DSL.new(self).instance_eval &block
130
- end
131
-
132
- def execute *args
133
- if MultiRedis.executing?
134
- MultiRedis.register_operation self, *args
135
- else
136
- Executor.new([ self ], args: [ args ], redis: @redis).execute.first
137
- end
138
- end
139
-
140
- def add_step multi_type = nil, &block
141
- @steps << Step.new(@target, multi_type, block)
142
- end
143
-
144
- class DSL
145
-
146
- def initialize op
147
- @op = op
148
- end
149
-
150
- def multi &block
151
- @op.add_step :multi, &block
152
- end
153
-
154
- def pipelined &block
155
- @op.add_step :pipelined, &block
156
- end
28
+ @mutex = Mutex.new
29
+ @executor = nil
157
30
 
158
- def run &block
159
- @op.add_step &block
160
- end
161
- end
31
+ def self.executor
32
+ @executor
162
33
  end
163
34
 
164
- class Step
165
-
166
- def initialize target, multi_type, block
167
- @target, @multi_type, @block = target, multi_type, block
168
- end
169
-
170
- def execute context, *args
171
- @target.instance_exec *args.unshift(context), &@block
172
- end
173
-
174
- def multi_type
175
- @multi_type
176
- end
35
+ def self.executing?
36
+ !!@executor
177
37
  end
178
38
  end
179
39
 
@@ -1,13 +1,28 @@
1
-
2
1
  module MultiRedis
3
2
 
4
3
  class Context
5
- attr_accessor :last_results
4
+ attr_accessor :last_result
5
+ attr_accessor :last_replies
6
6
 
7
- def initialize redis
8
- @last_results = []
9
- @data = Data.new
7
+ def initialize redis, shared_context = nil
10
8
  @redis = redis
9
+ @data = Data.new
10
+ @last_replies = []
11
+ @shared_context = shared_context
12
+ end
13
+
14
+ def execute operation, *args
15
+ @last_result = operation.execute self, *args
16
+ if @resolve = @redis.client.respond_to?(:futures)
17
+ @last_replies = @redis.client.futures[@shared_context.last_replies.length, @redis.client.futures.length]
18
+ @shared_context.last_replies.concat @last_replies
19
+ end
20
+ @shared_context.last_result = @last_result
21
+ @last_result
22
+ end
23
+
24
+ def shared
25
+ @shared_context
11
26
  end
12
27
 
13
28
  def redis
@@ -19,10 +34,11 @@ module MultiRedis
19
34
  end
20
35
 
21
36
  def resolve_futures!
22
- @data.contents.each_key do |k|
23
- @data.contents[k] = @data.contents[k].value if @data.contents[k].is_a? Redis::Future
37
+ return unless @resolve
38
+ @data.each_key do |k|
39
+ @data[k] = @data[k].value if @data[k].is_a? Redis::Future
24
40
  end
25
- @last_results.collect!{ |r| r.is_a?(Redis::Future) ? r.value : r }
41
+ @last_replies.collect!{ |r| r.is_a?(Redis::Future) ? r.value : r }
26
42
  end
27
43
  end
28
44
  end
@@ -1,27 +1,14 @@
1
-
2
1
  module MultiRedis
3
2
 
4
- class Data
5
- attr_reader :contents
6
-
7
- def initialize
8
- @contents = Hash.new
9
- end
10
-
11
- def [] k
12
- @contents[k]
13
- end
14
-
15
- def []= k, v
16
- @contents[k.to_sym] = v
17
- end
3
+ class Data < Hash
18
4
 
19
5
  def method_missing symbol, *args, &block
20
- if @contents.key? symbol
21
- @contents[symbol]
22
- elsif m = symbol.to_s.match(/\A(.*)\=\Z/)
23
- raise "Reserved name" if respond_to? acc = m[1].to_sym
24
- @contents[acc] = args[0]
6
+ if args.empty?
7
+ self[symbol]
8
+ elsif args.length == 1 && m = symbol.to_s.match(/\A(.*)\=\Z/)
9
+ acc = m[1].to_sym
10
+ raise ArgumentError, "Cannot set property #{acc}, method ##{acc} already exists" if respond_to? acc
11
+ self[acc] = args[0]
25
12
  else
26
13
  super symbol, *args, &block
27
14
  end
@@ -0,0 +1,97 @@
1
+ module MultiRedis
2
+
3
+ class Executor
4
+
5
+ def initialize options = {}
6
+ @operations = []
7
+ @redis = options[:redis]
8
+ end
9
+
10
+ def add operation, *args
11
+ @operations << { op: operation, args: args }
12
+ end
13
+
14
+ def execute options = {}
15
+
16
+ redis = @redis || MultiRedis.redis
17
+ shared_context = Context.new redis
18
+
19
+ total = 0
20
+ execution = @operations.collect do |operation|
21
+ total += operation[:op].steps.length
22
+ OperationExecution.new operation[:op], operation[:args], shared_context
23
+ end
24
+
25
+ while execution.any?{ |oe| !oe.done? } && total >= 1
26
+ total -= 1 # safeguard against infinite loop
27
+
28
+ TYPES.each do |type|
29
+
30
+ execution.each do |oe|
31
+ oe.execute_current_step while oe.next? :call
32
+ end
33
+
34
+ if execution.any?{ |oe| oe.next? type }
35
+ shared_context.last_replies.clear
36
+ redis.send type do
37
+ execution.each do |oe|
38
+ oe.execute_current_step if oe.next? type
39
+ end
40
+ end
41
+ execution.each{ |oe| oe.resolve_futures! }
42
+ end
43
+ end
44
+ end
45
+
46
+ execution.each{ |oe| oe.resolve_operation_future! }
47
+ execution.collect!{ |oe| oe.final_results }
48
+ end
49
+
50
+ private
51
+
52
+ TYPES = [ :pipelined, :multi ]
53
+
54
+ class OperationExecution
55
+ attr_reader :final_results
56
+
57
+ def initialize operation, args, shared_context
58
+
59
+ @operation = operation
60
+ @args = args
61
+
62
+ @context = Context.new shared_context.redis, shared_context
63
+ @steps = operation.steps
64
+
65
+ @current_index = 0
66
+ end
67
+
68
+ def done?
69
+ !current_step
70
+ end
71
+
72
+ def next? type
73
+ current_step && current_step.type == type
74
+ end
75
+
76
+ def execute_current_step
77
+ results = @context.execute current_step, *@args
78
+ @current_index += 1
79
+ @final_results = results
80
+ end
81
+
82
+ def resolve_futures!
83
+ @context.resolve_futures!
84
+ end
85
+
86
+ def resolve_operation_future!
87
+ @operation.future.value = @final_results if @operation.future
88
+ end
89
+
90
+ private
91
+
92
+ def current_step
93
+ @steps[@current_index]
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,13 @@
1
+ module MultiRedis
2
+
3
+ module Extension
4
+
5
+ def multi_redis_operation symbol, options = {}, &block
6
+ op = Operation.new options.merge(target: self), &block
7
+ define_method symbol do |*args|
8
+ op.execute *args
9
+ end
10
+ self
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module MultiRedis
2
+
3
+ class FutureNotReady < RuntimeError
4
+
5
+ def initialize
6
+ super "Value will be available once the operation executes."
7
+ end
8
+ end
9
+
10
+ class Future
11
+ FutureNotReady = ::MultiRedis::FutureNotReady.new
12
+ attr_writer :value
13
+
14
+ def initialize value = nil
15
+ @value = value || FutureNotReady
16
+ end
17
+
18
+ def value
19
+ raise @value if @value.kind_of? RuntimeError
20
+ @value
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,61 @@
1
+ module MultiRedis
2
+
3
+ class Operation
4
+ attr_accessor :redis
5
+ attr_reader :steps, :future
6
+
7
+ def initialize options = {}, &block
8
+
9
+ @target = options[:target] || self
10
+ @redis = options[:redis]
11
+ @steps = []
12
+
13
+ configure &block if block
14
+ end
15
+
16
+ def configure &block
17
+ DSL.new(self).instance_eval &block
18
+ end
19
+
20
+ def execute *args
21
+ if MultiRedis.executing?
22
+ MultiRedis.executor.add self, *args
23
+ @future = Future.new
24
+ else
25
+ e = Executor.new redis: @redis
26
+ e.add self, *args
27
+ e.execute.first.tap do |result|
28
+ @future = Future.new result
29
+ end
30
+ end
31
+ end
32
+
33
+ def add type, &block
34
+ raise ArgumentError, "Unknown type #{type}, must be one of #{TYPES.join ', '}." unless TYPES.include? type
35
+ @steps << Step.new(@target, type, block)
36
+ end
37
+
38
+ private
39
+
40
+ TYPES = [ :call, :pipelined, :multi ]
41
+
42
+ class DSL
43
+
44
+ def initialize op
45
+ @op = op
46
+ end
47
+
48
+ def multi &block
49
+ @op.add :multi, &block
50
+ end
51
+
52
+ def pipelined &block
53
+ @op.add :pipelined, &block
54
+ end
55
+
56
+ def run &block
57
+ @op.add :call, &block
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ module MultiRedis
2
+
3
+ class Step
4
+
5
+ def initialize target, type, block
6
+ @target, @type, @block = target, type, block
7
+ end
8
+
9
+ def execute context, *args
10
+ @target.instance_exec *args.unshift(context), &@block
11
+ end
12
+
13
+ def type
14
+ @type
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Oulevay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-09 00:00:00.000000000 Z
11
+ date: 2014-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -28,114 +28,100 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.5'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1.5'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '10.1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '10.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '2.14'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '2.14'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: jeweler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: gem-release
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
73
+ - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0'
75
+ version: '2.0'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
- - - ">="
80
+ - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0'
82
+ version: '2.0'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: rake-version
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
- - - ">="
87
+ - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: '0'
89
+ version: '0.4'
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
- - - ">="
94
+ - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: '0'
96
+ version: '0.4'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: simplecov
113
99
  requirement: !ruby/object:Gem::Requirement
114
100
  requirements:
115
- - - ">="
101
+ - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: '0'
103
+ version: '0.8'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
- - - ">="
108
+ - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: '0'
110
+ version: '0.8'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: coveralls
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
- - - ">="
115
+ - - "~>"
130
116
  - !ruby/object:Gem::Version
131
- version: '0'
117
+ version: '0.7'
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
- - - ">="
122
+ - - "~>"
137
123
  - !ruby/object:Gem::Version
138
- version: '0'
124
+ version: '0.7'
139
125
  description: Allows you to organize your redis calls in separate classes but still
140
126
  execute them atomically with pipelined or multi.
141
127
  email: git@alphahydrae.com
@@ -152,6 +138,11 @@ files:
152
138
  - lib/multi_redis.rb
153
139
  - lib/multi_redis/context.rb
154
140
  - lib/multi_redis/data.rb
141
+ - lib/multi_redis/executor.rb
142
+ - lib/multi_redis/extension.rb
143
+ - lib/multi_redis/future.rb
144
+ - lib/multi_redis/operation.rb
145
+ - lib/multi_redis/step.rb
155
146
  homepage: http://github.com/AlphaHydrae/multi_redis
156
147
  licenses:
157
148
  - MIT