flipper 0.10.2 → 0.11.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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