flipper-redis 0.26.2 → 1.2.2

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
  SHA256:
3
- metadata.gz: 07f785e46ede10238e72265b2db164520c385c6707652b61ac26e8f3571f198a
4
- data.tar.gz: 65c0f228d8427145fae22f3ea9d73856f4ef22cdf363a470b28975c41b67b358
3
+ metadata.gz: e55b034a67c36b705521502c717a6a702e20fe7339571700e7a9250f49f21781
4
+ data.tar.gz: 95633728475c7a39bd88fd59b17ba4924dbbf9c98e2f7a2b0f196722302b1b19
5
5
  SHA512:
6
- metadata.gz: 44261262d8159b0ac8d27630d40e326a0bf6eacefc663adede5f7f59bea1014504471a0c8169ec01b7e50e666388aaecaebc2ee1421dd2a7688dde4692eb12d3
7
- data.tar.gz: 4eb84f9a382046ced62a0d4140697fc8c500d0689c9ba4d2725d17bb9cabc0557262933e1d4a4e5f089436520b638570a6d767bea2f37f071ffa13b69ac3a950
6
+ metadata.gz: 4cf728abd260addff1b057c68b0ea401458bc53fe8aa1ec4247d322dd1f1083fdbec76d20a4d3fc3bd123c4babde353d5a5be1d66ff07be1881e5430e794d21f
7
+ data.tar.gz: af6843a3bb222f418ae9917bde9b7d4d9d5f37bcb88371950ad834a7f6d557c0bf7ee8779bcfba8ee57fe6f6144bb1ab928ecbac04fdd3d7290dd70c441f28d0
@@ -6,8 +6,8 @@ require 'flipper/adapters/redis'
6
6
  client = Redis.new
7
7
 
8
8
  # Register a few groups.
9
- Flipper.register(:admins) { |thing| thing.admin? }
10
- Flipper.register(:early_access) { |thing| thing.early_access? }
9
+ Flipper.register(:admins) { |actor| actor.admin? }
10
+ Flipper.register(:early_access) { |actor| actor.early_access? }
11
11
 
12
12
  # Create a user class that has flipper_id instance method.
13
13
  User = Struct.new(:flipper_id)
@@ -12,8 +12,8 @@ adapter = Flipper::Adapters::Redis.new(namespaced_client)
12
12
  flipper = Flipper.new(adapter)
13
13
 
14
14
  # Register a few groups.
15
- Flipper.register(:admins) { |thing| thing.admin? }
16
- Flipper.register(:early_access) { |thing| thing.early_access? }
15
+ Flipper.register(:admins) { |actor| actor.admin? }
16
+ Flipper.register(:early_access) { |actor| actor.early_access? }
17
17
 
18
18
  # Create a user class that has flipper_id instance method.
19
19
  User = Struct.new(:flipper_id)
@@ -8,10 +8,10 @@ end
8
8
 
9
9
  Gem::Specification.new do |gem|
10
10
  gem.authors = ['John Nunemaker']
11
- gem.email = ['nunemaker@gmail.com']
12
- gem.summary = 'Redis adapter for Flipper'
11
+ gem.email = 'support@flippercloud.io'
12
+ gem.summary = 'Redis feature flag adapter for Flipper'
13
13
  gem.license = 'MIT'
14
- gem.homepage = 'https://github.com/jnunemaker/flipper'
14
+ gem.homepage = 'https://www.flippercloud.io/docs/adapters/redis'
15
15
 
16
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)
@@ -7,18 +7,24 @@ module Flipper
7
7
  class Redis
8
8
  include ::Flipper::Adapter
9
9
 
10
- # Private: The key that stores the set of known features.
11
- FeaturesKey = :flipper_features
10
+ attr_reader :key_prefix
12
11
 
13
- # Public: The name of the adapter.
14
- attr_reader :name
12
+ def features_key
13
+ "#{key_prefix}flipper_features"
14
+ end
15
+
16
+ def key_for(feature_name)
17
+ "#{key_prefix}#{feature_name}"
18
+ end
15
19
 
16
20
  # Public: Initializes a Redis flipper adapter.
17
21
  #
18
- # client - The Redis client to use. Feel free to namespace it.
19
- def initialize(client)
22
+ # client - The Redis client to use.
23
+ # key_prefix - an optional prefix with which to namespace
24
+ # flipper's Redis keys
25
+ def initialize(client, key_prefix: nil)
20
26
  @client = client
21
- @name = :redis
27
+ @key_prefix = key_prefix
22
28
  end
23
29
 
24
30
  # Public: The set of known features.
@@ -29,9 +35,9 @@ module Flipper
29
35
  # Public: Adds a feature to the set of known features.
30
36
  def add(feature)
31
37
  if redis_sadd_returns_boolean?
32
- @client.sadd? FeaturesKey, feature.key
38
+ @client.sadd? features_key, feature.key
33
39
  else
34
- @client.sadd FeaturesKey, feature.key
40
+ @client.sadd features_key, feature.key
35
41
  end
36
42
  true
37
43
  end
@@ -39,17 +45,17 @@ module Flipper
39
45
  # Public: Removes a feature from the set of known features.
40
46
  def remove(feature)
41
47
  if redis_sadd_returns_boolean?
42
- @client.srem? FeaturesKey, feature.key
48
+ @client.srem? features_key, feature.key
43
49
  else
44
- @client.srem FeaturesKey, feature.key
50
+ @client.srem features_key, feature.key
45
51
  end
46
- @client.del feature.key
52
+ @client.del key_for(feature.key)
47
53
  true
48
54
  end
49
55
 
50
56
  # Public: Clears the gate values for a feature.
51
57
  def clear(feature)
52
- @client.del feature.key
58
+ @client.del key_for(feature.key)
53
59
  true
54
60
  end
55
61
 
@@ -73,19 +79,22 @@ module Flipper
73
79
  # Public: Enables a gate for a given thing.
74
80
  #
75
81
  # feature - The Flipper::Feature for the gate.
76
- # gate - The Flipper::Gate to disable.
82
+ # gate - The Flipper::Gate to enable.
77
83
  # thing - The Flipper::Type being enabled for the gate.
78
84
  #
79
85
  # Returns true.
80
86
  def enable(feature, gate, thing)
87
+ feature_key = key_for(feature.key)
81
88
  case gate.data_type
82
89
  when :boolean
83
90
  clear(feature)
84
- @client.hset feature.key, gate.key, thing.value.to_s
91
+ @client.hset feature_key, gate.key, thing.value.to_s
85
92
  when :integer
86
- @client.hset feature.key, gate.key, thing.value.to_s
93
+ @client.hset feature_key, gate.key, thing.value.to_s
87
94
  when :set
88
- @client.hset feature.key, to_field(gate, thing), 1
95
+ @client.hset feature_key, to_field(gate, thing), 1
96
+ when :json
97
+ @client.hset feature_key, gate.key, Typecast.to_json(thing.value)
89
98
  else
90
99
  unsupported_data_type gate.data_type
91
100
  end
@@ -101,13 +110,16 @@ module Flipper
101
110
  #
102
111
  # Returns true.
103
112
  def disable(feature, gate, thing)
113
+ feature_key = key_for(feature.key)
104
114
  case gate.data_type
105
115
  when :boolean
106
- @client.del feature.key
116
+ @client.del feature_key
107
117
  when :integer
108
- @client.hset feature.key, gate.key, thing.value.to_s
118
+ @client.hset feature_key, gate.key, thing.value.to_s
109
119
  when :set
110
- @client.hdel feature.key, to_field(gate, thing)
120
+ @client.hdel feature_key, to_field(gate, thing)
121
+ when :json
122
+ @client.hdel feature_key, gate.key
111
123
  else
112
124
  unsupported_data_type gate.data_type
113
125
  end
@@ -131,14 +143,14 @@ module Flipper
131
143
  end
132
144
 
133
145
  def read_feature_keys
134
- @client.smembers(FeaturesKey).to_set
146
+ @client.smembers(features_key).to_set
135
147
  end
136
148
 
137
149
  # Private: Gets a hash of fields => values for the given feature.
138
150
  #
139
151
  # Returns a Hash of fields => values.
140
152
  def doc_for(feature, pipeline: @client)
141
- pipeline.hgetall(feature.key)
153
+ pipeline.hgetall(key_for(feature.key))
142
154
  end
143
155
 
144
156
  def docs_for(features)
@@ -160,6 +172,9 @@ module Flipper
160
172
  doc[gate.key.to_s]
161
173
  when :set
162
174
  fields_to_gate_value fields, gate
175
+ when :json
176
+ value = doc[gate.key.to_s]
177
+ Typecast.from_json(value)
163
178
  else
164
179
  unsupported_data_type gate.data_type
165
180
  end
@@ -8,28 +8,19 @@ module Flipper
8
8
  class RedisCache
9
9
  include ::Flipper::Adapter
10
10
 
11
- Version = 'v1'.freeze
12
- Namespace = "flipper/#{Version}".freeze
13
- FeaturesKey = "#{Namespace}/features".freeze
14
- GetAllKey = "#{Namespace}/get_all".freeze
15
-
16
- # Private
17
- def self.key_for(key)
18
- "#{Namespace}/feature/#{key}"
19
- end
20
-
21
11
  # Internal
22
12
  attr_reader :cache
23
13
 
24
- # Public: The name of the adapter.
25
- attr_reader :name
26
-
27
14
  # Public
28
15
  def initialize(adapter, cache, ttl = 3600)
29
16
  @adapter = adapter
30
- @name = :redis_cache
31
17
  @cache = cache
32
18
  @ttl = ttl
19
+
20
+ @version = 'v1'.freeze
21
+ @namespace = "flipper/#{@version}".freeze
22
+ @features_key = "#{@namespace}/features".freeze
23
+ @get_all_key = "#{@namespace}/get_all".freeze
33
24
  end
34
25
 
35
26
  # Public
@@ -40,14 +31,14 @@ module Flipper
40
31
  # Public
41
32
  def add(feature)
42
33
  result = @adapter.add(feature)
43
- @cache.del(FeaturesKey)
34
+ @cache.del(@features_key)
44
35
  result
45
36
  end
46
37
 
47
38
  # Public
48
39
  def remove(feature)
49
40
  result = @adapter.remove(feature)
50
- @cache.del(FeaturesKey)
41
+ @cache.del(@features_key)
51
42
  @cache.del(key_for(feature.key))
52
43
  result
53
44
  end
@@ -71,13 +62,13 @@ module Flipper
71
62
  end
72
63
 
73
64
  def get_all
74
- if @cache.setnx(GetAllKey, Time.now.to_i)
75
- @cache.expire(GetAllKey, @ttl)
65
+ if @cache.setnx(@get_all_key, Time.now.to_i)
66
+ @cache.expire(@get_all_key, @ttl)
76
67
  response = @adapter.get_all
77
68
  response.each do |key, value|
78
69
  set_with_ttl key_for(key), value
79
70
  end
80
- set_with_ttl FeaturesKey, response.keys.to_set
71
+ set_with_ttl @features_key, response.keys.to_set
81
72
  response
82
73
  else
83
74
  features = read_feature_keys.map { |key| Flipper::Feature.new(key, self) }
@@ -102,11 +93,11 @@ module Flipper
102
93
  private
103
94
 
104
95
  def key_for(key)
105
- self.class.key_for(key)
96
+ "#{@namespace}/feature/#{key}"
106
97
  end
107
98
 
108
99
  def read_feature_keys
109
- fetch(FeaturesKey) { @adapter.features }
100
+ fetch(@features_key) { @adapter.features }
110
101
  end
111
102
 
112
103
  def read_many_features(features)
@@ -1,3 +1,13 @@
1
1
  module Flipper
2
- VERSION = '0.26.2'.freeze
2
+ VERSION = '1.2.2'.freeze
3
+
4
+ REQUIRED_RUBY_VERSION = '2.6'.freeze
5
+ NEXT_REQUIRED_RUBY_VERSION = '3.0'.freeze
6
+
7
+ REQUIRED_RAILS_VERSION = '5.2'.freeze
8
+ NEXT_REQUIRED_RAILS_VERSION = '6.1.0'.freeze
9
+
10
+ def self.deprecated_ruby_version?
11
+ Gem::Version.new(RUBY_VERSION) < Gem::Version.new(NEXT_REQUIRED_RUBY_VERSION)
12
+ end
3
13
  end
@@ -17,10 +17,8 @@ RSpec.describe Flipper::Adapters::RedisCache do
17
17
  subject { adapter }
18
18
 
19
19
  before do
20
- begin
20
+ skip_on_error(Redis::CannotConnectError, 'Redis not available') do
21
21
  client.flushdb
22
- rescue Redis::CannotConnectError
23
- ENV['CI'] ? raise : skip('Redis not available')
24
22
  end
25
23
  end
26
24
 
@@ -31,7 +29,7 @@ RSpec.describe Flipper::Adapters::RedisCache do
31
29
  feature = flipper[:stats]
32
30
  adapter.get(feature)
33
31
  adapter.remove(feature)
34
- expect(client.get(described_class.key_for(feature))).to be(nil)
32
+ expect(client.get("flipper/v1/feature/#{feature.key}")).to be(nil)
35
33
  end
36
34
  end
37
35
 
@@ -39,7 +37,7 @@ RSpec.describe Flipper::Adapters::RedisCache do
39
37
  it 'uses correct cache key' do
40
38
  stats = flipper[:stats]
41
39
  adapter.get(stats)
42
- expect(client.get(described_class.key_for(stats))).not_to be_nil
40
+ expect(client.get("flipper/v1/feature/#{stats.key}")).not_to be_nil
43
41
  end
44
42
  end
45
43
 
@@ -54,13 +52,13 @@ RSpec.describe Flipper::Adapters::RedisCache do
54
52
  memory_adapter.reset
55
53
 
56
54
  adapter.get(stats)
57
- expect(client.get(described_class.key_for(search))).to be(nil)
58
- expect(client.get(described_class.key_for(other))).to be(nil)
55
+ expect(client.get("flipper/v1/feature/#{search.key}")).to be(nil)
56
+ expect(client.get("flipper/v1/feature/#{other.key}")).to be(nil)
59
57
 
60
58
  adapter.get_multi([stats, search, other])
61
59
 
62
60
  search_cache_value, other_cache_value = [search, other].map do |f|
63
- Marshal.load(client.get(described_class.key_for(f)))
61
+ Marshal.load(client.get("flipper/v1/feature/#{f.key}"))
64
62
  end
65
63
  expect(search_cache_value[:boolean]).to eq('true')
66
64
  expect(other_cache_value[:boolean]).to be(nil)
@@ -82,9 +80,9 @@ RSpec.describe Flipper::Adapters::RedisCache do
82
80
 
83
81
  it 'warms all features' do
84
82
  adapter.get_all
85
- expect(Marshal.load(client.get(described_class.key_for(stats.key)))[:boolean]).to eq('true')
86
- expect(Marshal.load(client.get(described_class.key_for(search.key)))[:boolean]).to be(nil)
87
- expect(client.get(described_class::GetAllKey).to_i).to be_within(2).of(Time.now.to_i)
83
+ expect(Marshal.load(client.get("flipper/v1/feature/#{stats.key}"))[:boolean]).to eq('true')
84
+ expect(Marshal.load(client.get("flipper/v1/feature/#{search.key}"))[:boolean]).to be(nil)
85
+ expect(client.get("flipper/v1/get_all").to_i).to be_within(2).of(Time.now.to_i)
88
86
  end
89
87
 
90
88
  it 'returns same result when already cached' do
@@ -13,10 +13,8 @@ RSpec.describe Flipper::Adapters::Redis do
13
13
  subject { described_class.new(client) }
14
14
 
15
15
  before do
16
- begin
16
+ skip_on_error(Redis::CannotConnectError, 'Redis not available') do
17
17
  client.flushdb
18
- rescue Redis::CannotConnectError
19
- ENV['CI'] ? raise : skip('Redis not available')
20
18
  end
21
19
  end
22
20
 
@@ -30,4 +28,28 @@ RSpec.describe Flipper::Adapters::Redis do
30
28
 
31
29
  expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::Redis)
32
30
  end
31
+
32
+ describe 'with a key_prefix' do
33
+ let(:subject) { described_class.new(client, key_prefix: "lockbox:") }
34
+ let(:feature) { Flipper::Feature.new(:search, subject) }
35
+
36
+ it_should_behave_like 'a flipper adapter'
37
+
38
+ it 'namespaces feature-keys' do
39
+ subject.add(feature)
40
+
41
+ expect(client.smembers("flipper_features")).to eq([])
42
+ expect(client.exists?("search")).to eq(false)
43
+ expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
44
+ expect(client.hgetall("lockbox:search")).not_to eq(nil)
45
+ end
46
+
47
+ it "can remove namespaced keys" do
48
+ subject.add(feature)
49
+ expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
50
+
51
+ subject.remove(feature)
52
+ expect(client.smembers("lockbox:flipper_features")).to be_empty
53
+ end
54
+ end
33
55
  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.26.2
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-15 00:00:00.000000000 Z
11
+ date: 2024-01-19 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.26.2
19
+ version: 1.2.2
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.2
26
+ version: 1.2.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -45,8 +45,7 @@ dependencies:
45
45
  - !ruby/object:Gem::Version
46
46
  version: '6'
47
47
  description:
48
- email:
49
- - nunemaker@gmail.com
48
+ email: support@flippercloud.io
50
49
  executables: []
51
50
  extensions: []
52
51
  extra_rdoc_files: []
@@ -63,11 +62,15 @@ files:
63
62
  - spec/flipper/adapters/redis_spec.rb
64
63
  - test/adapters/redis_cache_test.rb
65
64
  - test/adapters/redis_test.rb
66
- homepage: https://github.com/jnunemaker/flipper
65
+ homepage: https://www.flippercloud.io/docs/adapters/redis
67
66
  licenses:
68
67
  - MIT
69
68
  metadata:
70
- changelog_uri: https://github.com/jnunemaker/flipper/blob/main/Changelog.md
69
+ documentation_uri: https://www.flippercloud.io/docs
70
+ homepage_uri: https://www.flippercloud.io
71
+ source_code_uri: https://github.com/flippercloud/flipper
72
+ bug_tracker_uri: https://github.com/flippercloud/flipper/issues
73
+ changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.2.2
71
74
  post_install_message:
72
75
  rdoc_options: []
73
76
  require_paths:
@@ -83,10 +86,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
86
  - !ruby/object:Gem::Version
84
87
  version: '0'
85
88
  requirements: []
86
- rubygems_version: 3.3.7
89
+ rubygems_version: 3.5.3
87
90
  signing_key:
88
91
  specification_version: 4
89
- summary: Redis adapter for Flipper
92
+ summary: Redis feature flag adapter for Flipper
90
93
  test_files:
91
94
  - spec/flipper/adapters/redis_cache_spec.rb
92
95
  - spec/flipper/adapters/redis_spec.rb