flipper-redis 0.26.2 → 1.2.2

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