flip_fab 1.0.0 → 1.0.16

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 (65) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +18 -0
  3. data/.github/workflows/dobby-actions.yml +29 -0
  4. data/.github/workflows/gem-publish.yml +46 -0
  5. data/.github/workflows/version-forget-me-not.yml +19 -0
  6. data/.gitignore +2 -0
  7. data/.rubocop.yml +31 -0
  8. data/.rubocop_todo.yml +58 -0
  9. data/.ruby-version +1 -0
  10. data/.semaphore/semaphore.yml +49 -0
  11. data/CODEOWNERS +3 -0
  12. data/Gemfile +0 -12
  13. data/README.md +8 -2
  14. data/_pipeline/step_build_gem.sh +5 -0
  15. data/_pipeline/step_test_gem.sh +6 -0
  16. data/catalog-info.yaml +8 -0
  17. data/example/rails_app/Gemfile +4 -21
  18. data/example/rails_app/Rakefile +1 -1
  19. data/example/rails_app/app/assets/config/manifest.js +3 -0
  20. data/example/rails_app/app/assets/javascripts/application.js +0 -1
  21. data/example/rails_app/app/controllers/beavers_controller.rb +12 -13
  22. data/example/rails_app/bin/bundle +1 -1
  23. data/example/rails_app/bin/rails +1 -1
  24. data/example/rails_app/config/application.rb +2 -2
  25. data/example/rails_app/config/boot.rb +1 -1
  26. data/example/rails_app/config/environment.rb +1 -1
  27. data/example/rails_app/config/environments/development.rb +1 -1
  28. data/example/rails_app/config/environments/test.rb +2 -2
  29. data/example/rails_app/config/initializers/cookies_serializer.rb +1 -1
  30. data/example/rails_app/config.ru +1 -1
  31. data/example/rails_app/db/schema.rb +5 -8
  32. data/example/rails_app/spec/rails_helper.rb +2 -2
  33. data/example/rails_app/spec/spec_helper.rb +0 -1
  34. data/example/rails_app/test/controllers/beavers_controller_test.rb +12 -12
  35. data/example/rails_app/test/test_helper.rb +1 -1
  36. data/flip_fab.gemspec +11 -5
  37. data/lib/flip_fab/contextual_feature.rb +23 -19
  38. data/lib/flip_fab/cookie_persistence.rb +10 -17
  39. data/lib/flip_fab/feature.rb +2 -3
  40. data/lib/flip_fab/features_by_name.rb +5 -4
  41. data/lib/flip_fab/helper.rb +0 -1
  42. data/lib/flip_fab/persistence.rb +2 -3
  43. data/lib/flip_fab/version.rb +6 -1
  44. data/lib/flip_fab.rb +4 -4
  45. data/script/cibuild +10 -0
  46. data/spec/lib/flip_fab/contextual_feature_spec.rb +54 -57
  47. data/spec/lib/flip_fab/cookie_persistence.feature +3 -3
  48. data/spec/lib/flip_fab/cookie_persistence_spec.rb +36 -43
  49. data/spec/lib/flip_fab/feature_spec.rb +6 -9
  50. data/spec/lib/flip_fab/features_by_name_spec.rb +3 -6
  51. data/spec/lib/flip_fab/helper_spec.rb +35 -38
  52. data/spec/lib/flip_fab/persistence_spec.rb +2 -5
  53. data/spec/lib/flip_fab_spec.rb +11 -15
  54. data/spec/spec_helper.rb +47 -49
  55. data/spec/support/test_app.rb +2 -2
  56. data/spec/support/test_context.rb +1 -1
  57. data/spec/support/test_multiple_persistence.rb +2 -3
  58. data/spec/support/test_persistence.rb +2 -3
  59. data/spec/support/test_rack_context.rb +3 -3
  60. metadata +103 -11
  61. data/Gemfile.lock +0 -92
  62. data/example/rails_app/Gemfile.lock +0 -178
  63. data/example/rails_app/README.rdoc +0 -28
  64. data/example/rails_app/config/rabbit_feed.yml +0 -8
  65. data/example/rails_app/config/unicorn.rb +0 -4
data/flip_fab.gemspec CHANGED
@@ -1,5 +1,4 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'flip_fab/version'
5
4
 
@@ -8,13 +7,20 @@ Gem::Specification.new do |spec|
8
7
  spec.version = FlipFab::VERSION
9
8
  spec.authors = ['Simply Business']
10
9
  spec.email = ['tech@simplybusiness.co.uk']
11
- spec.description = %q{A gem providing persistent, per-user feature flipping to Rack applications.}
12
- spec.summary = %q{A gem providing persistent, per-user feature flipping to Rack applications.}
10
+ spec.description = 'A gem providing persistent, per-user feature flipping to Rack applications.'
11
+ spec.summary = 'A gem providing persistent, per-user feature flipping to Rack applications.'
13
12
  spec.homepage = 'https://github.com/simplybusiness/flip_fab'
14
13
  spec.license = 'MIT'
15
14
 
16
- spec.files = `git ls-files`.split($/)
15
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
18
  spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'rack', '>=2.1.1'
21
+ spec.add_development_dependency 'rack-test'
22
+ spec.add_development_dependency 'rspec', '~> 3.5'
23
+ spec.add_development_dependency 'rutabaga', '~> 3.0'
24
+ spec.add_development_dependency 'simplycop', '~> 1.9'
25
+ spec.add_development_dependency 'timecop', '~> 0.8'
20
26
  end
@@ -2,13 +2,19 @@ module FlipFab
2
2
  class ContextualFeature
3
3
  attr_reader :feature, :context
4
4
 
5
- def initialize feature, context
5
+ def initialize(feature, context)
6
6
  @feature = feature
7
7
  @context = context
8
- if overridden?
9
- @state = override
10
- persist
11
- end
8
+ return unless overridden?
9
+
10
+ @state = override
11
+ persist
12
+ end
13
+
14
+ def as_json(options = {})
15
+ {
16
+ 'feature' => feature.as_json(options)
17
+ }
12
18
  end
13
19
 
14
20
  def enabled?
@@ -27,16 +33,16 @@ module FlipFab
27
33
  self.state = :disabled
28
34
  end
29
35
 
30
- def state= value
31
- raise "Invalid state provided: `#{value}`, possible states are :enabled, :disabled" unless %i(enabled disabled).include? value
32
- unless overridden?
33
- @state = value
34
- persist
35
- end
36
+ def state=(value)
37
+ raise "Invalid state provided: `#{value}`, possible states are :enabled, :disabled" unless %i[enabled disabled].include? value
38
+ return if overridden?
39
+
40
+ @state = value
41
+ persist
36
42
  end
37
43
 
38
44
  def persist
39
- persistence_adapters.each{ |adapter| adapter.write state }
45
+ persistence_adapters.each { |adapter| adapter.write state }
40
46
  end
41
47
 
42
48
  private
@@ -46,11 +52,7 @@ module FlipFab
46
52
  end
47
53
 
48
54
  def state
49
- @state ||= if state_in_context?
50
- state_from_context
51
- else
52
- default_state
53
- end
55
+ @state ||= state_in_context? ? state_from_context : default_state
54
56
  end
55
57
 
56
58
  def state_in_context?
@@ -62,7 +64,7 @@ module FlipFab
62
64
  end
63
65
 
64
66
  def first_adapter_with_state
65
- persistence_adapters.detect{|adapter| !adapter.read.nil?}
67
+ persistence_adapters.detect { |adapter| !adapter.read.nil? }
66
68
  end
67
69
 
68
70
  def default_state
@@ -71,8 +73,10 @@ module FlipFab
71
73
 
72
74
  def override
73
75
  return unless context.respond_to? :params
76
+
74
77
  override = context.params[feature.name.to_s]
75
- return unless %w(enabled disabled).include? override
78
+ return unless %w[enabled disabled].include? override
79
+
76
80
  override.to_sym
77
81
  end
78
82
 
@@ -1,12 +1,11 @@
1
1
  module FlipFab
2
2
  class CookiePersistence < FlipFab::Persistence
3
+ COOKIE_PATH = '/'.freeze
4
+ COOKIE_DURATION_MONTHS = 12
5
+ # See: https://github.com/rails/rails/blob/b1124a2ac88778c0feb0157ac09367cbd204bf01/actionpack/lib/action_dispatch/middleware/cookies.rb#L214
6
+ DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
3
7
 
4
- COOKIE_PATH = '/'
5
- COOKIE_DURATION_MONTHS = 12
6
- # See: https://github.com/rails/rails/blob/b1124a2ac88778c0feb0157ac09367cbd204bf01/actionpack/lib/action_dispatch/middleware/cookies.rb#L214
7
- DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
8
-
9
- def initialize feature_name, context
8
+ def initialize(feature_name, context)
10
9
  super
11
10
  end
12
11
 
@@ -14,14 +13,10 @@ module FlipFab
14
13
  value.to_sym unless value.nil?
15
14
  end
16
15
 
17
- def write state
18
- cookie_domain = ".#{top_level_domain}" unless top_level_domain.nil?
19
- context.response.set_cookie key, {
20
- value: state,
21
- expires: cookie_expiration,
22
- domain: cookie_domain,
23
- path: COOKIE_PATH,
24
- }
16
+ def write(state)
17
+ context.response.set_cookie key, value: state,
18
+ expires: cookie_expiration,
19
+ path: COOKIE_PATH
25
20
  end
26
21
 
27
22
  private
@@ -36,9 +31,7 @@ module FlipFab
36
31
 
37
32
  # See: https://github.com/rails/rails/blob/b1124a2ac88778c0feb0157ac09367cbd204bf01/actionpack/lib/action_dispatch/middleware/cookies.rb#L286-L294
38
33
  def top_level_domain
39
- if (host !~ /^[\d.]+$/) && (host =~ DOMAIN_REGEXP)
40
- $&
41
- end
34
+ Regexp.last_match(0) if (host !~ /^[\d.]+$/) && (host =~ DOMAIN_REGEXP)
42
35
  end
43
36
 
44
37
  def cookie_expiration
@@ -1,9 +1,8 @@
1
1
  module FlipFab
2
2
  class Feature
3
-
4
3
  attr_reader :name, :default, :persistence_adapters
5
4
 
6
- def initialize name, options={}
5
+ def initialize(name, options = {})
7
6
  @name = name
8
7
  @default = options[:default] || :disabled
9
8
  @persistence_adapters = options[:persistence_adapters] || [CookiePersistence]
@@ -17,7 +16,7 @@ module FlipFab
17
16
  !enabled?
18
17
  end
19
18
 
20
- def with_context context
19
+ def with_context(context)
21
20
  ContextualFeature.new self, context
22
21
  end
23
22
  end
@@ -4,17 +4,18 @@ module FlipFab
4
4
  class FeaturesByName
5
5
  extend Forwardable
6
6
 
7
- def initialize features_by_name={}
7
+ def initialize(features_by_name = {})
8
8
  @features_by_name = features_by_name
9
9
  end
10
10
 
11
- def [] name
11
+ def [](name)
12
12
  raise "no feature has been defined with the name: #{name}" if @features_by_name[name].nil?
13
+
13
14
  @features_by_name[name]
14
15
  end
15
16
 
16
- def with_context context
17
- FeaturesByName.new Hash[@features_by_name.map{|name, feature| [name, (feature.with_context context)]}]
17
+ def with_context(context)
18
+ FeaturesByName.new Hash[@features_by_name.map { |name, feature| [name, (feature.with_context context)] }]
18
19
  end
19
20
 
20
21
  def_delegators :@features_by_name, :[]=, :clear, :count, :each
@@ -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,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FlipFab
2
- VERSION = '1.0.0'
4
+ base = '1.0.16'
5
+
6
+ # SB-specific versioning "algorithm" to accommodate BNW/Jenkins/gemstash
7
+ VERSION = (pre = ENV.fetch('GEM_PRE_RELEASE', '')).empty? ? base : "#{base}.#{pre}"
3
8
  end
data/lib/flip_fab.rb CHANGED
@@ -6,19 +6,19 @@ require 'flip_fab/persistence'
6
6
  require 'flip_fab/cookie_persistence'
7
7
 
8
8
  module FlipFab
9
- extend self
10
-
11
9
  attr_reader :features
12
10
 
13
- def define_feature name, options={}
11
+ def define_feature(name, options = {})
14
12
  @features ||= {}
15
13
  @features[name] = Feature.new name, options
16
14
  end
17
15
 
18
16
  @features ||= FeaturesByName.new
17
+
18
+ module_function :features, :define_feature
19
19
  end
20
20
 
21
21
  if defined?(ActionController)
22
- ActionController::Base.send :include, FlipFab::Helper
22
+ ActionController::Base.include FlipFab::Helper
23
23
  ActionController::Base.helper FlipFab::Helper
24
24
  end
data/script/cibuild ADDED
@@ -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,20 @@
1
1
  module FlipFab
2
- describe ContextualFeature do
3
- let(:override) { }
2
+ describe ContextualFeature do # rubocop:disable Metrics/BlockLength
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
+
11
+ describe '.as_json' do
12
+ it 'returns only the feature' do
13
+ expect(subject.as_json.keys).to eq(['feature'])
14
+ end
15
+ end
10
16
 
11
17
  describe '.new' do
12
-
13
18
  it 'assigns the feature' do
14
19
  expect(subject.feature).to eq(feature)
15
20
  end
@@ -22,23 +27,22 @@ module FlipFab
22
27
  let(:override) { 'disabled' }
23
28
 
24
29
  it 'persists the override' do
25
- expect{ subject }.to change{ feature_states }.from({ example_feature: :enabled }).to({ example_feature: :disabled })
30
+ expect { subject }.to change { feature_states }.from(example_feature: :enabled).to(example_feature: :disabled)
26
31
  end
27
32
 
28
33
  context 'when the override provided is not one of enabled or disabled, it does not persist the override' do
29
34
  let(:override) { '' }
30
35
 
31
36
  it 'does not persist the override' do
32
- expect{ subject }.not_to change{ feature_states }.from({ example_feature: :enabled })
37
+ expect { subject }.not_to change { feature_states }.from(example_feature: :enabled)
33
38
  end
34
39
  end
35
40
  end
36
41
  end
37
42
 
38
43
  describe '#enabled?' do
39
-
40
44
  context 'when the feature is enabled in the adapter' do
41
- let(:feature_states) {{ example_feature: :enabled }}
45
+ let(:feature_states) { { example_feature: :enabled } }
42
46
 
43
47
  it 'returns true' do
44
48
  expect(subject.enabled?).to be_truthy
@@ -54,7 +58,7 @@ module FlipFab
54
58
  end
55
59
 
56
60
  context 'when the feature is disabled in the adapter' do
57
- let(:feature_states) {{ example_feature: :disabled }}
61
+ let(:feature_states) { { example_feature: :disabled } }
58
62
 
59
63
  it 'returns false' do
60
64
  expect(subject.enabled?).to be_falsey
@@ -62,7 +66,7 @@ module FlipFab
62
66
  end
63
67
 
64
68
  context 'when the feature is not specified in the adapter' do
65
- let(:feature_states) {{ }}
69
+ let(:feature_states) { {} }
66
70
 
67
71
  context 'when the default is :enabled' do
68
72
  let(:default) { :enabled }
@@ -85,7 +89,7 @@ module FlipFab
85
89
  let(:persistence_adapters) { [TestPersistence, TestMultiplePersistence] }
86
90
 
87
91
  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 }}
92
+ let(:feature_states) { { example_feature: :enabled, different_example_feature: nil } }
89
93
 
90
94
  it 'returns true' do
91
95
  expect(subject.enabled?).to be_truthy
@@ -93,7 +97,7 @@ module FlipFab
93
97
  end
94
98
 
95
99
  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 }}
100
+ let(:feature_states) { { example_feature: nil, different_example_feature: :enabled } }
97
101
 
98
102
  it 'returns true' do
99
103
  expect(subject.enabled?).to be_truthy
@@ -101,7 +105,7 @@ module FlipFab
101
105
  end
102
106
 
103
107
  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 }}
108
+ let(:feature_states) { { example_feature: :disabled, different_example_feature: :enabled } }
105
109
 
106
110
  it 'returns false' do
107
111
  expect(subject.enabled?).to be_falsey
@@ -111,9 +115,8 @@ module FlipFab
111
115
  end
112
116
 
113
117
  describe '#disabled?' do
114
-
115
118
  context 'when #enabled? returns true' do
116
- let(:feature_states) {{ example_feature: :enabled }}
119
+ let(:feature_states) { { example_feature: :enabled } }
117
120
 
118
121
  it 'returns false' do
119
122
  expect(subject.disabled?).to be_falsey
@@ -121,7 +124,7 @@ module FlipFab
121
124
  end
122
125
 
123
126
  context 'when #enabled? returns false' do
124
- let(:feature_states) {{ example_feature: :disabled }}
127
+ let(:feature_states) { { example_feature: :disabled } }
125
128
 
126
129
  it 'returns true' do
127
130
  expect(subject.disabled?).to be_truthy
@@ -130,34 +133,30 @@ module FlipFab
130
133
  end
131
134
 
132
135
  describe '#state=' do
133
-
134
136
  context 'when the provided value is not :enabled or :disabled' do
135
-
136
137
  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'
138
+ expect { subject.state = '' }.to raise_error 'Invalid state provided: ``, possible states are :enabled, :disabled'
139
+ expect { subject.state = 'enabled' }.to raise_error 'Invalid state provided: `enabled`, possible states are :enabled, :disabled'
139
140
  end
140
141
  end
141
142
 
142
143
  context 'when the provided value is :enabled or :disabled' do
143
-
144
144
  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)
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)
147
147
  end
148
148
  end
149
149
  end
150
150
 
151
151
  describe '#enable' do
152
-
153
152
  context 'when the state has been overridden' do
154
153
  let(:override) { 'disabled' }
155
154
 
156
155
  context 'and the persistence adapter has the opposite state' do
157
- let(:feature_states) {{ example_feature: :disabled }}
156
+ let(:feature_states) { { example_feature: :disabled } }
158
157
 
159
158
  it 'does not change the state of the feature' do
160
- expect{subject.enable}.not_to change{subject.enabled?}.from(false)
159
+ expect { subject.enable }.not_to change { subject.enabled? }.from(false)
161
160
  end
162
161
 
163
162
  it 'does not persist the state in the adapter' do
@@ -169,14 +168,14 @@ module FlipFab
169
168
 
170
169
  context 'when there are multiple persistence adapters' do
171
170
  let(:persistence_adapters) { [TestPersistence, TestMultiplePersistence] }
172
- let(:feature_states) {{ example_feature: :disabled, different_example_feature: :disabled }}
171
+ let(:feature_states) { { example_feature: :disabled, different_example_feature: :disabled } }
173
172
 
174
173
  it 'changes the state of the feature' do
175
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
174
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
176
175
  end
177
176
 
178
177
  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 })
178
+ expect { subject.enable }.to change { feature_states }.from(example_feature: :disabled, different_example_feature: :disabled).to(example_feature: :enabled, different_example_feature: :enabled)
180
179
  end
181
180
  end
182
181
 
@@ -184,37 +183,37 @@ module FlipFab
184
183
  let(:persistence_adapters) { [TestPersistence] }
185
184
 
186
185
  context 'and the persistence adapter has the same state' do
187
- let(:feature_states) {{ example_feature: :enabled }}
186
+ let(:feature_states) { { example_feature: :enabled } }
188
187
 
189
188
  it 'does not change the state of the feature' do
190
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
189
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
191
190
  end
192
191
  end
193
192
 
194
193
  context 'and the persistence adapter has the opposite state' do
195
- let(:feature_states) {{ example_feature: :disabled }}
194
+ let(:feature_states) { { example_feature: :disabled } }
196
195
 
197
196
  it 'changes the state of the feature' do
198
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
197
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
199
198
  end
200
199
 
201
200
  it 'persists the state in the adapter' do
202
- expect{ subject.enable }.to change{ feature_states }.from({ example_feature: :disabled }).to({ example_feature: :enabled })
201
+ expect { subject.enable }.to change { feature_states }.from(example_feature: :disabled).to(example_feature: :enabled)
203
202
  end
204
203
  end
205
204
 
206
205
  context 'and the persistence adapter has no state' do
207
- let(:feature_states) {{ }}
206
+ let(:feature_states) { {} }
208
207
 
209
208
  context 'and the feature is disabled' do
210
209
  let(:default) { :disabled }
211
210
 
212
211
  it 'changes the state of the feature' do
213
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
212
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
214
213
  end
215
214
 
216
215
  it 'persists the state in the adapter' do
217
- expect{ subject.enable }.to change{ feature_states }.from({ }).to({ example_feature: :enabled })
216
+ expect { subject.enable }.to change { feature_states }.from({}).to(example_feature: :enabled)
218
217
  end
219
218
  end
220
219
 
@@ -222,11 +221,11 @@ module FlipFab
222
221
  let(:default) { :enabled }
223
222
 
224
223
  it 'does not change the state of the feature' do
225
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
224
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
226
225
  end
227
226
 
228
227
  it 'persists the state in the adapter' do
229
- expect{ subject.enable }.to change{ feature_states }.from({ }).to({ example_feature: :enabled })
228
+ expect { subject.enable }.to change { feature_states }.from({}).to(example_feature: :enabled)
230
229
  end
231
230
  end
232
231
  end
@@ -238,7 +237,7 @@ module FlipFab
238
237
  let(:default) { :enabled }
239
238
 
240
239
  it 'does not change the state of the feature' do
241
- expect{subject.enable}.not_to change{subject.enabled?}.from(true)
240
+ expect { subject.enable }.not_to change { subject.enabled? }.from(true)
242
241
  end
243
242
  end
244
243
 
@@ -246,24 +245,22 @@ module FlipFab
246
245
  let(:default) { :disabled }
247
246
 
248
247
  it 'changes the state of the feature' do
249
- expect{subject.enable}.to change{subject.enabled?}.from(false).to(true)
248
+ expect { subject.enable }.to change { subject.enabled? }.from(false).to(true)
250
249
  end
251
250
  end
252
251
  end
253
252
  end
254
253
  end
255
254
 
256
-
257
255
  describe '#disable' do
258
-
259
256
  context 'when the state has been overridden' do
260
257
  let(:override) { 'enabled' }
261
258
 
262
259
  context 'and the persistence adapter has the opposite state' do
263
- let(:feature_states) {{ example_feature: :enabled }}
260
+ let(:feature_states) { { example_feature: :enabled } }
264
261
 
265
262
  it 'does not change the state of the feature' do
266
- expect{subject.disable}.not_to change{subject.disabled?}.from(false)
263
+ expect { subject.disable }.not_to change { subject.disabled? }.from(false)
267
264
  end
268
265
 
269
266
  it 'does not persist the state in the adapter' do
@@ -277,18 +274,18 @@ module FlipFab
277
274
  let(:persistence_adapters) { [TestPersistence] }
278
275
 
279
276
  context 'and the persistence adapter has the same state' do
280
- let(:feature_states) {{ example_feature: :disabled }}
277
+ let(:feature_states) { { example_feature: :disabled } }
281
278
 
282
279
  it 'does not change the state of the feature' do
283
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
280
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
284
281
  end
285
282
  end
286
283
 
287
284
  context 'and the persistence adapter has the opposite state' do
288
- let(:feature_states) {{ example_feature: :enabled }}
285
+ let(:feature_states) { { example_feature: :enabled } }
289
286
 
290
287
  it 'changes the state of the feature' do
291
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
288
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
292
289
  end
293
290
 
294
291
  it 'persists the state in the adapter' do
@@ -298,13 +295,13 @@ module FlipFab
298
295
  end
299
296
 
300
297
  context 'and the persistence adapter has no state' do
301
- let(:feature_states) {{ }}
298
+ let(:feature_states) { {} }
302
299
 
303
300
  context 'and the feature is enabled' do
304
301
  let(:default) { :enabled }
305
302
 
306
303
  it 'changes the state of the feature' do
307
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
304
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
308
305
  end
309
306
 
310
307
  it 'persists the state in the adapter' do
@@ -317,7 +314,7 @@ module FlipFab
317
314
  let(:default) { :disabled }
318
315
 
319
316
  it 'does not change the state of the feature' do
320
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
317
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
321
318
  end
322
319
 
323
320
  it 'persists the state in the adapter' do
@@ -334,7 +331,7 @@ module FlipFab
334
331
  let(:default) { :disabled }
335
332
 
336
333
  it 'does not change the state of the feature' do
337
- expect{subject.disable}.not_to change{subject.disabled?}.from(true)
334
+ expect { subject.disable }.not_to change { subject.disabled? }.from(true)
338
335
  end
339
336
  end
340
337
 
@@ -342,7 +339,7 @@ module FlipFab
342
339
  let(:default) { :enabled }
343
340
 
344
341
  it 'changes the state of the feature' do
345
- expect{subject.disable}.to change{subject.disabled?}.from(false).to(true)
342
+ expect { subject.disable }.to change { subject.disabled? }.from(false).to(true)
346
343
  end
347
344
  end
348
345
  end
@@ -10,10 +10,10 @@ Feature: Persisting the feature state in a cookie
10
10
  When I persist the feature state in a cookie
11
11
  Then the cookie has the path '/'
12
12
 
13
- Scenario Outline: The cookie should apply for all domains under the top-level domain (no domain for localhost or IP addresses, however)
13
+ Scenario Outline: The cookie populated should not contain domain
14
14
  Given the host is '<host>'
15
15
  When I persist the feature state in a cookie
16
- Then the cookie has the domain '<cookie domain>'
16
+ Then the cookie does not have domain '<cookie domain>'
17
17
 
18
18
  Examples:
19
19
  | host | cookie domain |
@@ -37,7 +37,7 @@ Feature: Persisting the feature state in a cookie
37
37
 
38
38
  Scenario: The cookie should expire after 1 year
39
39
  When I persist the feature state in a cookie
40
- Then the cookie expires at 'Fri, 22 Jan 2016 15:26:31 -0000'
40
+ Then the cookie expires at 'Fri, 22 Jan 2016 15:26:31 GMT'
41
41
 
42
42
  Scenario Outline: The cookie's value should be the state of the feature
43
43
  Given the state of the feature is '<feature state>'