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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a13a83c0fcc0c673d0ec7f0eb384006701dda61
4
- data.tar.gz: bd58070c270efaa9b84621e654e1f61e3dc2b027
3
+ metadata.gz: fdeb25654096e05e254effadaec3e4172f5017a4
4
+ data.tar.gz: 3ce4cde5901b75e961137eddc00023e0d7ee6f5b
5
5
  SHA512:
6
- metadata.gz: 5fbbb7cb31fd3007f6afbfeb0db8915a9b067c2b977675bea6d127bb6bc32e070e837a1572e56e8099b1b998958de4526acb72d97407267470331805df5aa938
7
- data.tar.gz: 4bb7a22274f4c5666f02e9f887d5ecaaa9de717f1c823f317f5160be548e9138d2b0d427b6a342c1626c7124643199813a61946ec904f3d424a0c01fd0f7e4a5
6
+ metadata.gz: b5c985b97209b5b20cbe053da4c0c2fecdf40ab1f9287fdefc9094b198d3457e8f0464527a2b79098ada13f6eb5e07ec461eac2698c3a76529710f5bc81709ce
7
+ data.tar.gz: ec607bd967b5d16568b4507bca7b80d2d11937b8feaf4776a38258764202207d878c4e49d5901fbe61b688f4e6e40939ea651db2c49484068cd204b2afc1ff10
@@ -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 { |file|
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 = ["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"
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) + ["lib/flipper/version.rb"]
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 = "flipper-redis"
19
- gem.require_paths = ["lib"]
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 disabled for the gate.
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] = case gate.data_type
130
- when :boolean, :integer
131
- doc[gate.key.to_s]
132
- when :set
133
- fields_to_gate_value fields, gate
134
- else
135
- unsupported_data_type gate.data_type
136
- end
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 = /^#{Regexp.escape(gate.key.to_s)}\//
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
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = "0.10.2".freeze
2
+ VERSION = '0.11.0.beta1'.freeze
3
3
  end
@@ -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
@@ -5,7 +5,8 @@ class RedisTest < MiniTest::Test
5
5
  prepend Flipper::Test::SharedAdapterTests
6
6
 
7
7
  def setup
8
- client = Redis.new({}).tap { |c| c.flushdb }
9
- @adapter = Flipper::Adapters::Redis.new(client)
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.10.2
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: 2016-12-08 00:00:00.000000000 Z
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.10.2
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.10.2
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: '0'
84
+ version: 1.3.1
82
85
  requirements: []
83
86
  rubyforge_project:
84
- rubygems_version: 2.4.5.1
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