flip_fab 1.0.0 → 1.0.16

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