stockpile-redis 1.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5265acd0adce155a74ad5e760a4220f2e67d21bd
4
+ data.tar.gz: a0255909976359af85261d59d10b9b7cf50fc256
5
+ SHA512:
6
+ metadata.gz: f4bcc22097af1e9ecda717d747a8462da5b7894ec795a27878a6f3bd44d6bd65eddba590b24f00064f20315f8f7be5bf6c44f5633f48824a620b431ab18a6880
7
+ data.tar.gz: 5878c2e4459ad15f96b65948d2b724c0bd7062dbe63d44db9b1329edb661558d7297f391c6540d328e3d130674ac860698fef53d46dc48f9534d87be90615c9b
@@ -0,0 +1,27 @@
1
+ # -*- ruby -*-
2
+
3
+ require "autotest/restart"
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ # .minitest.rb ensures that the gem version of minitest is used.
7
+ at.testlib = ".minitest.rb"
8
+ # at.testlib = "minitest/unit"
9
+ #
10
+ # at.extra_files << "../some/external/dependency.rb"
11
+ #
12
+ # at.libs << ":../some/external"
13
+ #
14
+ # at.add_exception "vendor"
15
+ #
16
+ # at.add_mapping(/dependency.rb/) do |f, _|
17
+ # at.files_matching(/test_.*rb$/)
18
+ # end
19
+ #
20
+ # %w(TestA TestB).each do |klass|
21
+ # at.extra_class_map[klass] = "test/test_misc.rb"
22
+ # end
23
+ end
24
+
25
+ # Autotest.add_hook :run_command do |at|
26
+ # system "rake build"
27
+ # end
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,2 @@
1
+ gem "minitest"
2
+ require "minitest/autorun"
@@ -0,0 +1,37 @@
1
+ ---
2
+ language: ruby
3
+ rvm:
4
+ - "2.2"
5
+ - "2.1"
6
+ - 2.0.0
7
+ - 1.9.3
8
+ - ruby-head
9
+ - jruby-19mode
10
+ - jruby-head
11
+ - rbx-2
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: rbx-2
15
+ - rvm: jruby-head
16
+ - rvm: ruby-head
17
+ gemfile:
18
+ - Gemfile
19
+ before_script:
20
+ - |
21
+ case "${TRAVIS_RUBY_VERSION}" in
22
+ rbx*)
23
+ gem install psych
24
+ ;;
25
+ esac
26
+ - rake travis:before -t
27
+ script: rake travis
28
+ after_script:
29
+ - rake travis:after -t
30
+ notifications:
31
+ email:
32
+ recipients:
33
+ - halostatue@gmail.com
34
+ on_success: change
35
+ on_failure: always
36
+ sudo:
37
+ false
@@ -0,0 +1,5 @@
1
+ #! zsh
2
+
3
+ --workenv-tab --first
4
+ --workenv-tab --desc autotest autotest
5
+ --workenv-tab --desc documents "fswatch -o *.rdoc lib/**/*.rb| xargs -n1 -I{} rake docs"
@@ -0,0 +1,64 @@
1
+ == Contributing
2
+
3
+ I value any contribution to stockpile-redis you can provide: a bug report, a
4
+ feature request, or code contributions.
5
+
6
+ As stockpile-redis is a complex codebase, there are a few guidelines:
7
+
8
+ * Changes *will* *not* be accepted without tests. The test suite is written
9
+ with {Minitest}[https://github.com/seattlerb/minitest].
10
+ * Match my coding style.
11
+ * Use a thoughtfully-named topic branch that contains your change. Rebase your
12
+ commits into logical chunks as necessary.
13
+ * Use {quality commit messages}[http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html].
14
+ * Do not change the version number; when your patch is accepted and a release
15
+ is made, the version will be updated at that point.
16
+ * Submit a GitHub pull request with your changes.
17
+ * New behaviours require new or updated documentation.
18
+
19
+ === Test Dependencies
20
+
21
+ stockpile-redis uses Ryan Davis’s {Hoe}[https://github.com/seattlerb/hoe]
22
+ to manage the release process, and it adds a number of rake tasks. You will
23
+ mostly be interested in:
24
+
25
+ $ rake
26
+
27
+ which runs the tests the same way that:
28
+
29
+ $ rake test
30
+ $ rake travis
31
+
32
+ will do.
33
+
34
+ To assist with the installation of the development dependencies for
35
+ stockpile-redis, I have provided the simplest possible Gemfile pointing to
36
+ the (generated) +stockpile-redis.gemspec+ file. This will permit you to do:
37
+
38
+ $ bundle install
39
+
40
+ to get the development dependencies. If you aleady have +hoe+ installed, you
41
+ can accomplish the same thing with:
42
+
43
+ $ rake newb
44
+
45
+ This task will install any missing dependencies, run the tests/specs, and
46
+ generate the RDoc.
47
+
48
+ === Workflow
49
+
50
+ Here's the most direct way to get your work merged into the project:
51
+
52
+ * Fork the project.
53
+ * Clone down your fork (<tt>git clone git://github.com/halostatue/stockpile-redis.git</tt>).
54
+ * Create a topic branch to contain your change (<tt>git checkout -b my\_awesome\_feature</tt>).
55
+ * Hack away, add tests. Not necessarily in that order.
56
+ * Make sure everything still passes by running +rake+.
57
+ * If necessary, rebase your commits into logical chunks, without errors.
58
+ * Push the branch up (<tt>git push origin my\_awesome\_feature</tt>).
59
+ * Create a pull request against halostatue/stockpile-redis and describe
60
+ what your change does and the why you think it should be merged.
61
+
62
+ === Contributors
63
+
64
+ * Austin Ziegler created stockpile-redis.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # -*- ruby -*-
2
+
3
+ # NOTE: This file is present to keep Travis CI happy. Edits to it will not
4
+ # be accepted.
5
+
6
+ source "https://rubygems.org/"
7
+ gemspec
8
+
9
+ # vim: syntax=ruby
@@ -0,0 +1,5 @@
1
+ === 1.0 / 2015-01-21
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
@@ -0,0 +1,27 @@
1
+ == Licence
2
+
3
+ This software is available under an MIT-style licence.
4
+
5
+ * Copyright 2015 Austin Ziegler
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
8
+ this software and associated documentation files (the "Software"), to deal in
9
+ the Software without restriction, including without limitation the rights to
10
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11
+ of the Software, and to permit persons to whom the Software is furnished to do
12
+ so, subject to the following conditions:
13
+
14
+ * The names of its contributors may not be used to endorse or promote
15
+ products derived from this software without specific prior written
16
+ permission.
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ .autotest
2
+ .gemtest
3
+ .minitest.rb
4
+ .travis.yml
5
+ .workenv
6
+ Contributing.rdoc
7
+ Gemfile
8
+ History.rdoc
9
+ Licence.rdoc
10
+ Manifest.txt
11
+ README.rdoc
12
+ Rakefile
13
+ lib/stockpile-redis.rb
14
+ lib/stockpile/redis.rb
15
+ test/minitest_config.rb
16
+ test/test_stockpile_adapter_redis.rb
17
+ test/test_stockpile_redis.rb
@@ -0,0 +1,118 @@
1
+ = stockpile-redis
2
+
3
+ code :: https://github.com/halostatue/stockpile-redis/
4
+ bugs :: https://github.com/halostatue/stockpile-redis/issues
5
+ continuous integration :: {<img src="https://travis-ci.org/halostatue/stockpile-redis.png" />}[https://travis-ci.org/halostatue/stockpile-redis]
6
+
7
+ == Description
8
+
9
+ stockpile-redis is a connection manager for Redis to be used with
10
+ {Stockpile}[https://github.com/halostatue/stockpile].
11
+
12
+ == Features
13
+
14
+ stockpile-redis supports both normal Redis connections (<tt>Redis.new</tt>),
15
+ and Redis::Namespace connections (<tt>Redis::Namespace.new('namespace', redis:
16
+ Redis.new</tt>).
17
+
18
+ stockpile-redis provides special-case handling for connections for Resque when
19
+ the name of the client is +:resque+.
20
+
21
+ == Synopsis
22
+
23
+ require 'stockpile/redis'
24
+
25
+ wide = Stockpile.new(manager: Stockpile::Redis) # A Stockpile to Redis.
26
+ wide.connection.set('hello', 'world') # => 'OK'
27
+ wide.connection.get('hello') # => 'world'
28
+
29
+ # Connections are independent from one another.
30
+ wide.connection_for(:other) != wide.connection # => true
31
+
32
+ # A 'narrow' Stockpile to Redis.
33
+ narrow = Stockpile.new(manager: Stockpile::Redis, narrow: true)
34
+ # Or set ENV['STOCKPILE_CONNECTION_WIDTH'] = 'narrow' and call Stockpile.new
35
+ # normally.
36
+ narrow.connection_for(:other) == narrow.connection # => true
37
+
38
+ # Special Redis::Namespace handling for Resque clients.
39
+ narrow.connection_for(:resque) != narrow.connection # => true
40
+ narrow.connection_for(:resque).redis == narrow.connection # => true
41
+
42
+ # Show a Stockpile with no adapter capabilities, but name the method
43
+ # stockpile, not cache. This will still usefully manage connections.
44
+ # The use of inject_redis! makes Stockpile::Redis the default connection
45
+ # manager for the Cacher module Stockpile.
46
+ module Cacher
47
+ Stockpile.inject_redis!(self, method: :stockpile, adaptable: false)
48
+ end
49
+ Cacher.respond_to?(:stockpile) # => true
50
+ Cacher.respond_to?(:stockpile_adapter) # => false
51
+ Cacher.stockpile.connection.set('hello', 'world') # => 'OK'
52
+ Cacher.stockpile.connection.get('hello') # => 'world'
53
+
54
+ # Now a Stockpile with adapter capabilities.
55
+ module Jobber
56
+ module LastRunTime
57
+ def last_run_time(key, value = nil)
58
+ if value
59
+ connection.hset(__method__, key, value.utc.iso8601)
60
+ else
61
+ value = connection.hget(__method__, key)
62
+ Time.parse(value) if value
63
+ end
64
+ end
65
+ end
66
+
67
+ Stockpile.inject_redis!(self)
68
+ end
69
+ Jobber.respond_to?(:cache) # => true
70
+ Jobber.respond_to?(:cache_adapter) # => true
71
+
72
+ # Four ways:
73
+ # 1. Adapt Jobber.cache to recognize #last_run_time.
74
+ Jobber.cache_adapter(Jobber::LastRunTime)
75
+ Jobber.cache.last_run_time('hello', t = Time.now) # => true
76
+ Jobber.cache.last_run_time('hello') # => approximately t
77
+
78
+ # 2. Adapt Jobber.cache and another module to recognize #last_run_time.
79
+ module Foo; end
80
+ Jobber.cache_adapter(Jobber::LastRunTime, Foo)
81
+ Foo.last_run_time('hello', t = Time.now) # => true
82
+ Foo.last_run_time('hello') # => approximately t
83
+
84
+ # 3. Adapt Jobber.cache and Jobber to recognize #last_run_time.
85
+ Jobber.cache_adapter(Jobber::LastRunTime, Jobber)
86
+ Jobber.last_run_time('hello', t = Time.now) # => true
87
+ Jobber.last_run_time('hello') # => approximately t
88
+
89
+ # 4. Adapt Jobber.cache and Jobber::LastRunTime to recognize #last_run_time.
90
+ Jobber.cache_adapter!(Jobber::LastRunTime)
91
+ # or Jobber.cache_adapter(Jobber::LastRunTime, Jobber::LastRunTime)
92
+ Jobber::LastRunTime.last_run_time('hello', t = Time.now) # => true
93
+ Jobber::LastRunTime.last_run_time('hello') # => approximately t
94
+
95
+ == Install
96
+
97
+ Put stockpile-redis in your Gemfile:
98
+
99
+ gem 'stockpile-redis', '~> 1.0'
100
+
101
+ Or manually install:
102
+
103
+ % gem install stockpile-redis
104
+
105
+ and require Stockpile in your code:
106
+
107
+ require 'stockpile/redis'
108
+
109
+ == stockpile-redis Semantic Versioning
110
+
111
+ stockpile-redis uses a {Semantic Versioning}[http://semver.org/] scheme with
112
+ one change:
113
+
114
+ * When PATCH is zero (+0+), it will be omitted from version references.
115
+
116
+ :include: Contributing.rdoc
117
+
118
+ :include: Licence.rdoc
@@ -0,0 +1,56 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :doofus
7
+ Hoe.plugin :gemspec2
8
+ Hoe.plugin :git
9
+ Hoe.plugin :minitest
10
+ Hoe.plugin :travis
11
+ Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
12
+
13
+ spec = Hoe.spec 'stockpile-redis' do
14
+ developer('Austin Ziegler', 'halostatue@gmail.com')
15
+
16
+ self.history_file = 'History.rdoc'
17
+ self.readme_file = 'README.rdoc'
18
+ self.extra_rdoc_files = FileList["*.rdoc"].to_a
19
+
20
+ license "MIT"
21
+
22
+ self.need_tar = true
23
+ self.require_ruby_version '>= 1.9.2'
24
+
25
+ self.extra_deps << ['stockpile', '~> 1.0']
26
+ self.extra_deps << ['redis', '~> 3.0']
27
+ self.extra_deps << ['redis-namespace', '~> 1.0']
28
+ self.extra_dev_deps << ['fakeredis', '~> 0.5']
29
+ self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
30
+ self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
31
+ self.extra_dev_deps << ['hoe-git', '~> 1.5']
32
+ self.extra_dev_deps << ['hoe-travis', '~> 1.2']
33
+ self.extra_dev_deps << ['minitest', '~> 5.4']
34
+ self.extra_dev_deps << ['minitest-around', '~> 0.3']
35
+ self.extra_dev_deps << ['minitest-autotest', '~> 1.0']
36
+ self.extra_dev_deps << ['minitest-bisect', '~> 1.2']
37
+ self.extra_dev_deps << ['minitest-focus', '~> 1.1']
38
+ self.extra_dev_deps << ['minitest-moar', '~> 0.0']
39
+ self.extra_dev_deps << ['minitest-pretty_diff', '~> 0.1']
40
+ self.extra_dev_deps << ['rake', '>= 10.0']
41
+ self.extra_dev_deps << ['redis-namespace', '~> 1.5']
42
+ self.extra_dev_deps << ['simplecov', '~> 0.7']
43
+ end
44
+
45
+ namespace :test do
46
+ task :coverage do
47
+ spec.test_prelude = [
48
+ 'require "simplecov"',
49
+ 'SimpleCov.start("test_frameworks") { command_name "Minitest" }',
50
+ 'gem "minitest"'
51
+ ].join('; ')
52
+ Rake::Task['test'].execute
53
+ end
54
+ end
55
+
56
+ # vim: syntax=ruby
@@ -0,0 +1 @@
1
+ require 'stockpile/redis'
@@ -0,0 +1,195 @@
1
+ # coding: utf-8
2
+
3
+ require 'redis'
4
+ require 'redis/namespace'
5
+ require 'stockpile'
6
+
7
+ class Stockpile
8
+ # A connection manager for Redis.
9
+ class Redis
10
+ VERSION = '1.0' # :nodoc:
11
+
12
+ # Create a new Redis connection manager with the provided options.
13
+ #
14
+ # == Options
15
+ #
16
+ # +redis+:: Provides the Redis connection options.
17
+ # +namespace+:: Provides the Redis namespace to use, but only if
18
+ # redis-namespace is in use (detected with the existence of
19
+ # Redis::Namespace).
20
+ #
21
+ # The namespace can also be provided as a key in the +redis+
22
+ # options if it is missing from the main options. If there is
23
+ # no namespace key present in either +options+ or
24
+ # <tt>options[:redis]</tt>, a namespace will be generated
25
+ # from one of the following: <tt>$REDIS_NAMESPACE</tt>,
26
+ # <tt>Rails.env</tt> (if in Rails), or <tt>$RACK_ENV</tt>.
27
+ # +narrow+:: Use a narrow connection width if true; if not provided,
28
+ # uses the value of ::Stockpile.narrow? in this connection
29
+ # manager.
30
+ def initialize(options = {})
31
+ @redis_options = options.fetch(:redis, {})
32
+ @narrow = !!options.fetch(:narrow, ::Stockpile.narrow?)
33
+ @namespace = options.fetch(:namespace) {
34
+ @redis_options.fetch(:namespace) {
35
+ ENV['REDIS_NAMESPACE'] ||
36
+ (defined?(::Rails) && ::Rails.env) ||
37
+ ENV['RACK_ENV']
38
+ }
39
+ }
40
+
41
+ if @redis_options.has_key?(:namespace)
42
+ @redis_options = @redis_options.reject { |k, _| k == :namespace }
43
+ end
44
+
45
+ @connection = nil
46
+ @clients = {}
47
+ end
48
+
49
+ # The current primary connection to Redis.
50
+ attr_reader :connection
51
+
52
+ # Indicates if this connection manager is using a narrow connection
53
+ # width.
54
+ def narrow?
55
+ @narrow
56
+ end
57
+
58
+ # Connect to Redis, unless already connected. Additional client connections
59
+ # can be specified in the parameters as a shorthand for calls to
60
+ # #connection_for.
61
+ #
62
+ # If #narrow? is true, the same Redis connection will be used for all
63
+ # clients managed by this connection manager.
64
+ #
65
+ # manager.connect
66
+ # manager.connection_for(:redis)
67
+ #
68
+ # # This means the same as above.
69
+ # manager.connect(:redis)
70
+ def connect(*client_names)
71
+ @connection ||= connect_for_any
72
+
73
+ clients_from(*client_names).each { |client_name|
74
+ connection_for(client_name)
75
+ }
76
+
77
+ connection
78
+ end
79
+
80
+ # Perform a client connection to Redis for a specific +client_name+. The
81
+ # +client_name+ of +:all+ will always return +nil+.
82
+ #
83
+ # If the requested client does not yet exist, the connection will be
84
+ # created.
85
+ #
86
+ # Because Resque depends on Redis::Namespace, #connection_for will perform
87
+ # special Redis::Namespace handling for a connection with the name
88
+ # +:resque+.
89
+ #
90
+ # If #narrow? is true, the same Redis connection will be shared between all
91
+ # clients.
92
+ #
93
+ # If a connection has not yet been made, it will be made.
94
+ def connection_for(client_name)
95
+ connect unless connection
96
+ return nil if client_name == :all
97
+ @clients[client_name] ||= case client_name
98
+ when :resque
99
+ connect_for_resque
100
+ else
101
+ connect_for_any
102
+ end
103
+ end
104
+
105
+ # Reconnect to Redis for some or all clients. The primary connection will
106
+ # always be reconnected; other clients will be reconnected based on the
107
+ # +clients+ provided. Only clients actively managed by previous calls to
108
+ # #connect or #connection_for will be reconnected.
109
+ #
110
+ # If #reconnect is called with the value +:all+, all currently managed
111
+ # clients will be reconnected.
112
+ #
113
+ # If #narrow? is true, only the primary connection will be reconnected.
114
+ def reconnect(*client_names)
115
+ return unless connection
116
+
117
+ connection.client.reconnect
118
+
119
+ unless narrow?
120
+ clients_from(*client_names).each { |client_name|
121
+ redis = @clients[client_name]
122
+ redis.client.reconnect if redis
123
+ }
124
+ end
125
+
126
+ connection
127
+ end
128
+
129
+ # Disconnect from Redis for some or all clients. The primary connection
130
+ # will always be disconnected; other clients will be disconnected based on
131
+ # the +clients+ provided. Only clients actively managed by previous calls
132
+ # to #connect or #connection_for will be disconnected.
133
+ #
134
+ # If #disconnect is called with the value +:all+, all currently managed
135
+ # clients will be disconnected.
136
+ #
137
+ # If #narrow? is true, only the primary connection will be disconnected.
138
+ def disconnect(*client_names)
139
+ return unless connection
140
+
141
+ unless narrow?
142
+ clients_from(*client_names).each { |client_name|
143
+ redis = @clients[client_name]
144
+ redis.quit if redis
145
+ }
146
+ end
147
+
148
+ connection.quit
149
+ end
150
+
151
+ private
152
+ def clients_from(*client_names)
153
+ if client_names.size == 1
154
+ if client_names.first == :all
155
+ @clients.keys
156
+ else
157
+ client_names
158
+ end
159
+ else
160
+ client_names
161
+ end
162
+ end
163
+
164
+ def connect_for_any
165
+ return connection if connection && narrow?
166
+
167
+ r = ::Redis.new(@redis_options)
168
+ if @namespace
169
+ r = ::Redis::Namespace.new(@namespace, redis: r)
170
+ end
171
+ r
172
+ end
173
+
174
+ def connect_for_resque
175
+ r = connect_for_any
176
+
177
+ if r.instance_of?(::Redis::Namespace) && r.namespace.to_s !~ /:resque\z/
178
+ r = ::Redis::Namespace.new(:"#{r.namespace}:resque", redis: r.redis)
179
+ elsif r.instance_of?(::Redis)
180
+ r = ::Redis::Namespace.new("resque", redis: r)
181
+ end
182
+
183
+ r
184
+ end
185
+ end
186
+
187
+ # Enables module or class +mod+ to contain a Stockpile instance that defaults
188
+ # the created +cache+ method to using Stockpile::Redis as the key-value store
189
+ # connection manager.
190
+ #
191
+ # See <tt>Stockpile.inject!</tt>.
192
+ def self.inject_redis!(mod, options = {})
193
+ inject!(mod, options.merge(default_manager: Stockpile::Redis))
194
+ end
195
+ end
@@ -0,0 +1,41 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ gem 'minitest'
4
+ require 'minitest/autorun'
5
+ require 'minitest/pretty_diff'
6
+ require 'minitest/focus'
7
+ require 'minitest/moar'
8
+ require 'minitest/bisect'
9
+
10
+ require 'fakeredis'
11
+
12
+ module Minitest::FakeRedis
13
+ def setup
14
+ super
15
+ Redis::Connection::Memory.reset_all_databases
16
+ end
17
+
18
+ Minitest::Test.send(:include, self)
19
+ end
20
+
21
+ module Minitest::ENVStub
22
+ def stub_env env, options = {}, *block_args, &block
23
+ mock = lambda { |key|
24
+ env.fetch(key) { |k|
25
+ if options[:passthrough]
26
+ ENV.send(:"__minitest_stub__[]", k)
27
+ else
28
+ nil
29
+ end
30
+ }
31
+ }
32
+
33
+ if defined? Minitest::Moar::Stubbing
34
+ stub ENV, :[], mock, *block_args, &block
35
+ else
36
+ ENV.stub :[], mock, *block_args, &block
37
+ end
38
+ end
39
+
40
+ Minitest::Test.send(:include, self)
41
+ end
@@ -0,0 +1,47 @@
1
+ require 'minitest_config'
2
+ require 'stockpile/redis'
3
+ require 'time'
4
+
5
+ describe Stockpile do
6
+ describe ".inject!" do
7
+ let(:mod) { Module.new }
8
+ let(:lrt) {
9
+ Module.new do
10
+ def last_run_time(key, value = nil)
11
+ if value
12
+ connection.hset(__method__, key, value.utc.iso8601)
13
+ else
14
+ value = connection.hget(__method__, key)
15
+ Time.parse(value) if value
16
+ end
17
+ end
18
+ end
19
+ }
20
+
21
+ describe "Mod.cache_adapter" do
22
+ let(:now) { Time.now }
23
+ before { ::Stockpile.inject_redis!(mod, adaptable: true) }
24
+
25
+ it "adapts the cache with last_run_time" do
26
+ mod.cache_adapter(lrt)
27
+ assert_nil mod.cache.last_run_time('foo')
28
+ assert_equal true, mod.cache.last_run_time('foo', now)
29
+ assert_equal now.to_i, mod.cache.last_run_time('foo').to_i
30
+ end
31
+
32
+ it "adapts the module with last_run_time" do
33
+ mod.cache_adapter(lrt, mod)
34
+ assert_nil mod.last_run_time('foo')
35
+ assert_equal true, mod.last_run_time('foo', now)
36
+ assert_equal now.to_i, mod.last_run_time('foo').to_i
37
+ end
38
+
39
+ it "adapts the lrt module with last_run_time" do
40
+ mod.cache_adapter!(lrt)
41
+ assert_nil lrt.last_run_time('foo')
42
+ assert_equal true, lrt.last_run_time('foo', now)
43
+ assert_equal now.to_i, lrt.last_run_time('foo').to_i
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,281 @@
1
+ require 'minitest_config'
2
+ require 'stockpile/redis'
3
+
4
+ describe Stockpile::Redis do
5
+ def assert_clients expected_clients, connector
6
+ actual_clients = connector.instance_variable_get(:@clients).keys
7
+ assert_equal actual_clients.sort, expected_clients.sort
8
+ end
9
+
10
+ let(:rcm) { stub_env({}) { Stockpile::Redis.new } }
11
+ let(:rcm_namespace) { stub_env({}) { Stockpile::Redis.new(namespace: 'Z') } }
12
+ let(:rcm_wide) { stub_env({}) { Stockpile::Redis.new(narrow: false) } }
13
+ let(:rcm_narrow) { stub_env({}) { Stockpile::Redis.new(narrow: true) } }
14
+
15
+ describe 'constructor' do
16
+ it "uses the default connection width by default" do
17
+ stub ::Stockpile, :narrow?, lambda { false } do
18
+ refute Stockpile::Redis.new.narrow?,
19
+ "should be narrow, but is not"
20
+ end
21
+
22
+ stub ::Stockpile, :narrow?, lambda { true } do
23
+ assert Stockpile::Redis.new.narrow?,
24
+ "is not narrow, but should be"
25
+ end
26
+ end
27
+
28
+ it "can be told which connection width to use explicitly" do
29
+ stub ::Stockpile, :narrow?, lambda { false } do
30
+ assert rcm_narrow.narrow?
31
+ end
32
+
33
+ stub ::Stockpile, :narrow?, lambda { true } do
34
+ refute rcm_wide.narrow?
35
+ end
36
+ end
37
+
38
+ it "passes settings through to Redis" do
39
+ options = {
40
+ redis: {
41
+ url: 'redis://xyz/'
42
+ }
43
+ }
44
+ rcm = ::Stockpile::Redis.new(options)
45
+ assert_equal 'xyz', rcm.connect.client.options[:host]
46
+ end
47
+
48
+ it "has no clients by default" do
49
+ assert_clients [], ::Stockpile::Redis.new
50
+ end
51
+
52
+ describe "namespace support" do
53
+ def assert_namespace(client)
54
+ assert_equal 'stockpile', client.instance_variable_get(:@namespace)
55
+ end
56
+
57
+ it "will set namespace from ENV['REDIS_NAMESPACE']" do
58
+ stub_env({ 'REDIS_NAMESPACE' => 'stockpile' }) do
59
+ assert_namespace ::Stockpile::Redis.new
60
+ end
61
+ end
62
+
63
+ it "will set namespace from Rails.env" do
64
+ begin
65
+ ::Rails = Class.new do
66
+ def self.env
67
+ 'stockpile'
68
+ end
69
+ end
70
+
71
+ stub_env({}) do
72
+ assert_namespace ::Stockpile::Redis.new
73
+ end
74
+ ensure
75
+ Object.send(:remove_const, :Rails)
76
+ end
77
+ end
78
+
79
+ it "will set namespace from ENV['RACK_ENV']" do
80
+ stub_env({ 'RACK_ENV' => 'stockpile' }) do
81
+ assert_namespace ::Stockpile::Redis.new
82
+ end
83
+ end
84
+
85
+ it "will set namespace from parameters" do
86
+ stub_env({ 'RACK_ENV' => 'test' }) do
87
+ assert_namespace ::Stockpile::Redis.new(namespace: 'stockpile')
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#connect" do
94
+ it "creates a connection to Redis" do
95
+ assert_nil rcm.connection
96
+ refute_nil rcm.connect
97
+ assert_kind_of ::Redis, rcm.connection
98
+ end
99
+
100
+ it "creates a namespaced connection to Redis" do
101
+ assert_nil rcm_namespace.connection
102
+ refute_nil rcm_namespace.connect
103
+ assert_kind_of ::Redis::Namespace, rcm_namespace.connection
104
+ end
105
+
106
+ describe "with a wide connection width" do
107
+ before do
108
+ rcm_wide.connect(:redis, :rollout)
109
+ end
110
+
111
+ it "connects multiple clients" do
112
+ assert_clients [ :redis, :rollout ], rcm_wide
113
+ end
114
+
115
+ it "connects *different* clients" do
116
+ refute_same rcm_wide.connection, rcm_wide.connection_for(:redis)
117
+ refute_same rcm_wide.connection, rcm_wide.connection_for(:rollout)
118
+ refute_same rcm_wide.connection_for(:redis), rcm_wide.connection_for(:rollout)
119
+ end
120
+ end
121
+
122
+ describe "with a narrow connection width" do
123
+ before do
124
+ rcm_narrow.connect(:redis, :rollout)
125
+ end
126
+
127
+ it "appears to connect multiple clients" do
128
+ assert_clients [ :redis, :rollout ], rcm_narrow
129
+ end
130
+
131
+ it "returns identical clients" do
132
+ assert_same rcm_narrow.connection, rcm_narrow.connection_for(:redis)
133
+ assert_same rcm_narrow.connection, rcm_narrow.connection_for(:rollout)
134
+ assert_same rcm_narrow.connection_for(:redis), rcm_narrow.connection_for(:rollout)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "#connection_for" do
140
+ describe "with a wide connection width" do
141
+ it "connects the main client" do
142
+ rcm_wide.connection_for(:global)
143
+ assert rcm_wide.connection
144
+ refute_same rcm_wide.connection, rcm_wide.connection_for(:global)
145
+ end
146
+
147
+ it "wraps a :resque client in Redis::Namespace" do
148
+ assert_kind_of Redis::Namespace, rcm_wide.connection_for(:resque)
149
+ assert_equal "resque", rcm_wide.connection_for(:resque).namespace
150
+ end
151
+ end
152
+
153
+ describe "with a narrow connection width" do
154
+ it "connects the main client" do
155
+ rcm_narrow.connection_for(:global)
156
+ assert rcm_narrow.connection
157
+ assert_same rcm_narrow.connection, rcm_narrow.connection_for(:global)
158
+ end
159
+
160
+ it "wraps a :resque client in Redis::Namespace" do
161
+ assert_kind_of Redis::Namespace, rcm_narrow.connection_for(:resque)
162
+ end
163
+ end
164
+ end
165
+
166
+ # #disconnect cannot be tested with FakeRedis because the FakeRedis
167
+ # #connected? method always returns true.
168
+ describe "#disconnect" do
169
+ describe "with a wide connection width" do
170
+ let(:global) { rcm_wide.connection }
171
+ let(:redis) { rcm_wide.connection_for(:redis) }
172
+
173
+ def force_connection
174
+ rcm_wide.connect(:redis)
175
+ global.client.connect
176
+ redis.client.connect
177
+ end
178
+
179
+ it "disconnects the global client" do
180
+ instance_stub Redis, :quit do
181
+ force_connection
182
+ rcm_wide.disconnect
183
+ end
184
+ assert_instance_called Redis, :quit, 1
185
+ end
186
+
187
+ it "disconnects the redis and global clients" do
188
+ instance_stub Redis, :quit do
189
+ force_connection
190
+ rcm_wide.disconnect(:redis)
191
+ end
192
+ assert_instance_called Redis, :quit, 2
193
+ end
194
+ end
195
+
196
+ describe "with a narrow connection width" do
197
+ let(:global) { rcm_narrow.connection }
198
+ let(:redis) { rcm_narrow.connection_for(:redis) }
199
+
200
+ def force_connection
201
+ rcm_narrow.connect(:redis)
202
+ global.client.connect
203
+ redis.client.connect
204
+ end
205
+
206
+ it "disconnects the global client" do
207
+ instance_stub Redis, :quit do
208
+ force_connection
209
+ rcm_narrow.disconnect
210
+ end
211
+ assert_instance_called Redis, :quit, 1
212
+ end
213
+
214
+ it "disconnects the redis and global clients" do
215
+ instance_stub Redis, :quit do
216
+ force_connection
217
+ rcm_narrow.disconnect(:redis)
218
+ end
219
+ assert_instance_called Redis, :quit, 1
220
+ end
221
+ end
222
+ end
223
+
224
+ # #reconnect cannot be tested with FakeRedis because the FakeRedis
225
+ # #connected? method always returns true.
226
+ describe "#reconnect" do
227
+ describe "with a wide connection width" do
228
+ let(:global) { rcm_wide.connection }
229
+ let(:redis) { rcm_wide.connection_for(:redis) }
230
+
231
+ def force_connection
232
+ rcm_wide.connect(:redis)
233
+ global.client.connect
234
+ redis.client.connect
235
+ end
236
+
237
+ it "reconnects the global client" do
238
+ instance_stub Redis::Client, :reconnect do
239
+ force_connection
240
+ rcm_wide.reconnect
241
+ end
242
+ assert_instance_called Redis::Client, :reconnect, 1
243
+ end
244
+
245
+ it "reconnects the redis and global clients" do
246
+ instance_stub Redis::Client, :reconnect do
247
+ force_connection
248
+ rcm_wide.reconnect(:redis)
249
+ end
250
+ assert_instance_called Redis::Client, :reconnect, 2
251
+ end
252
+ end
253
+
254
+ describe "with a narrow connection width" do
255
+ let(:global) { rcm_narrow.connection }
256
+ let(:redis) { rcm_narrow.connection_for(:redis) }
257
+
258
+ def force_connection
259
+ rcm_narrow.connect(:redis)
260
+ global.client.connect
261
+ redis.client.connect
262
+ end
263
+
264
+ it "reconnects the global client" do
265
+ instance_stub Redis::Client, :reconnect do
266
+ force_connection
267
+ rcm_narrow.reconnect
268
+ end
269
+ assert_instance_called Redis::Client, :reconnect, 1
270
+ end
271
+
272
+ it "reconnects the redis and global clients" do
273
+ instance_stub Redis::Client, :reconnect do
274
+ force_connection
275
+ rcm_narrow.reconnect(:redis)
276
+ end
277
+ assert_instance_called Redis::Client, :reconnect, 1
278
+ end
279
+ end
280
+ end
281
+ end
metadata ADDED
@@ -0,0 +1,338 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stockpile-redis
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Austin Ziegler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: stockpile
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis-namespace
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakeredis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hoe-doofus
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: hoe-gemspec2
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.1'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.1'
125
+ - !ruby/object:Gem::Dependency
126
+ name: hoe-git
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.5'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.5'
139
+ - !ruby/object:Gem::Dependency
140
+ name: hoe-travis
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.2'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: minitest-around
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.3'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.3'
167
+ - !ruby/object:Gem::Dependency
168
+ name: minitest-autotest
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: minitest-bisect
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '1.2'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '1.2'
195
+ - !ruby/object:Gem::Dependency
196
+ name: minitest-focus
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '1.1'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '1.1'
209
+ - !ruby/object:Gem::Dependency
210
+ name: minitest-moar
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '0.0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '0.0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: minitest-pretty_diff
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '0.1'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: '0.1'
237
+ - !ruby/object:Gem::Dependency
238
+ name: rake
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '10.0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '10.0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: simplecov
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: '0.7'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: '0.7'
265
+ - !ruby/object:Gem::Dependency
266
+ name: hoe
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - "~>"
270
+ - !ruby/object:Gem::Version
271
+ version: '3.13'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - "~>"
277
+ - !ruby/object:Gem::Version
278
+ version: '3.13'
279
+ description: |-
280
+ stockpile-redis is a connection manager for Redis to be used with
281
+ {Stockpile}[https://github.com/halostatue/stockpile].
282
+ email:
283
+ - halostatue@gmail.com
284
+ executables: []
285
+ extensions: []
286
+ extra_rdoc_files:
287
+ - Contributing.rdoc
288
+ - History.rdoc
289
+ - Licence.rdoc
290
+ - Manifest.txt
291
+ - README.rdoc
292
+ files:
293
+ - ".autotest"
294
+ - ".gemtest"
295
+ - ".minitest.rb"
296
+ - ".travis.yml"
297
+ - ".workenv"
298
+ - Contributing.rdoc
299
+ - Gemfile
300
+ - History.rdoc
301
+ - Licence.rdoc
302
+ - Manifest.txt
303
+ - README.rdoc
304
+ - Rakefile
305
+ - lib/stockpile-redis.rb
306
+ - lib/stockpile/redis.rb
307
+ - test/minitest_config.rb
308
+ - test/test_stockpile_adapter_redis.rb
309
+ - test/test_stockpile_redis.rb
310
+ homepage: https://github.com/halostatue/stockpile-redis/
311
+ licenses:
312
+ - MIT
313
+ metadata: {}
314
+ post_install_message:
315
+ rdoc_options:
316
+ - "--main"
317
+ - README.rdoc
318
+ require_paths:
319
+ - lib
320
+ required_ruby_version: !ruby/object:Gem::Requirement
321
+ requirements:
322
+ - - ">="
323
+ - !ruby/object:Gem::Version
324
+ version: 1.9.2
325
+ required_rubygems_version: !ruby/object:Gem::Requirement
326
+ requirements:
327
+ - - ">="
328
+ - !ruby/object:Gem::Version
329
+ version: '0'
330
+ requirements: []
331
+ rubyforge_project:
332
+ rubygems_version: 2.2.2
333
+ signing_key:
334
+ specification_version: 4
335
+ summary: stockpile-redis is a connection manager for Redis to be used with {Stockpile}[https://github.com/halostatue/stockpile].
336
+ test_files:
337
+ - test/test_stockpile_adapter_redis.rb
338
+ - test/test_stockpile_redis.rb