resque-approval 1.0.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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +100 -0
- data/Rakefile +13 -0
- data/lib/resque-approval.rb +72 -0
- data/lib/resque-approval/version.rb +7 -0
- data/resque-approval.gemspec +28 -0
- data/spec/lib/resque-approval_spec.rb +153 -0
- data/spec/redis-test.conf +7 -0
- data/spec/spec_helper.rb +29 -0
- metadata +117 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Earle Clubb
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# resque-approval
|
2
|
+
|
3
|
+
A Resque plugin allowing jobs to be sent to a temporary queue to await approval.
|
4
|
+
Once the job is approved, it is placed on its normal queue.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'resque-approval'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install resque-approval
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
To enable approval holding for a job class, simply extend that class with
|
23
|
+
Resque::Plugins::Approval, like so:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
class Job
|
27
|
+
extend Resque::Plugins::Approval
|
28
|
+
|
29
|
+
@queue = 'dummy'
|
30
|
+
|
31
|
+
def self.perform
|
32
|
+
# ...
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Then, when you want to queue up a job of that class, add a couple special
|
38
|
+
arguments to your job:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
Resque.enqueue(Job, :requires_approval => true, :approval_message => 'Test')
|
42
|
+
```
|
43
|
+
|
44
|
+
`:requires_approval` tells resque-approval to put your job in a special queue to
|
45
|
+
wait for approval. If its missing or false, your job is placed in its default
|
46
|
+
queue.
|
47
|
+
|
48
|
+
`:approval_message` is an optional message you can reference later.
|
49
|
+
|
50
|
+
To get a list of pending jobs:
|
51
|
+
```ruby
|
52
|
+
Resque::Plugins::Approval.pending_job_keys
|
53
|
+
```
|
54
|
+
This will return a list in first-in, first-out order. Each entry contains an id
|
55
|
+
and any message you may have specified when enqueueing the job.
|
56
|
+
|
57
|
+
To approve a job:
|
58
|
+
```ruby
|
59
|
+
Job.approve(key)
|
60
|
+
```
|
61
|
+
where key is an entry from the list returned by pending_job_keys. This will
|
62
|
+
move the job from the approval_required queue to the default queue for that job.
|
63
|
+
|
64
|
+
To reject a job:
|
65
|
+
```ruby
|
66
|
+
Job.reject(key)
|
67
|
+
```
|
68
|
+
This will delete the job from the approval_required queue, but will not move it
|
69
|
+
to the job's default queue. This effectively drops the job from the system.
|
70
|
+
|
71
|
+
## Example
|
72
|
+
|
73
|
+
A sample session using the Job class above might look like this:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# Queue up a job with a message.
|
77
|
+
Resque.enqueue(Job, :requires_approval => true, :approval_message => 'Just a test')
|
78
|
+
|
79
|
+
# Queue up a job without a message.
|
80
|
+
Resque.enqueue(Job, :requires_approval => true)
|
81
|
+
|
82
|
+
# List the ids and messages.
|
83
|
+
pending_actions = Resque::Plugins::Approval.pending_job_keys
|
84
|
+
pending_actions.each do |action|
|
85
|
+
puts "id: #{action['id'], message: #{action['approval_message']}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Approve the first job...
|
89
|
+
Job.approve(pending_actions[0])
|
90
|
+
|
91
|
+
# But reject the second
|
92
|
+
Job.reject(pending_actions[1])
|
93
|
+
```
|
94
|
+
## Contributing
|
95
|
+
|
96
|
+
1. Fork it
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
99
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
100
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'resque-approval/version'
|
2
|
+
require 'resque'
|
3
|
+
|
4
|
+
module Resque
|
5
|
+
module Plugins
|
6
|
+
module Approval
|
7
|
+
def self.pending_job_keys
|
8
|
+
keys = Resque.redis.hkeys('pending_jobs')
|
9
|
+
keys.map! { |key| JSON.parse(key) }
|
10
|
+
keys.sort! { |a, b| a['id'] <=> b['id'] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def before_enqueue_approval(*args)
|
14
|
+
args = args[0] || {}
|
15
|
+
|
16
|
+
requires_approval = args.delete(:requires_approval) || args.delete('requires_approval')
|
17
|
+
if requires_approval
|
18
|
+
enqueue_for_approval(args)
|
19
|
+
allow_enqueue = false
|
20
|
+
else
|
21
|
+
allow_enqueue = true
|
22
|
+
end
|
23
|
+
|
24
|
+
allow_enqueue
|
25
|
+
end
|
26
|
+
|
27
|
+
def enqueue_for_approval(*args)
|
28
|
+
args = args[0] || {}
|
29
|
+
|
30
|
+
message = args.delete(:approval_message) || args.delete('approval_message')
|
31
|
+
|
32
|
+
Resque.enqueue_to(:approval_required, self, args)
|
33
|
+
|
34
|
+
id = Resque.size(:approval_required) - 1
|
35
|
+
|
36
|
+
if message
|
37
|
+
key = {:id => id, :approval_message => message}.to_json
|
38
|
+
else
|
39
|
+
key = { :id => id }.to_json
|
40
|
+
end
|
41
|
+
|
42
|
+
job = Resque.peek(:approval_required, id)
|
43
|
+
value = job.to_json
|
44
|
+
|
45
|
+
Resque.redis.hset('pending_jobs', key, value)
|
46
|
+
end
|
47
|
+
|
48
|
+
def approve(key)
|
49
|
+
value = Resque.redis.hget('pending_jobs', key)
|
50
|
+
|
51
|
+
return false if value.nil?
|
52
|
+
|
53
|
+
job = JSON.parse(value)
|
54
|
+
|
55
|
+
Resque.redis.hdel('pending_jobs', key)
|
56
|
+
Resque.redis.lrem('queue:approval_required', 1, job.to_json)
|
57
|
+
Resque.push(Resque.queue_from_class(self), job)
|
58
|
+
end
|
59
|
+
|
60
|
+
def reject(key)
|
61
|
+
value = Resque.redis.hget('pending_jobs', key)
|
62
|
+
|
63
|
+
return false if value.nil?
|
64
|
+
|
65
|
+
job = JSON.parse(value)
|
66
|
+
|
67
|
+
Resque.redis.hdel('pending_jobs', key)
|
68
|
+
Resque.redis.lrem('queue:approval_required', 1, job.to_json)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/resque-approval/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'resque-approval'
|
6
|
+
gem.version = Resque::Plugins::Approval::VERSION
|
7
|
+
gem.date = Time.now.strftime('%Y-%m-%d')
|
8
|
+
gem.description = %q{A Resque plugin allowing jobs to be sent to a temporary
|
9
|
+
queue to await approval. Once the job is approved, it
|
10
|
+
is placed on its normal queue.}
|
11
|
+
gem.summary = %q{A Resque plugin allowing jobs to be sent to a temporary
|
12
|
+
queue to await approval.}
|
13
|
+
gem.homepage = 'https://github.com/eclubb/resque-approval'
|
14
|
+
gem.authors = ['Earle Clubb']
|
15
|
+
gem.email = ['eclubb@valcom.com']
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($\)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ['lib']
|
21
|
+
|
22
|
+
gem.add_runtime_dependency 'resque'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'rake'
|
25
|
+
gem.add_development_dependency 'rspec'
|
26
|
+
gem.add_development_dependency 'guard'
|
27
|
+
gem.add_development_dependency 'guard-rspec'
|
28
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Job
|
4
|
+
extend Resque::Plugins::Approval
|
5
|
+
|
6
|
+
@queue = 'dummy'
|
7
|
+
|
8
|
+
def self.perform
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Resque::Plugins::Approval" do
|
13
|
+
before do
|
14
|
+
Resque.remove_queue(:dummy)
|
15
|
+
Resque.remove_queue(:approval_required)
|
16
|
+
Resque.redis.del('pending_jobs')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "is a valid Resque plugin" do
|
20
|
+
lambda { Resque::Plugin.lint(Resque::Plugins::Approval) }.should_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#pending_job_keys" do
|
24
|
+
it "lists keys (ordered by id) for all jobs that are waiting for approval" do
|
25
|
+
Job.enqueue_for_approval(:approval_message => 'test message 1')
|
26
|
+
Job.enqueue_for_approval
|
27
|
+
Job.enqueue_for_approval(:approval_message => 'test message 2')
|
28
|
+
|
29
|
+
keys = [{'id' => 0, 'approval_message' => 'test message 1'},
|
30
|
+
{'id' => 1},
|
31
|
+
{'id' => 2, 'approval_message' => 'test message 2'}]
|
32
|
+
Resque::Plugins::Approval.pending_job_keys.should == keys
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe ".before_enqueue_approval" do
|
37
|
+
context "when a job requires approval (via symbol or string)" do
|
38
|
+
it "calls enqueue_for_approval" do
|
39
|
+
Job.should_receive(:enqueue_for_approval).twice.with({})
|
40
|
+
Resque.enqueue(Job, :requires_approval => true)
|
41
|
+
Resque.enqueue(Job, 'requires_approval' => true)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when a job does not require approval" do
|
46
|
+
it "does not call enqueue_for_approval" do
|
47
|
+
Job.should_not_receive(:enqueue_for_approval)
|
48
|
+
Resque.enqueue(Job)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".enqueue_for_approval" do
|
54
|
+
it "adds the job to the appoval queue" do
|
55
|
+
Job.enqueue_for_approval
|
56
|
+
Resque.size(:approval_required).should == 1
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not add the job to the dummy queue" do
|
60
|
+
Job.enqueue_for_approval
|
61
|
+
Resque.size(:dummy).should == 0
|
62
|
+
end
|
63
|
+
|
64
|
+
it "adds an entry to the 'pending_jobs' hash" do
|
65
|
+
Job.enqueue_for_approval()
|
66
|
+
|
67
|
+
key = '{"id":0}'
|
68
|
+
value = '{"class":"Job","args":[{}]}'
|
69
|
+
|
70
|
+
Resque.redis.hget('pending_jobs', key).should == value
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with an approval message (via symbol)" do
|
74
|
+
it "includes the message in the 'pending_jobs' hash entry" do
|
75
|
+
Job.enqueue_for_approval(:approval_message => 'symbol test message')
|
76
|
+
|
77
|
+
key = '{"id":0,"approval_message":"symbol test message"}'
|
78
|
+
value = '{"class":"Job","args":[{}]}'
|
79
|
+
|
80
|
+
Resque.redis.hget('pending_jobs', key).should == value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with an approval message (via string)" do
|
85
|
+
it "includes the message in the 'pending_jobs' hash entry" do
|
86
|
+
Job.enqueue_for_approval('approval_message' => 'string test message')
|
87
|
+
|
88
|
+
key = '{"id":0,"approval_message":"string test message"}'
|
89
|
+
value = '{"class":"Job","args":[{}]}'
|
90
|
+
|
91
|
+
Resque.redis.hget('pending_jobs', key).should == value
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe ".approve" do
|
97
|
+
it "moves the job from the approval queue to its normal queue" do
|
98
|
+
key = '{"id":0}'
|
99
|
+
|
100
|
+
Resque.enqueue(Job, :requires_approval => true)
|
101
|
+
Job.approve(key)
|
102
|
+
|
103
|
+
Resque.size(:approval_required).should == 0
|
104
|
+
Resque.size(:dummy).should == 1
|
105
|
+
end
|
106
|
+
|
107
|
+
it "deletes the entry in the 'pending_jobs' hash" do
|
108
|
+
key = '{"id":0}'
|
109
|
+
|
110
|
+
Resque.enqueue(Job, :requires_approval => true)
|
111
|
+
Job.approve(key)
|
112
|
+
|
113
|
+
Resque.redis.hget('pending_jobs', key).should be_nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns false when key can not be found" do
|
117
|
+
Job.approve('bad key').should == false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe ".reject" do
|
122
|
+
it "deletes the job from the approval queue" do
|
123
|
+
key = '{"id":0}'
|
124
|
+
|
125
|
+
Resque.enqueue(Job, :requires_approval => true)
|
126
|
+
Job.reject(key)
|
127
|
+
|
128
|
+
Resque.size(:approval_required).should == 0
|
129
|
+
end
|
130
|
+
|
131
|
+
it "does not add the job to its normal queue" do
|
132
|
+
key = '{"id":0}'
|
133
|
+
|
134
|
+
Resque.enqueue(Job, :requires_approval => true)
|
135
|
+
Job.reject(key)
|
136
|
+
|
137
|
+
Resque.size(:dummy).should == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
it "deletes the entry in the 'pending_jobs' hash" do
|
141
|
+
key = '{"id":0}'
|
142
|
+
|
143
|
+
Resque.enqueue(Job, :requires_approval => true)
|
144
|
+
Job.reject(key)
|
145
|
+
|
146
|
+
Resque.redis.hget('pending_jobs', key).should be_nil
|
147
|
+
end
|
148
|
+
|
149
|
+
it "returns false when key can not be found" do
|
150
|
+
Job.reject('bad key').should == false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'resque-approval'
|
2
|
+
|
3
|
+
ROOT_PATH = File.expand_path('..', __FILE__)
|
4
|
+
TMP_PATH = '/tmp'
|
5
|
+
|
6
|
+
def start_redis
|
7
|
+
puts 'Starting redis for testing at localhost:9736...'
|
8
|
+
`redis-server #{ROOT_PATH}/redis-test.conf`
|
9
|
+
Resque.redis = 'localhost:9736'
|
10
|
+
sleep 0.1
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop_redis
|
14
|
+
puts "\nKilling test redis server..."
|
15
|
+
%x{
|
16
|
+
cat #{TMP_PATH}/redis-test.pid | xargs kill -QUIT
|
17
|
+
rm -f #{TMP_PATH}/redis-test-dump.rdb
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.before(:suite) do
|
23
|
+
start_redis
|
24
|
+
end
|
25
|
+
|
26
|
+
config.after(:suite) do
|
27
|
+
stop_redis
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-approval
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Earle Clubb
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: resque
|
16
|
+
requirement: &12740880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *12740880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &12740240 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *12740240
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &12739480 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *12739480
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: guard
|
49
|
+
requirement: &12737500 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *12737500
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: guard-rspec
|
60
|
+
requirement: &12732800 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *12732800
|
69
|
+
description: ! "A Resque plugin allowing jobs to be sent to a temporary\n queue
|
70
|
+
to await approval. Once the job is approved, it\n is placed
|
71
|
+
on its normal queue."
|
72
|
+
email:
|
73
|
+
- eclubb@valcom.com
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- Gemfile
|
80
|
+
- Guardfile
|
81
|
+
- LICENSE
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- lib/resque-approval.rb
|
85
|
+
- lib/resque-approval/version.rb
|
86
|
+
- resque-approval.gemspec
|
87
|
+
- spec/lib/resque-approval_spec.rb
|
88
|
+
- spec/redis-test.conf
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
homepage: https://github.com/eclubb/resque-approval
|
91
|
+
licenses: []
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.8.10
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: A Resque plugin allowing jobs to be sent to a temporary queue to await approval.
|
114
|
+
test_files:
|
115
|
+
- spec/lib/resque-approval_spec.rb
|
116
|
+
- spec/redis-test.conf
|
117
|
+
- spec/spec_helper.rb
|