flipper-redis 0.10.2 → 0.11.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/flipper-redis.gemspec +11 -11
- data/lib/flipper/adapters/redis.rb +11 -10
- data/lib/flipper/adapters/redis_cache.rb +129 -0
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/redis_cache_spec.rb +64 -0
- data/spec/flipper/adapters/redis_spec.rb +3 -5
- data/test/adapters/redis_cache_test.rb +18 -0
- data/test/adapters/redis_test.rb +3 -2
- metadata +12 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdeb25654096e05e254effadaec3e4172f5017a4
|
4
|
+
data.tar.gz: 3ce4cde5901b75e961137eddc00023e0d7ee6f5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5c985b97209b5b20cbe053da4c0c2fecdf40ab1f9287fdefc9094b198d3457e8f0464527a2b79098ada13f6eb5e07ec461eac2698c3a76529710f5bc81709ce
|
7
|
+
data.tar.gz: ec607bd967b5d16568b4507bca7b80d2d11937b8feaf4776a38258764202207d878c4e49d5901fbe61b688f4e6e40939ea651db2c49484068cd204b2afc1ff10
|
data/flipper-redis.gemspec
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require File.expand_path('../lib/flipper/version', __FILE__)
|
3
3
|
|
4
|
-
flipper_redis_files = lambda
|
4
|
+
flipper_redis_files = lambda do |file|
|
5
5
|
file =~ /redis/
|
6
|
-
|
6
|
+
end
|
7
7
|
|
8
8
|
Gem::Specification.new do |gem|
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
11
|
-
gem.summary =
|
12
|
-
gem.description =
|
13
|
-
gem.license =
|
14
|
-
gem.homepage =
|
9
|
+
gem.authors = ['John Nunemaker']
|
10
|
+
gem.email = ['nunemaker@gmail.com']
|
11
|
+
gem.summary = 'Redis adapter for Flipper'
|
12
|
+
gem.description = 'Redis adapter for Flipper'
|
13
|
+
gem.license = 'MIT'
|
14
|
+
gem.homepage = 'https://github.com/jnunemaker/flipper'
|
15
15
|
|
16
|
-
gem.files = `git ls-files`.split("\n").select(&flipper_redis_files) + [
|
16
|
+
gem.files = `git ls-files`.split("\n").select(&flipper_redis_files) + ['lib/flipper/version.rb']
|
17
17
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").select(&flipper_redis_files)
|
18
|
-
gem.name =
|
19
|
-
gem.require_paths = [
|
18
|
+
gem.name = 'flipper-redis'
|
19
|
+
gem.require_paths = ['lib']
|
20
20
|
gem.version = Flipper::VERSION
|
21
21
|
|
22
22
|
gem.add_dependency 'flipper', "~> #{Flipper::VERSION}"
|
@@ -68,7 +68,7 @@ module Flipper
|
|
68
68
|
#
|
69
69
|
# feature - The Flipper::Feature for the gate.
|
70
70
|
# gate - The Flipper::Gate to disable.
|
71
|
-
# thing - The Flipper::Type being
|
71
|
+
# thing - The Flipper::Type being enabled for the gate.
|
72
72
|
#
|
73
73
|
# Returns true.
|
74
74
|
def enable(feature, gate, thing)
|
@@ -126,14 +126,15 @@ module Flipper
|
|
126
126
|
fields = doc.keys
|
127
127
|
|
128
128
|
feature.gates.each do |gate|
|
129
|
-
result[gate.key] =
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
129
|
+
result[gate.key] =
|
130
|
+
case gate.data_type
|
131
|
+
when :boolean, :integer
|
132
|
+
doc[gate.key.to_s]
|
133
|
+
when :set
|
134
|
+
fields_to_gate_value fields, gate
|
135
|
+
else
|
136
|
+
unsupported_data_type gate.data_type
|
137
|
+
end
|
137
138
|
end
|
138
139
|
|
139
140
|
result
|
@@ -148,7 +149,7 @@ module Flipper
|
|
148
149
|
#
|
149
150
|
# Returns a Set of the values enabled for the gate.
|
150
151
|
def fields_to_gate_value(fields, gate)
|
151
|
-
regex =
|
152
|
+
regex = %r{^#{Regexp.escape(gate.key.to_s)}/}
|
152
153
|
keys = fields.grep(regex)
|
153
154
|
values = keys.map { |key| key.split('/', 2).last }
|
154
155
|
values.to_set
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Flipper
|
4
|
+
module Adapters
|
5
|
+
# Public: Adapter that wraps another adapter with the ability to cache
|
6
|
+
# adapter calls in Redis
|
7
|
+
class RedisCache
|
8
|
+
include ::Flipper::Adapter
|
9
|
+
|
10
|
+
Version = 'v1'.freeze
|
11
|
+
Namespace = "flipper/#{Version}".freeze
|
12
|
+
FeaturesKey = "#{Namespace}/features".freeze
|
13
|
+
|
14
|
+
# Private
|
15
|
+
def self.key_for(key)
|
16
|
+
"#{Namespace}/feature/#{key}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal
|
20
|
+
attr_reader :cache
|
21
|
+
|
22
|
+
# Public: The name of the adapter.
|
23
|
+
attr_reader :name
|
24
|
+
|
25
|
+
# Public
|
26
|
+
def initialize(adapter, cache, ttl = 3600)
|
27
|
+
@adapter = adapter
|
28
|
+
@name = :redis_cache
|
29
|
+
@cache = cache
|
30
|
+
@ttl = ttl
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public
|
34
|
+
def features
|
35
|
+
fetch(FeaturesKey) do
|
36
|
+
@adapter.features
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Public
|
41
|
+
def add(feature)
|
42
|
+
result = @adapter.add(feature)
|
43
|
+
@cache.del(FeaturesKey)
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public
|
48
|
+
def remove(feature)
|
49
|
+
result = @adapter.remove(feature)
|
50
|
+
@cache.del(FeaturesKey)
|
51
|
+
@cache.del(key_for(feature.key))
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public
|
56
|
+
def clear(feature)
|
57
|
+
result = @adapter.clear(feature)
|
58
|
+
@cache.del(key_for(feature.key))
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
# Public
|
63
|
+
def get(feature)
|
64
|
+
fetch(key_for(feature.key)) do
|
65
|
+
@adapter.get(feature)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_multi(features)
|
70
|
+
keys = features.map(&:key)
|
71
|
+
result = Hash[keys.zip(multi_cache_get(keys))]
|
72
|
+
uncached_features = features.reject do |feature|
|
73
|
+
result[feature.key]
|
74
|
+
end
|
75
|
+
|
76
|
+
if uncached_features.any?
|
77
|
+
response = @adapter.get_multi(uncached_features)
|
78
|
+
response.each do |key, value|
|
79
|
+
set_with_ttl(key_for(key), value)
|
80
|
+
result[key] = value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
# Public
|
87
|
+
def enable(feature, gate, thing)
|
88
|
+
result = @adapter.enable(feature, gate, thing)
|
89
|
+
@cache.del(key_for(feature.key))
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
# Public
|
94
|
+
def disable(feature, gate, thing)
|
95
|
+
result = @adapter.disable(feature, gate, thing)
|
96
|
+
@cache.del(key_for(feature.key))
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def key_for(key)
|
103
|
+
self.class.key_for(key)
|
104
|
+
end
|
105
|
+
|
106
|
+
def fetch(key)
|
107
|
+
cached = @cache.get(key)
|
108
|
+
if cached
|
109
|
+
Marshal.load(cached)
|
110
|
+
else
|
111
|
+
to_cache = yield
|
112
|
+
set_with_ttl(key, to_cache)
|
113
|
+
to_cache
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def set_with_ttl(key, value)
|
118
|
+
@cache.setex(key, @ttl, Marshal.dump(value))
|
119
|
+
end
|
120
|
+
|
121
|
+
def multi_cache_get(keys)
|
122
|
+
cache_keys = keys.map { |key| key_for(key) }
|
123
|
+
@cache.mget(cache_keys).map do |value|
|
124
|
+
value ? Marshal.load(value) : nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/flipper/version.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'flipper/adapters/memory'
|
3
|
+
require 'flipper/adapters/redis_cache'
|
4
|
+
require 'flipper/spec/shared_adapter_specs'
|
5
|
+
|
6
|
+
RSpec.describe Flipper::Adapters::RedisCache do
|
7
|
+
let(:client) do
|
8
|
+
options = {}
|
9
|
+
|
10
|
+
options[:url] = ENV['BOXEN_REDIS_URL'] if ENV['BOXEN_REDIS_URL']
|
11
|
+
|
12
|
+
Redis.new(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:memory_adapter) { Flipper::Adapters::Memory.new }
|
16
|
+
let(:cache) { Redis.new(url: ENV.fetch('BOXEN_REDIS_URL', 'redis://localhost:6379')) }
|
17
|
+
let(:adapter) { described_class.new(memory_adapter, cache) }
|
18
|
+
let(:flipper) { Flipper.new(adapter) }
|
19
|
+
|
20
|
+
subject { adapter }
|
21
|
+
|
22
|
+
before do
|
23
|
+
client.flushdb
|
24
|
+
end
|
25
|
+
|
26
|
+
it_should_behave_like 'a flipper adapter'
|
27
|
+
|
28
|
+
describe '#remove' do
|
29
|
+
it 'expires feature' do
|
30
|
+
feature = flipper[:stats]
|
31
|
+
adapter.get(feature)
|
32
|
+
adapter.remove(feature)
|
33
|
+
expect(cache.get(described_class.key_for(feature))).to be(nil)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#get_multi' do
|
38
|
+
it 'warms uncached features' do
|
39
|
+
stats = flipper[:stats]
|
40
|
+
search = flipper[:search]
|
41
|
+
other = flipper[:other]
|
42
|
+
stats.enable
|
43
|
+
search.enable
|
44
|
+
|
45
|
+
adapter.get(stats)
|
46
|
+
expect(cache.get(described_class.key_for(search))).to be(nil)
|
47
|
+
expect(cache.get(described_class.key_for(other))).to be(nil)
|
48
|
+
|
49
|
+
adapter.get_multi([stats, search, other])
|
50
|
+
|
51
|
+
search_cache_value, other_cache_value = [search, other].map do |f|
|
52
|
+
Marshal.load(cache.get(described_class.key_for(f)))
|
53
|
+
end
|
54
|
+
expect(search_cache_value[:boolean]).to eq('true')
|
55
|
+
expect(other_cache_value[:boolean]).to be(nil)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#name' do
|
60
|
+
it 'is redis_cache' do
|
61
|
+
expect(subject.name).to be(:redis_cache)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -3,15 +3,13 @@ require 'flipper/adapters/redis'
|
|
3
3
|
require 'flipper/spec/shared_adapter_specs'
|
4
4
|
|
5
5
|
RSpec.describe Flipper::Adapters::Redis do
|
6
|
-
let(:client)
|
6
|
+
let(:client) do
|
7
7
|
options = {}
|
8
8
|
|
9
|
-
if ENV['BOXEN_REDIS_URL']
|
10
|
-
options[:url] = ENV['BOXEN_REDIS_URL']
|
11
|
-
end
|
9
|
+
options[:url] = ENV['BOXEN_REDIS_URL'] if ENV['BOXEN_REDIS_URL']
|
12
10
|
|
13
11
|
Redis.new(options)
|
14
|
-
|
12
|
+
end
|
15
13
|
|
16
14
|
subject { described_class.new(client) }
|
17
15
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'flipper/adapters/memory'
|
3
|
+
require 'flipper/adapters/redis_cache'
|
4
|
+
|
5
|
+
class DalliTest < MiniTest::Test
|
6
|
+
prepend Flipper::Test::SharedAdapterTests
|
7
|
+
|
8
|
+
def setup
|
9
|
+
url = ENV.fetch('BOXEN_REDIS_URL', 'redis://localhost:6379')
|
10
|
+
@cache = Redis.new(url: url).tap(&:flushdb)
|
11
|
+
memory_adapter = Flipper::Adapters::Memory.new
|
12
|
+
@adapter = Flipper::Adapters::RedisCache.new(memory_adapter, @cache)
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
@cache.flushdb
|
17
|
+
end
|
18
|
+
end
|
data/test/adapters/redis_test.rb
CHANGED
@@ -5,7 +5,8 @@ class RedisTest < MiniTest::Test
|
|
5
5
|
prepend Flipper::Test::SharedAdapterTests
|
6
6
|
|
7
7
|
def setup
|
8
|
-
|
9
|
-
|
8
|
+
url = ENV.fetch('BOXEN_REDIS_URL', 'redis://localhost:6379')
|
9
|
+
client = Redis.new(url: url).tap(&:flushdb)
|
10
|
+
@adapter = Flipper::Adapters::Redis.new(client)
|
10
11
|
end
|
11
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: flipper
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.11.0.beta1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.11.0.beta1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: redis
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,8 +58,11 @@ files:
|
|
58
58
|
- flipper-redis.gemspec
|
59
59
|
- lib/flipper-redis.rb
|
60
60
|
- lib/flipper/adapters/redis.rb
|
61
|
+
- lib/flipper/adapters/redis_cache.rb
|
61
62
|
- lib/flipper/version.rb
|
63
|
+
- spec/flipper/adapters/redis_cache_spec.rb
|
62
64
|
- spec/flipper/adapters/redis_spec.rb
|
65
|
+
- test/adapters/redis_cache_test.rb
|
63
66
|
- test/adapters/redis_test.rb
|
64
67
|
homepage: https://github.com/jnunemaker/flipper
|
65
68
|
licenses:
|
@@ -76,15 +79,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
79
|
version: '0'
|
77
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
81
|
requirements:
|
79
|
-
- - "
|
82
|
+
- - ">"
|
80
83
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
84
|
+
version: 1.3.1
|
82
85
|
requirements: []
|
83
86
|
rubyforge_project:
|
84
|
-
rubygems_version: 2.
|
87
|
+
rubygems_version: 2.5.2
|
85
88
|
signing_key:
|
86
89
|
specification_version: 4
|
87
90
|
summary: Redis adapter for Flipper
|
88
91
|
test_files:
|
92
|
+
- spec/flipper/adapters/redis_cache_spec.rb
|
89
93
|
- spec/flipper/adapters/redis_spec.rb
|
94
|
+
- test/adapters/redis_cache_test.rb
|
90
95
|
- test/adapters/redis_test.rb
|