flipper 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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +42 -0
  3. data/.rubocop_todo.yml +188 -0
  4. data/Changelog.md +10 -0
  5. data/Gemfile +6 -3
  6. data/README.md +4 -3
  7. data/Rakefile +13 -13
  8. data/docs/Adapters.md +2 -1
  9. data/docs/DockerCompose.md +6 -3
  10. data/docs/Gates.md +25 -3
  11. data/docs/Optimization.md +27 -5
  12. data/docs/api/README.md +73 -32
  13. data/docs/http/README.md +34 -0
  14. data/docs/read-only/README.md +22 -0
  15. data/examples/percentage_of_actors_group.rb +49 -0
  16. data/flipper.gemspec +15 -15
  17. data/lib/flipper.rb +2 -5
  18. data/lib/flipper/adapter.rb +10 -0
  19. data/lib/flipper/adapters/http.rb +147 -0
  20. data/lib/flipper/adapters/http/client.rb +83 -0
  21. data/lib/flipper/adapters/http/error.rb +14 -0
  22. data/lib/flipper/adapters/instrumented.rb +36 -36
  23. data/lib/flipper/adapters/memoizable.rb +2 -6
  24. data/lib/flipper/adapters/memory.rb +10 -9
  25. data/lib/flipper/adapters/operation_logger.rb +1 -1
  26. data/lib/flipper/adapters/pstore.rb +12 -11
  27. data/lib/flipper/adapters/read_only.rb +6 -6
  28. data/lib/flipper/dsl.rb +1 -3
  29. data/lib/flipper/feature.rb +11 -16
  30. data/lib/flipper/gate.rb +3 -3
  31. data/lib/flipper/gate_values.rb +6 -6
  32. data/lib/flipper/gates/group.rb +2 -2
  33. data/lib/flipper/gates/percentage_of_actors.rb +2 -2
  34. data/lib/flipper/instrumentation/log_subscriber.rb +2 -4
  35. data/lib/flipper/instrumentation/metriks.rb +1 -1
  36. data/lib/flipper/instrumentation/statsd.rb +1 -1
  37. data/lib/flipper/instrumentation/statsd_subscriber.rb +1 -3
  38. data/lib/flipper/instrumentation/subscriber.rb +11 -10
  39. data/lib/flipper/instrumenters/memory.rb +1 -5
  40. data/lib/flipper/instrumenters/noop.rb +1 -1
  41. data/lib/flipper/middleware/memoizer.rb +11 -27
  42. data/lib/flipper/middleware/setup_env.rb +44 -0
  43. data/lib/flipper/registry.rb +8 -10
  44. data/lib/flipper/spec/shared_adapter_specs.rb +45 -67
  45. data/lib/flipper/test/shared_adapter_test.rb +25 -31
  46. data/lib/flipper/typecast.rb +2 -2
  47. data/lib/flipper/types/actor.rb +2 -4
  48. data/lib/flipper/types/group.rb +1 -1
  49. data/lib/flipper/types/percentage.rb +2 -1
  50. data/lib/flipper/version.rb +1 -1
  51. data/spec/fixtures/feature.json +31 -0
  52. data/spec/flipper/adapters/http_spec.rb +148 -0
  53. data/spec/flipper/adapters/instrumented_spec.rb +20 -20
  54. data/spec/flipper/adapters/memoizable_spec.rb +59 -59
  55. data/spec/flipper/adapters/operation_logger_spec.rb +16 -16
  56. data/spec/flipper/adapters/pstore_spec.rb +6 -6
  57. data/spec/flipper/adapters/read_only_spec.rb +28 -34
  58. data/spec/flipper/dsl_spec.rb +73 -84
  59. data/spec/flipper/feature_check_context_spec.rb +27 -27
  60. data/spec/flipper/feature_spec.rb +186 -196
  61. data/spec/flipper/gate_spec.rb +11 -11
  62. data/spec/flipper/gate_values_spec.rb +46 -45
  63. data/spec/flipper/gates/actor_spec.rb +2 -2
  64. data/spec/flipper/gates/boolean_spec.rb +24 -23
  65. data/spec/flipper/gates/group_spec.rb +19 -19
  66. data/spec/flipper/gates/percentage_of_actors_spec.rb +10 -10
  67. data/spec/flipper/gates/percentage_of_time_spec.rb +2 -2
  68. data/spec/flipper/instrumentation/log_subscriber_spec.rb +20 -20
  69. data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +20 -20
  70. data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +11 -11
  71. data/spec/flipper/instrumenters/memory_spec.rb +5 -5
  72. data/spec/flipper/instrumenters/noop_spec.rb +6 -6
  73. data/spec/flipper/middleware/memoizer_spec.rb +83 -100
  74. data/spec/flipper/middleware/setup_env_spec.rb +76 -0
  75. data/spec/flipper/registry_spec.rb +35 -39
  76. data/spec/flipper/typecast_spec.rb +18 -18
  77. data/spec/flipper/types/actor_spec.rb +30 -29
  78. data/spec/flipper/types/boolean_spec.rb +8 -8
  79. data/spec/flipper/types/group_spec.rb +28 -28
  80. data/spec/flipper/types/percentage_spec.rb +14 -14
  81. data/spec/flipper_spec.rb +61 -54
  82. data/spec/helper.rb +26 -21
  83. data/spec/integration_spec.rb +121 -113
  84. data/spec/support/fake_udp_socket.rb +1 -1
  85. data/spec/support/spec_helpers.rb +32 -4
  86. data/test/adapters/pstore_test.rb +3 -3
  87. data/test/test_helper.rb +1 -1
  88. metadata +20 -5
@@ -3,8 +3,8 @@ module Flipper
3
3
  TruthMap = {
4
4
  true => true,
5
5
  1 => true,
6
- "true" => true,
7
- "1" => true,
6
+ 'true' => true,
7
+ '1' => true,
8
8
  }.freeze
9
9
 
10
10
  # Internal: Convert value to a boolean.
@@ -9,12 +9,10 @@ module Flipper
9
9
  attr_reader :thing
10
10
 
11
11
  def initialize(thing)
12
- if thing.nil?
13
- raise ArgumentError.new("thing cannot be nil")
14
- end
12
+ raise ArgumentError, 'thing cannot be nil' if thing.nil?
15
13
 
16
14
  unless thing.respond_to?(:flipper_id)
17
- raise ArgumentError.new("#{thing.inspect} must respond to flipper_id, but does not")
15
+ raise ArgumentError, "#{thing.inspect} must respond to flipper_id, but does not"
18
16
  end
19
17
 
20
18
  @thing = thing
@@ -16,7 +16,7 @@ module Flipper
16
16
  @block = block
17
17
  @single_argument = @block.arity == 1
18
18
  else
19
- @block = lambda { |thing, context| false }
19
+ @block = ->(_thing, _context) { false }
20
20
  @single_argument = false
21
21
  end
22
22
  end
@@ -5,7 +5,8 @@ module Flipper
5
5
  value = Typecast.to_integer(value)
6
6
 
7
7
  if value < 0 || value > 100
8
- raise ArgumentError, "value must be a positive number less than or equal to 100, but was #{value}"
8
+ raise ArgumentError,
9
+ "value must be a positive number less than or equal to 100, but was #{value}"
9
10
  end
10
11
 
11
12
  @value = value
@@ -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,31 @@
1
+ {
2
+ "key": "my_feature",
3
+ "state": "on",
4
+ "gates": [
5
+ {
6
+ "key": "boolean",
7
+ "name": "boolean",
8
+ "value": "true"
9
+ },
10
+ {
11
+ "key": "groups",
12
+ "name": "group",
13
+ "value": []
14
+ },
15
+ {
16
+ "key": "actors",
17
+ "name": "actor",
18
+ "value": []
19
+ },
20
+ {
21
+ "key": "percentage_of_actors",
22
+ "name": "percentage_of_actors",
23
+ "value": null
24
+ },
25
+ {
26
+ "key": "percentage_of_time",
27
+ "name": "percentage_of_time",
28
+ "value": null
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,148 @@
1
+ require 'helper'
2
+ require 'flipper/adapters/http'
3
+ require 'flipper/adapters/pstore'
4
+ require 'flipper/spec/shared_adapter_specs'
5
+ require 'rack/handler/webrick'
6
+
7
+ FLIPPER_SPEC_API_PORT = ENV.fetch('FLIPPER_SPEC_API_PORT', 9001).to_i
8
+
9
+ RSpec.describe Flipper::Adapters::Http do
10
+ context 'adapter' do
11
+ subject do
12
+ described_class.new(uri: URI("http://localhost:#{FLIPPER_SPEC_API_PORT}"))
13
+ end
14
+
15
+ before :all do
16
+ dir = FlipperRoot.join('tmp').tap(&:mkpath)
17
+ log_path = dir.join('flipper_adapters_http_spec.log')
18
+ @pstore_file = dir.join('flipper.pstore')
19
+ @pstore_file.unlink if @pstore_file.exist?
20
+
21
+ api_adapter = Flipper::Adapters::PStore.new(@pstore_file)
22
+ flipper_api = Flipper.new(api_adapter)
23
+ app = Flipper::Api.app(flipper_api)
24
+ server_options = {
25
+ Port: FLIPPER_SPEC_API_PORT,
26
+ StartCallback: -> { @started = true },
27
+ Logger: WEBrick::Log.new(log_path.to_s, WEBrick::Log::INFO),
28
+ AccessLog: [
29
+ [log_path.open('w'), WEBrick::AccessLog::COMBINED_LOG_FORMAT],
30
+ ],
31
+ }
32
+ @server = WEBrick::HTTPServer.new(server_options)
33
+ @server.mount '/', Rack::Handler::WEBrick, app
34
+
35
+ Thread.new { @server.start }
36
+ Timeout.timeout(1) { :wait until @started }
37
+ end
38
+
39
+ after :all do
40
+ @server.shutdown if @server
41
+ end
42
+
43
+ before(:each) do
44
+ @pstore_file.unlink if @pstore_file.exist?
45
+ end
46
+
47
+ it_should_behave_like 'a flipper adapter'
48
+
49
+ it "can enable and disable unregistered group" do
50
+ flipper = Flipper.new(subject)
51
+ expect(flipper[:search].enable_group(:some_made_up_group)).to be(true)
52
+ expect(flipper[:search].groups_value).to eq(Set["some_made_up_group"])
53
+
54
+ expect(flipper[:search].disable_group(:some_made_up_group)).to be(true)
55
+ expect(flipper[:search].groups_value).to eq(Set.new)
56
+ end
57
+ end
58
+
59
+ it "sends default headers" do
60
+ headers = {
61
+ 'Accept' => 'application/json',
62
+ 'Content-Type' => 'application/json',
63
+ 'User-Agent' => 'Flipper HTTP Adapter v0.10.2',
64
+ }
65
+ stub_request(:get, "http://app.com/flipper/features/feature_panel")
66
+ .with(headers: headers)
67
+ .to_return(status: 404, body: "", headers: {})
68
+
69
+ adapter = described_class.new(uri: URI('http://app.com/flipper'))
70
+ adapter.get(flipper[:feature_panel])
71
+ end
72
+
73
+ describe "#get" do
74
+ it "raises error when not successful response" do
75
+ stub_request(:get, "http://app.com/flipper/features/feature_panel")
76
+ .to_return(status: 503, body: "", headers: {})
77
+
78
+ adapter = described_class.new(uri: URI('http://app.com/flipper'))
79
+ expect do
80
+ adapter.get(flipper[:feature_panel])
81
+ end.to raise_error(Flipper::Adapters::Http::Error)
82
+ end
83
+ end
84
+
85
+ describe "#get_multi" do
86
+ it "raises error when not successful response" do
87
+ stub_request(:get, "http://app.com/flipper/features?keys=feature_panel")
88
+ .to_return(status: 503, body: "", headers: {})
89
+
90
+ adapter = described_class.new(uri: URI('http://app.com/flipper'))
91
+ expect do
92
+ adapter.get_multi([flipper[:feature_panel]])
93
+ end.to raise_error(Flipper::Adapters::Http::Error)
94
+ end
95
+ end
96
+
97
+ describe "#features" do
98
+ it "raises error when not successful response" do
99
+ stub_request(:get, "http://app.com/flipper/features")
100
+ .to_return(status: 503, body: "", headers: {})
101
+
102
+ adapter = described_class.new(uri: URI('http://app.com/flipper'))
103
+ expect do
104
+ adapter.features
105
+ end.to raise_error(Flipper::Adapters::Http::Error)
106
+ end
107
+ end
108
+
109
+ describe 'configuration' do
110
+ let(:options) do
111
+ {
112
+ uri: URI('http://app.com/mount-point'),
113
+ headers: { 'X-Custom-Header' => 'foo' },
114
+ basic_auth_username: 'username',
115
+ basic_auth_password: 'password',
116
+ read_timeout: 100,
117
+ open_timeout: 40,
118
+ }
119
+ end
120
+ subject { described_class.new(options) }
121
+ let(:feature) { flipper[:feature_panel] }
122
+
123
+ before do
124
+ stub_request(:get, %r{\Ahttp://app.com*}).to_return(body: fixture_file('feature.json'))
125
+ end
126
+
127
+ it 'allows client to set request headers' do
128
+ subject.get(feature)
129
+ expect(
130
+ a_request(:get, 'http://app.com/mount-point/features/feature_panel')
131
+ .with(headers: { 'X-Custom-Header' => 'foo' })
132
+ ).to have_been_made.once
133
+ end
134
+
135
+ it 'allows client to set basic auth' do
136
+ subject.get(feature)
137
+ expect(
138
+ a_request(:get, 'http://app.com/mount-point/features/feature_panel')
139
+ .with(basic_auth: %w(username password))
140
+ ).to have_been_made.once
141
+ end
142
+ end
143
+
144
+ def fixture_file(name)
145
+ fixtures_path = File.expand_path('../../../fixtures', __FILE__)
146
+ File.new(fixtures_path + '/' + name)
147
+ end
148
+ end
@@ -13,13 +13,13 @@ RSpec.describe Flipper::Adapters::Instrumented do
13
13
  let(:gate) { feature.gate(:percentage_of_actors) }
14
14
  let(:thing) { flipper.actors(22) }
15
15
 
16
- subject {
17
- described_class.new(adapter, :instrumenter => instrumenter)
18
- }
16
+ subject do
17
+ described_class.new(adapter, instrumenter: instrumenter)
18
+ end
19
19
 
20
20
  it_should_behave_like 'a flipper adapter'
21
21
 
22
- it "forwards missing methods to underlying adapter" do
22
+ it 'forwards missing methods to underlying adapter' do
23
23
  adapter = Class.new do
24
24
  def foo
25
25
  :foo
@@ -29,14 +29,14 @@ RSpec.describe Flipper::Adapters::Instrumented do
29
29
  expect(instrumented.foo).to eq(:foo)
30
30
  end
31
31
 
32
- describe "#name" do
33
- it "is instrumented" do
32
+ describe '#name' do
33
+ it 'is instrumented' do
34
34
  expect(subject.name).to be(:instrumented)
35
35
  end
36
36
  end
37
37
 
38
- describe "#get" do
39
- it "records instrumentation" do
38
+ describe '#get' do
39
+ it 'records instrumentation' do
40
40
  result = subject.get(feature)
41
41
 
42
42
  event = instrumenter.events.last
@@ -49,8 +49,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
49
49
  end
50
50
  end
51
51
 
52
- describe "#enable" do
53
- it "records instrumentation" do
52
+ describe '#enable' do
53
+ it 'records instrumentation' do
54
54
  result = subject.enable(feature, gate, thing)
55
55
 
56
56
  event = instrumenter.events.last
@@ -64,8 +64,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
64
64
  end
65
65
  end
66
66
 
67
- describe "#disable" do
68
- it "records instrumentation" do
67
+ describe '#disable' do
68
+ it 'records instrumentation' do
69
69
  result = subject.disable(feature, gate, thing)
70
70
 
71
71
  event = instrumenter.events.last
@@ -79,8 +79,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
79
79
  end
80
80
  end
81
81
 
82
- describe "#add" do
83
- it "records instrumentation" do
82
+ describe '#add' do
83
+ it 'records instrumentation' do
84
84
  result = subject.add(feature)
85
85
 
86
86
  event = instrumenter.events.last
@@ -93,8 +93,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
93
93
  end
94
94
  end
95
95
 
96
- describe "#remove" do
97
- it "records instrumentation" do
96
+ describe '#remove' do
97
+ it 'records instrumentation' do
98
98
  result = subject.remove(feature)
99
99
 
100
100
  event = instrumenter.events.last
@@ -107,8 +107,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
107
107
  end
108
108
  end
109
109
 
110
- describe "#clear" do
111
- it "records instrumentation" do
110
+ describe '#clear' do
111
+ it 'records instrumentation' do
112
112
  result = subject.clear(feature)
113
113
 
114
114
  event = instrumenter.events.last
@@ -121,8 +121,8 @@ RSpec.describe Flipper::Adapters::Instrumented do
121
121
  end
122
122
  end
123
123
 
124
- describe "#features" do
125
- it "records instrumentation" do
124
+ describe '#features' do
125
+ it 'records instrumentation' do
126
126
  result = subject.features
127
127
 
128
128
  event = instrumenter.events.last
@@ -13,7 +13,7 @@ RSpec.describe Flipper::Adapters::Memoizable do
13
13
 
14
14
  it_should_behave_like 'a flipper adapter'
15
15
 
16
- it "forwards missing methods to underlying adapter" do
16
+ it 'forwards missing methods to underlying adapter' do
17
17
  adapter = Class.new do
18
18
  def foo
19
19
  :foo
@@ -23,14 +23,14 @@ RSpec.describe Flipper::Adapters::Memoizable do
23
23
  expect(memoizable.foo).to eq(:foo)
24
24
  end
25
25
 
26
- describe "#name" do
27
- it "is instrumented" do
26
+ describe '#name' do
27
+ it 'is instrumented' do
28
28
  expect(subject.name).to be(:memoizable)
29
29
  end
30
30
  end
31
31
 
32
- describe "#memoize=" do
33
- it "sets value" do
32
+ describe '#memoize=' do
33
+ it 'sets value' do
34
34
  subject.memoize = true
35
35
  expect(subject.memoizing?).to eq(true)
36
36
 
@@ -38,44 +38,44 @@ RSpec.describe Flipper::Adapters::Memoizable do
38
38
  expect(subject.memoizing?).to eq(false)
39
39
  end
40
40
 
41
- it "clears the local cache" do
41
+ it 'clears the local cache' do
42
42
  subject.cache['some'] = 'thing'
43
43
  subject.memoize = true
44
44
  expect(subject.cache).to be_empty
45
45
  end
46
46
  end
47
47
 
48
- describe "#memoizing?" do
49
- it "returns true if enabled" do
48
+ describe '#memoizing?' do
49
+ it 'returns true if enabled' do
50
50
  subject.memoize = true
51
51
  expect(subject.memoizing?).to eq(true)
52
52
  end
53
53
 
54
- it "returns false if disabled" do
54
+ it 'returns false if disabled' do
55
55
  subject.memoize = false
56
56
  expect(subject.memoizing?).to eq(false)
57
57
  end
58
58
  end
59
59
 
60
- describe "#get" do
61
- context "with memoization enabled" do
60
+ describe '#get' do
61
+ context 'with memoization enabled' do
62
62
  before do
63
63
  subject.memoize = true
64
64
  end
65
65
 
66
- it "memoizes feature" do
66
+ it 'memoizes feature' do
67
67
  feature = flipper[:stats]
68
68
  result = subject.get(feature)
69
69
  expect(cache[feature.key]).to be(result)
70
70
  end
71
71
  end
72
72
 
73
- context "with memoization disabled" do
73
+ context 'with memoization disabled' do
74
74
  before do
75
75
  subject.memoize = false
76
76
  end
77
77
 
78
- it "returns result" do
78
+ it 'returns result' do
79
79
  feature = flipper[:stats]
80
80
  result = subject.get(feature)
81
81
  adapter_result = adapter.get(feature)
@@ -84,30 +84,30 @@ RSpec.describe Flipper::Adapters::Memoizable do
84
84
  end
85
85
  end
86
86
 
87
- describe "#get_multi" do
88
- context "with memoization enabled" do
87
+ describe '#get_multi' do
88
+ context 'with memoization enabled' do
89
89
  before do
90
90
  subject.memoize = true
91
91
  end
92
92
 
93
- it "memoizes feature" do
94
- names = %i{stats shiny}
93
+ it 'memoizes feature' do
94
+ names = %i(stats shiny)
95
95
  features = names.map { |name| flipper[name] }
96
96
  results = subject.get_multi(features)
97
97
  features.each do |feature|
98
- expect(cache[feature.key]).to_not be(nil)
98
+ expect(cache[feature.key]).not_to be(nil)
99
99
  expect(cache[feature.key]).to be(results[feature.key])
100
100
  end
101
101
  end
102
102
  end
103
103
 
104
- context "with memoization disabled" do
104
+ context 'with memoization disabled' do
105
105
  before do
106
106
  subject.memoize = false
107
107
  end
108
108
 
109
- it "returns result" do
110
- names = %i{stats shiny}
109
+ it 'returns result' do
110
+ names = %i(stats shiny)
111
111
  features = names.map { |name| flipper[name] }
112
112
  result = subject.get_multi(features)
113
113
  adapter_result = adapter.get_multi(features)
@@ -116,27 +116,27 @@ RSpec.describe Flipper::Adapters::Memoizable do
116
116
  end
117
117
  end
118
118
 
119
- describe "#enable" do
120
- context "with memoization enabled" do
119
+ describe '#enable' do
120
+ context 'with memoization enabled' do
121
121
  before do
122
122
  subject.memoize = true
123
123
  end
124
124
 
125
- it "unmemoizes feature" do
125
+ it 'unmemoizes feature' do
126
126
  feature = flipper[:stats]
127
127
  gate = feature.gate(:boolean)
128
- cache[feature.key] = {:some => 'thing'}
128
+ cache[feature.key] = { some: 'thing' }
129
129
  subject.enable(feature, gate, flipper.bool)
130
130
  expect(cache[feature.key]).to be_nil
131
131
  end
132
132
  end
133
133
 
134
- context "with memoization disabled" do
134
+ context 'with memoization disabled' do
135
135
  before do
136
136
  subject.memoize = false
137
137
  end
138
138
 
139
- it "returns result" do
139
+ it 'returns result' do
140
140
  feature = flipper[:stats]
141
141
  gate = feature.gate(:boolean)
142
142
  result = subject.enable(feature, gate, flipper.bool)
@@ -146,27 +146,27 @@ RSpec.describe Flipper::Adapters::Memoizable do
146
146
  end
147
147
  end
148
148
 
149
- describe "#disable" do
150
- context "with memoization enabled" do
149
+ describe '#disable' do
150
+ context 'with memoization enabled' do
151
151
  before do
152
152
  subject.memoize = true
153
153
  end
154
154
 
155
- it "unmemoizes feature" do
155
+ it 'unmemoizes feature' do
156
156
  feature = flipper[:stats]
157
157
  gate = feature.gate(:boolean)
158
- cache[feature.key] = {:some => 'thing'}
158
+ cache[feature.key] = { some: 'thing' }
159
159
  subject.disable(feature, gate, flipper.bool)
160
160
  expect(cache[feature.key]).to be_nil
161
161
  end
162
162
  end
163
163
 
164
- context "with memoization disabled" do
164
+ context 'with memoization disabled' do
165
165
  before do
166
166
  subject.memoize = false
167
167
  end
168
168
 
169
- it "returns result" do
169
+ it 'returns result' do
170
170
  feature = flipper[:stats]
171
171
  gate = feature.gate(:boolean)
172
172
  result = subject.disable(feature, gate, flipper.bool)
@@ -176,13 +176,13 @@ RSpec.describe Flipper::Adapters::Memoizable do
176
176
  end
177
177
  end
178
178
 
179
- describe "#features" do
180
- context "with memoization enabled" do
179
+ describe '#features' do
180
+ context 'with memoization enabled' do
181
181
  before do
182
182
  subject.memoize = true
183
183
  end
184
184
 
185
- it "memoizes features" do
185
+ it 'memoizes features' do
186
186
  flipper[:stats].enable
187
187
  flipper[:search].disable
188
188
  result = subject.features
@@ -190,92 +190,92 @@ RSpec.describe Flipper::Adapters::Memoizable do
190
190
  end
191
191
  end
192
192
 
193
- context "with memoization disabled" do
193
+ context 'with memoization disabled' do
194
194
  before do
195
195
  subject.memoize = false
196
196
  end
197
197
 
198
- it "returns result" do
198
+ it 'returns result' do
199
199
  expect(subject.features).to eq(adapter.features)
200
200
  end
201
201
  end
202
202
  end
203
203
 
204
- describe "#add" do
205
- context "with memoization enabled" do
204
+ describe '#add' do
205
+ context 'with memoization enabled' do
206
206
  before do
207
207
  subject.memoize = true
208
208
  end
209
209
 
210
- it "unmemoizes the known features" do
211
- cache[features_key] = {:some => 'thing'}
210
+ it 'unmemoizes the known features' do
211
+ cache[features_key] = { some: 'thing' }
212
212
  subject.add(flipper[:stats])
213
213
  expect(cache).to be_empty
214
214
  end
215
215
  end
216
216
 
217
- context "with memoization disabled" do
217
+ context 'with memoization disabled' do
218
218
  before do
219
219
  subject.memoize = false
220
220
  end
221
221
 
222
- it "returns result" do
222
+ it 'returns result' do
223
223
  expect(subject.add(flipper[:stats])).to eq(adapter.add(flipper[:stats]))
224
224
  end
225
225
  end
226
226
  end
227
227
 
228
- describe "#remove" do
229
- context "with memoization enabled" do
228
+ describe '#remove' do
229
+ context 'with memoization enabled' do
230
230
  before do
231
231
  subject.memoize = true
232
232
  end
233
233
 
234
- it "unmemoizes the known features" do
235
- cache[features_key] = {:some => 'thing'}
234
+ it 'unmemoizes the known features' do
235
+ cache[features_key] = { some: 'thing' }
236
236
  subject.remove(flipper[:stats])
237
237
  expect(cache).to be_empty
238
238
  end
239
239
 
240
- it "unmemoizes the feature" do
240
+ it 'unmemoizes the feature' do
241
241
  feature = flipper[:stats]
242
- cache[feature.key] = {:some => 'thing'}
242
+ cache[feature.key] = { some: 'thing' }
243
243
  subject.remove(feature)
244
244
  expect(cache[feature.key]).to be_nil
245
245
  end
246
246
  end
247
247
 
248
- context "with memoization disabled" do
248
+ context 'with memoization disabled' do
249
249
  before do
250
250
  subject.memoize = false
251
251
  end
252
252
 
253
- it "returns result" do
253
+ it 'returns result' do
254
254
  expect(subject.remove(flipper[:stats])).to eq(adapter.remove(flipper[:stats]))
255
255
  end
256
256
  end
257
257
  end
258
258
 
259
- describe "#clear" do
260
- context "with memoization enabled" do
259
+ describe '#clear' do
260
+ context 'with memoization enabled' do
261
261
  before do
262
262
  subject.memoize = true
263
263
  end
264
264
 
265
- it "unmemoizes feature" do
265
+ it 'unmemoizes feature' do
266
266
  feature = flipper[:stats]
267
- cache[feature.key] = {:some => 'thing'}
267
+ cache[feature.key] = { some: 'thing' }
268
268
  subject.clear(feature)
269
269
  expect(cache[feature.key]).to be_nil
270
270
  end
271
271
  end
272
272
 
273
- context "with memoization disabled" do
273
+ context 'with memoization disabled' do
274
274
  before do
275
275
  subject.memoize = false
276
276
  end
277
277
 
278
- it "returns result" do
278
+ it 'returns result' do
279
279
  feature = flipper[:stats]
280
280
  expect(subject.clear(feature)).to eq(adapter.clear(feature))
281
281
  end