flipper-redis 0.10.2 → 0.11.0.beta1

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: 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