flip_fab 1.0.1 → 1.0.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +29 -0
  3. data/example/rails_app/Gemfile +2 -19
  4. data/example/rails_app/app/assets/javascripts/application.js +0 -1
  5. data/example/rails_app/app/controllers/beavers_controller.rb +11 -12
  6. data/example/rails_app/bin/rails +1 -1
  7. data/example/rails_app/config.ru +1 -1
  8. data/example/rails_app/config/environments/development.rb +1 -1
  9. data/example/rails_app/config/environments/test.rb +2 -2
  10. data/example/rails_app/config/initializers/cookies_serializer.rb +1 -1
  11. data/example/rails_app/db/schema.rb +5 -7
  12. data/example/rails_app/spec/rails_helper.rb +2 -2
  13. data/example/rails_app/spec/spec_helper.rb +0 -1
  14. data/example/rails_app/test/controllers/beavers_controller_test.rb +12 -12
  15. data/flip_fab.gemspec +9 -8
  16. data/lib/flip_fab.rb +3 -3
  17. data/lib/flip_fab/contextual_feature.rb +11 -17
  18. data/lib/flip_fab/cookie_persistence.rb +11 -16
  19. data/lib/flip_fab/feature.rb +2 -3
  20. data/lib/flip_fab/features_by_name.rb +4 -4
  21. data/lib/flip_fab/helper.rb +0 -1
  22. data/lib/flip_fab/persistence.rb +2 -3
  23. data/lib/flip_fab/version.rb +1 -1
  24. data/script/cibuild +10 -0
  25. data/spec/lib/flip_fab/contextual_feature_spec.rb +47 -56
  26. data/spec/lib/flip_fab/cookie_persistence_spec.rb +40 -43
  27. data/spec/lib/flip_fab/feature_spec.rb +6 -9
  28. data/spec/lib/flip_fab/features_by_name_spec.rb +3 -6
  29. data/spec/lib/flip_fab/helper_spec.rb +35 -38
  30. data/spec/lib/flip_fab/persistence_spec.rb +2 -5
  31. data/spec/lib/flip_fab_spec.rb +11 -15
  32. data/spec/spec_helper.rb +47 -49
  33. data/spec/support/test_app.rb +2 -2
  34. data/spec/support/test_context.rb +1 -1
  35. data/spec/support/test_multiple_persistence.rb +2 -3
  36. data/spec/support/test_persistence.rb +2 -3
  37. data/spec/support/test_rack_context.rb +3 -3
  38. metadata +38 -25
  39. data/example/rails_app/README.rdoc +0 -28
  40. data/example/rails_app/config/rabbit_feed.yml +0 -8
  41. data/example/rails_app/config/unicorn.rb +0 -4
@@ -1,6 +1,5 @@
1
1
  module FlipFab
2
2
  module Helper
3
-
4
3
  def features
5
4
  @features ||= FlipFab.features.with_context self
6
5
  end
@@ -1,9 +1,8 @@
1
1
  module FlipFab
2
2
  class Persistence
3
-
4
3
  attr_reader :feature_name, :context
5
4
 
6
- def initialize feature_name, context
5
+ def initialize(feature_name, context)
7
6
  @feature_name = feature_name
8
7
  @context = context
9
8
  end
@@ -12,7 +11,7 @@ module FlipFab
12
11
  raise NotImplementedError
13
12
  end
14
13
 
15
- def write state
14
+ def write(state)
16
15
  raise NotImplementedError
17
16
  end
18
17
  end
@@ -1,3 +1,3 @@
1
1
  module FlipFab
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'.freeze
3
3
  end
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ # script/cibuild: Setup environment for CI to run tests. This is primarily
4
+ # designed to run on the continuous integration server.
5
+
6
+ set -e
7
+
8
+ cd "$(dirname "$0")/.."
9
+ bundle exec rubocop --fail-level warning
10
+
@@ -1,15 +1,14 @@
1
1
  module FlipFab
2
2
  describe ContextualFeature do
3
- let(:override) { }
3
+ let(:override) {}
4
4
  let(:default) { :disabled }
5
5
  let(:persistence_adapters) { [TestPersistence] }
6
- let(:feature) { Feature.new :example_feature, { default: default, persistence_adapters: persistence_adapters } }
7
- let(:feature_states) {{ example_feature: :enabled }}
8
- let(:context) { TestContext.new feature_states, { 'example_feature' => override } }
9
- subject{ described_class.new feature, context }
6
+ let(:feature) { Feature.new :example_feature, default: default, persistence_adapters: persistence_adapters }
7
+ let(:feature_states) { { example_feature: :enabled } }
8
+ let(:context) { TestContext.new feature_states, 'example_feature' => override }
9
+ subject { described_class.new feature, context }
10
10
 
11
11
  describe '.new' do
12
-
13
12
  it 'assigns the feature' do
14
13
  expect(subject.feature).to eq(feature)
15
14
  end
@@ -22,23 +21,22 @@ module FlipFab
22
21
  let(:override) { 'disabled' }
23
22
 
24
23
  it 'persists the override' do
25
- expect{ subject }.to change{ feature_states }.from({ example_feature: :enabled }).to({ example_feature: :disabled })
24
+ expect { subject }.to change { feature_states }.from(example_feature: :enabled).to(example_feature: :disabled)
26
25
  end
27
26
 
28
27
  context 'when the override provided is not one of enabled or disabled, it does not persist the override' do
29
28
  let(:override) { '' }
30
29
 
31
30
  it 'does not persist the override' do
32
- expect{ subject }.not_to change{ feature_states }.from({ example_feature: :enabled })
31
+ expect { subject }.not_to change { feature_states }.from(example_feature: :enabled)
33
32
  end
34
33
  end
35
34
  end
36
35
  end
37
36
 
38
37
  describe '#enabled?' do
39
-
40
38
  context 'when the feature is enabled in the adapter' do
41
- let(:feature_states) {{ example_feature: :enabled }}
39
+ let(:feature_states) { { example_feature: :enabled } }
42
40
 
43
41
  it 'returns true' do
44
42
  expect(subject.enabled?).to be_truthy
@@ -54,7 +52,7 @@ module FlipFab
54
52
  end
55
53
 
56
54
  context 'when the feature is disabled in the adapter' do
57
- let(:feature_states) {{ example_feature: :disabled }}
55
+ let(:feature_states) { { example_feature: :disabled } }
58
56
 
59
57
  it 'returns false' do
60
58
  expect(subject.enabled?).to be_falsey
@@ -62,7 +60,7 @@ module FlipFab
62
60
  end
63
61
 
64
62
  context 'when the feature is not specified in the adapter' do
65
- let(:feature_states) {{ }}
63
+ let(:feature_states) { {} }
66
64
 
67
65
  context 'when the default is :enabled' do
68
66
  let(:default) { :enabled }
@@ -85,7 +83,7 @@ module FlipFab
85
83
  let(:persistence_adapters) { [TestPersistence, TestMultiplePersistence] }
86
84
 
87
85
  context 'when the first adapter has enabled and the second adapter has nil' do
88
- let(:feature_states) {{ example_feature: :enabled, different_example_feature: nil }}
86
+ let(:feature_states) { { example_feature: :enabled, different_example_feature: nil } }
89
87
 
90
88
  it 'returns true' do
91
89
  expect(subject.enabled?).to be_truthy
@@ -93,7 +91,7 @@ module FlipFab
93
91
  end
94
92
 
95
93
  context 'when the first adapter has nil and the second adapter has enabled' do
96
- let(:feature_states) {{ example_feature: nil, different_example_feature: :enabled }}
94
+ let(:feature_states) { { example_feature: nil, different_example_feature: :enabled } }
97
95
 
98
96
  it 'returns true' do
99
97
  expect(subject.enabled?).to be_truthy
@@ -101,7 +99,7 @@ module FlipFab
101
99
  end
102
100
 
103
101
  context 'when the first adapter has disabled and the second adapter has enabled' do
104
- let(:feature_states) {{ example_feature: :disabled, different_example_feature: :enabled }}
102
+ let(:feature_states) { { example_feature: :disabled, different_example_feature: :enabled } }
105
103
 
106
104
  it 'returns false' do
107
105
  expect(subject.enabled?).to be_falsey
@@ -111,9 +109,8 @@ module FlipFab
111
109
  end
112
110
 
113
111
  describe '#disabled?' do
114
-
115
112
  context 'when #enabled? returns true' do
116
- let(:feature_states) {{ example_feature: :enabled }}
113
+ let(:feature_states) { { example_feature: :enabled } }
117
114
 
118
115
  it 'returns false' do
119
116
  expect(subject.disabled?).to be_falsey
@@ -121,7 +118,7 @@ module FlipFab
121
118
  end
122
119
 
123
120
  context 'when #enabled? returns false' do
124
- let(:feature_states) {{ example_feature: :disabled }}
121
+ let(:feature_states) { { example_feature: :disabled } }
125
122
 
126
123
  it 'returns true' do
127
124
  expect(subject.disabled?).to be_truthy
@@ -130,34 +127,30 @@ module FlipFab
130
127
  end
131
128
 
132
129
  describe '#state=' do
133
-
134
130
  context 'when the provided value is not :enabled or :disabled' do
135
-
136
131
  it 'raises' do
137
- expect{ subject.state = '' }.to raise_error 'Invalid state provided: ``, possible states are :enabled, :disabled'
138
- expect{ subject.state = 'enabled' }.to raise_error 'Invalid state provided: `enabled`, possible states are :enabled, :disabled'
132
+ expect { subject.state = '' }.to raise_error 'Invalid state provided: ``, possible states are :enabled, :disabled'
133
+ expect { subject.state = 'enabled' }.to raise_error 'Invalid state provided: `enabled`, possible states are :enabled, :disabled'
139
134
  end
140
135
  end
141
136
 
142
137
  context 'when the provided value is :enabled or :disabled' do
143
-
144
138
  it 'changes the state of the feature' do
145
- expect{ subject.state = :disabled }.to change{subject.enabled?}.from(true).to(false)
146
- expect{ subject.state = :enabled }.to change{subject.enabled?}.from(false).to(true)
139
+ expect { subject.state = :disabled }.to change { subject.enabled? }.from(true).to(false)
140
+ expect { subject.state = :enabled }.to change { subject.enabled? }.from(false).to(true)
147
141
  end
148
142
  end
149
143
  end
150
144
 
151
145
  describe '#enable' do
152
-
153
146
  context 'when the state has been overridden' do
154
147
  let(:override) { 'disabled' }
155
148
 
156
149
  context 'and the persistence adapter has the opposite state' do
157
- let(:feature_states) {{ example_feature: :disabled }}
150
+ let(:feature_states) { { example_feature: :disabled } }
158
151
 
159
152
  it 'does not change the state of the feature' do
160
- expect{subject.enable}.not_to change{subject.enabled?}.from(false)
153
+ expect { subject.enable }.not_to change { subject.enabled? }.from(false)
161
154
  end
162
155
 
163
156
  it 'does not persist the state in the adapter' do
@@ -169,14 +162,14 @@ module FlipFab
169
162
 
170
163
  context 'when there are multiple persistence adapters' do
171
164
  let(:persistence_adapters) { [TestPersistence, TestMultiplePersistence] }
172
- let(:feature_states) {{ example_feature: :disabled, different_example_feature: :disabled }}
165
+ let(:feature_states) { { example_feature: :disabled, different_example_feature: :disabled } }
173
166
 
174
167
  it 'changes the state of the feature' do
175
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
168
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
176
169
  end
177
170
 
178
171
  it 'persists the state in the adapters' do
179
- expect{ subject.enable }.to change{ feature_states }.from({ example_feature: :disabled, different_example_feature: :disabled }).to({ example_feature: :enabled, different_example_feature: :enabled })
172
+ expect { subject.enable }.to change { feature_states }.from(example_feature: :disabled, different_example_feature: :disabled).to(example_feature: :enabled, different_example_feature: :enabled)
180
173
  end
181
174
  end
182
175
 
@@ -184,37 +177,37 @@ module FlipFab
184
177
  let(:persistence_adapters) { [TestPersistence] }
185
178
 
186
179
  context 'and the persistence adapter has the same state' do
187
- let(:feature_states) {{ example_feature: :enabled }}
180
+ let(:feature_states) { { example_feature: :enabled } }
188
181
 
189
182
  it 'does not change the state of the feature' do
190
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
183
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
191
184
  end
192
185
  end
193
186
 
194
187
  context 'and the persistence adapter has the opposite state' do
195
- let(:feature_states) {{ example_feature: :disabled }}
188
+ let(:feature_states) { { example_feature: :disabled } }
196
189
 
197
190
  it 'changes the state of the feature' do
198
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
191
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
199
192
  end
200
193
 
201
194
  it 'persists the state in the adapter' do
202
- expect{ subject.enable }.to change{ feature_states }.from({ example_feature: :disabled }).to({ example_feature: :enabled })
195
+ expect { subject.enable }.to change { feature_states }.from(example_feature: :disabled).to(example_feature: :enabled)
203
196
  end
204
197
  end
205
198
 
206
199
  context 'and the persistence adapter has no state' do
207
- let(:feature_states) {{ }}
200
+ let(:feature_states) { {} }
208
201
 
209
202
  context 'and the feature is disabled' do
210
203
  let(:default) { :disabled }
211
204
 
212
205
  it 'changes the state of the feature' do
213
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
206
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
214
207
  end
215
208
 
216
209
  it 'persists the state in the adapter' do
217
- expect{ subject.enable }.to change{ feature_states }.from({ }).to({ example_feature: :enabled })
210
+ expect { subject.enable }.to change { feature_states }.from({}).to(example_feature: :enabled)
218
211
  end
219
212
  end
220
213
 
@@ -222,11 +215,11 @@ module FlipFab
222
215
  let(:default) { :enabled }
223
216
 
224
217
  it 'does not change the state of the feature' do
225
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
218
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
226
219
  end
227
220
 
228
221
  it 'persists the state in the adapter' do
229
- expect{ subject.enable }.to change{ feature_states }.from({ }).to({ example_feature: :enabled })
222
+ expect { subject.enable }.to change { feature_states }.from({}).to(example_feature: :enabled)
230
223
  end
231
224
  end
232
225
  end
@@ -238,7 +231,7 @@ module FlipFab
238
231
  let(:default) { :enabled }
239
232
 
240
233
  it 'does not change the state of the feature' do
241
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
234
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
242
235
  end
243
236
  end
244
237
 
@@ -246,24 +239,22 @@ module FlipFab
246
239
  let(:default) { :disabled }
247
240
 
248
241
  it 'changes the state of the feature' do
249
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
242
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
250
243
  end
251
244
  end
252
245
  end
253
246
  end
254
247
  end
255
248
 
256
-
257
249
  describe '#disable' do
258
-
259
250
  context 'when the state has been overridden' do
260
251
  let(:override) { 'enabled' }
261
252
 
262
253
  context 'and the persistence adapter has the opposite state' do
263
- let(:feature_states) {{ example_feature: :enabled }}
254
+ let(:feature_states) { { example_feature: :enabled } }
264
255
 
265
256
  it 'does not change the state of the feature' do
266
- expect{subject.disable}.not_to change{subject.disabled?}.from(false)
257
+ expect { subject.disable }.not_to change { subject.disabled? }.from(false)
267
258
  end
268
259
 
269
260
  it 'does not persist the state in the adapter' do
@@ -277,18 +268,18 @@ module FlipFab
277
268
  let(:persistence_adapters) { [TestPersistence] }
278
269
 
279
270
  context 'and the persistence adapter has the same state' do
280
- let(:feature_states) {{ example_feature: :disabled }}
271
+ let(:feature_states) { { example_feature: :disabled } }
281
272
 
282
273
  it 'does not change the state of the feature' do
283
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
274
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
284
275
  end
285
276
  end
286
277
 
287
278
  context 'and the persistence adapter has the opposite state' do
288
- let(:feature_states) {{ example_feature: :enabled }}
279
+ let(:feature_states) { { example_feature: :enabled } }
289
280
 
290
281
  it 'changes the state of the feature' do
291
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
282
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
292
283
  end
293
284
 
294
285
  it 'persists the state in the adapter' do
@@ -298,13 +289,13 @@ module FlipFab
298
289
  end
299
290
 
300
291
  context 'and the persistence adapter has no state' do
301
- let(:feature_states) {{ }}
292
+ let(:feature_states) { {} }
302
293
 
303
294
  context 'and the feature is enabled' do
304
295
  let(:default) { :enabled }
305
296
 
306
297
  it 'changes the state of the feature' do
307
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
298
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
308
299
  end
309
300
 
310
301
  it 'persists the state in the adapter' do
@@ -317,7 +308,7 @@ module FlipFab
317
308
  let(:default) { :disabled }
318
309
 
319
310
  it 'does not change the state of the feature' do
320
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
311
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
321
312
  end
322
313
 
323
314
  it 'persists the state in the adapter' do
@@ -334,7 +325,7 @@ module FlipFab
334
325
  let(:default) { :disabled }
335
326
 
336
327
  it 'does not change the state of the feature' do
337
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
328
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
338
329
  end
339
330
  end
340
331
 
@@ -342,7 +333,7 @@ module FlipFab
342
333
  let(:default) { :enabled }
343
334
 
344
335
  it 'changes the state of the feature' do
345
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
336
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
346
337
  end
347
338
  end
348
339
  end
@@ -3,66 +3,63 @@ require 'timecop'
3
3
 
4
4
  module FlipFab
5
5
  describe CookiePersistence do
6
- let(:cookies) { }
6
+ let(:cookies) {}
7
7
  let(:context) { TestRackContext.new cookies, 'simplybusiness.co.uk' }
8
8
  before { FlipFab.define_feature :example_feature }
9
9
  after { FlipFab.features.clear }
10
- subject{ described_class.new :example_feature, context }
10
+ subject { described_class.new :example_feature, context }
11
11
 
12
- it 'runs the feature' do
13
- feature
14
- end
15
-
16
- step 'the host is :host' do |host|
17
- @host = host
18
- end
12
+ feature do
13
+ step 'the host is :host' do |host|
14
+ @host = host
15
+ end
19
16
 
20
- step 'the feature name is :feature_name' do |feature_name|
21
- @feature_name = feature_name
22
- end
17
+ step 'the feature name is :feature_name' do |feature_name|
18
+ @feature_name = feature_name
19
+ end
23
20
 
24
- step 'the time is :current_time' do |current_time|
25
- Timecop.freeze(Time.parse current_time)
26
- end
21
+ step 'the time is :current_time' do |current_time|
22
+ Timecop.freeze(Time.parse(current_time))
23
+ end
27
24
 
28
- step 'the state of the feature is :feature_state' do |feature_state|
29
- @feature_state = feature_state
30
- end
25
+ step 'the state of the feature is :feature_state' do |feature_state|
26
+ @feature_state = feature_state
27
+ end
31
28
 
32
- step 'I persist the feature state in a cookie' do
33
- context = TestRackContext.new '', @host
34
- (described_class.new @feature_name, context).write @feature_state
35
- @cookie = context.response_cookies
36
- end
29
+ step 'I persist the feature state in a cookie' do
30
+ context = TestRackContext.new '', @host
31
+ (described_class.new @feature_name, context).write @feature_state
32
+ @cookie = context.response_cookies
33
+ end
37
34
 
38
- step 'the cookie has the path :path' do |path|
39
- expect(@cookie).to match(/path=#{path};/)
40
- end
35
+ step 'the cookie has the path :path' do |path|
36
+ expect(@cookie).to match(/path=#{path};/)
37
+ end
41
38
 
42
- step 'the cookie has the domain :domain' do |domain|
43
- if domain == ''
44
- expect(@cookie).not_to match(/domain/)
45
- else
46
- expect(@cookie).to match(/domain=#{domain};/)
39
+ step 'the cookie has the domain :domain' do |domain|
40
+ if domain == ''
41
+ expect(@cookie).not_to match(/domain/)
42
+ else
43
+ expect(@cookie).to match(/domain=#{domain};/)
44
+ end
47
45
  end
48
- end
49
46
 
50
- step 'the cookie has the name :name' do |name|
51
- expect(@cookie).to match(/\A#{name}.*/)
52
- end
47
+ step 'the cookie has the name :name' do |name|
48
+ expect(@cookie).to match(/\A#{name}.*/)
49
+ end
53
50
 
54
- step 'the cookie expires at :expiration' do |expiration|
55
- expect(@cookie).to match(/expires=#{expiration}\Z/)
56
- end
51
+ step 'the cookie expires at :expiration' do |expiration|
52
+ expect(@cookie).to match(/expires=#{expiration}\Z/)
53
+ end
57
54
 
58
- step 'the cookie value is :value' do |value|
59
- expect(@cookie).to match(/\=#{value};/)
55
+ step 'the cookie value is :value' do |value|
56
+ expect(@cookie).to match(/\=#{value};/)
57
+ end
60
58
  end
61
59
 
62
60
  describe '#read' do
63
-
64
61
  context 'when there is no existing cookie' do
65
- let(:cookies) { }
62
+ let(:cookies) {}
66
63
 
67
64
  it 'returns nil' do
68
65
  expect(subject.read).to be_nil
@@ -83,7 +80,7 @@ module FlipFab
83
80
  after { Timecop.return }
84
81
 
85
82
  it 'saves the feature state' do
86
- expect{ subject.write :enabled }.to change{ context.response_cookies }.from(nil).to('flip_fab.example_feature=enabled; domain=.simplybusiness.co.uk; path=/; expires=Tue, 01 Jan 1991 00:00:00 -0000')
83
+ expect { subject.write :enabled }.to change { context.response_cookies }.from(nil).to('flip_fab.example_feature=enabled; domain=.simplybusiness.co.uk; path=/; expires=Tue, 01 Jan 1991 00:00:00 -0000')
87
84
  end
88
85
  end
89
86
  end