abstract_feature_branch 1.2.2 → 1.3.1

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 (44) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +15 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +74 -43
  5. data/VERSION +1 -1
  6. data/abstract_feature_branch.gemspec +31 -56
  7. data/lib/abstract_feature_branch/configuration.rb +22 -7
  8. data/lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb +34 -0
  9. data/lib/abstract_feature_branch.rb +75 -7
  10. data/lib/ext/feature_branch.rb +4 -3
  11. data/lib/generators/templates/config/initializers/abstract_feature_branch.rb +7 -5
  12. metadata +76 -55
  13. data/.coveralls.yml +0 -1
  14. data/.travis.yml +0 -40
  15. data/RELEASE_NOTES.md +0 -55
  16. data/config/features/admin.local.yml +0 -15
  17. data/config/features/admin.yml +0 -17
  18. data/config/features/internal/wiki.local.yml +0 -15
  19. data/config/features/internal/wiki.yml +0 -17
  20. data/config/features/public.local.yml +0 -15
  21. data/config/features/public.yml +0 -17
  22. data/ruby187.Gemfile +0 -12
  23. data/ruby187.Gemfile.lock +0 -63
  24. data/spec/abstract_feature_branch/file_beautifier_spec.rb +0 -384
  25. data/spec/ext/feature_branch__feature_branch_per_user_spec.rb +0 -113
  26. data/spec/ext/feature_branch__feature_branch_spec.rb +0 -125
  27. data/spec/ext/feature_branch__feature_enabled_spec.rb +0 -260
  28. data/spec/fixtures/application_development_config/config/features.reference.yml +0 -21
  29. data/spec/fixtures/application_no_config/no_config +0 -1
  30. data/spec/fixtures/application_rails_config/config/features.local.yml +0 -16
  31. data/spec/fixtures/application_rails_config/config/features.yml +0 -20
  32. data/spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml +0 -31
  33. data/spec/fixtures/application_ugly_config_reference/config/database.yml +0 -17
  34. data/spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml +0 -44
  35. data/spec/fixtures/application_ugly_config_reference/config/features/admin.yml +0 -44
  36. data/spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml +0 -0
  37. data/spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml +0 -13
  38. data/spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml +0 -52
  39. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml +0 -44
  40. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml +0 -44
  41. data/spec/fixtures/application_ugly_config_reference/config/features/public.local.yml +0 -44
  42. data/spec/fixtures/application_ugly_config_reference/config/features/public.yml +0 -44
  43. data/spec/fixtures/application_ugly_config_reference/config/features.local.yml +0 -44
  44. data/spec/fixtures/application_ugly_config_reference/config/features.yml +0 -49
@@ -1,384 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe AbstractFeatureBranch::FileBeautifier do
4
- describe '#process' do
5
- before do
6
- @ugly_config_application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
7
- @ugly_config_application_reference_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config_reference'))
8
- FileUtils.rm_rf( @ugly_config_application_root)
9
- FileUtils.cp_r(@ugly_config_application_reference_root, @ugly_config_application_root)
10
- end
11
- after do
12
- FileUtils.rm_rf( @ugly_config_application_root)
13
- end
14
-
15
- context "a file is specified" do
16
- it 'gets rid of extra empty lines' do
17
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features.yml'))
18
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
19
- File.open(feature_file_path, 'r') do |file|
20
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
21
- defaults: &defaults
22
- FEATURE1: true
23
- Feature2: true
24
- feature3: false
25
- feature4: true
26
- feature4a: true
27
-
28
- development:
29
- <<: *defaults
30
- FEATURE1: true
31
- Feature2: true
32
- feature3: false
33
- feature4: true
34
- feature4a: true
35
-
36
- test:
37
- <<: *defaults
38
- FEATURE1: true
39
- Feature2: true
40
- feature3: false
41
- feature4: true
42
- feature4a: true
43
-
44
- staging:
45
- <<: *defaults
46
- FEATURE1: true
47
- Feature2: true
48
- feature3: false
49
- feature4: true
50
- feature4a: true
51
-
52
- production:
53
- <<: *defaults
54
- FEATURE1: true
55
- Feature2: true
56
- feature3: false
57
- feature4: true
58
- feature4a: true
59
-
60
- EXPECTED_FILE_CONTENT
61
- end
62
- end
63
-
64
- it 'sorts features by name under each section (e.g. environment)' do
65
- local_feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features.local.yml'))
66
- AbstractFeatureBranch::FileBeautifier.process(local_feature_file_path)
67
- File.open(local_feature_file_path, 'r') do |file|
68
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
69
- defaults: &defaults
70
- FEATURE1: true
71
- Feature2: true
72
- feature3: false
73
- feature4: true
74
- feature4a: true
75
-
76
- development:
77
- <<: *defaults
78
- FEATURE1: true
79
- Feature2: true
80
- feature3: false
81
- feature4: true
82
- feature4a: true
83
-
84
- test:
85
- <<: *defaults
86
- FEATURE1: true
87
- Feature2: true
88
- feature3: false
89
- feature4: true
90
- feature4a: true
91
-
92
- staging:
93
- <<: *defaults
94
- FEATURE1: true
95
- Feature2: true
96
- feature3: false
97
- feature4: true
98
- feature4a: true
99
-
100
- production:
101
- <<: *defaults
102
- FEATURE1: true
103
- Feature2: true
104
- feature3: false
105
- feature4: true
106
- feature4a: true
107
-
108
- EXPECTED_FILE_CONTENT
109
- end
110
- end
111
-
112
- it 'handles comments by ignoring comments on top and deleting comments in the middle' do
113
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'including_comments.local.yml'))
114
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
115
- File.open(feature_file_path, 'r') do |file|
116
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
117
- # This file allows you to override any feature configuration locally without it being committed to git
118
- # It is recommended to use this file only for temporary overrides. Once done, make final change in main .yml
119
- defaults: &defaults
120
- FEATURE1: true
121
- Feature2: true
122
- feature3: false
123
- feature4: true
124
- feature4a: true
125
-
126
- development:
127
- <<: *defaults
128
- FEATURE1: true
129
- Feature2: true
130
- feature3: false
131
- feature4: true
132
- feature4a: true
133
-
134
- test:
135
- <<: *defaults
136
- FEATURE1: true
137
- Feature2: true
138
- feature3: false
139
- feature4: true
140
- feature4a: true
141
-
142
- staging:
143
- <<: *defaults
144
- FEATURE1: true
145
- Feature2: true
146
- feature3: false
147
- feature4: true
148
- feature4a: true
149
-
150
- production:
151
- <<: *defaults
152
- FEATURE1: true
153
- Feature2: true
154
- feature3: false
155
- feature4: true
156
- feature4a: true
157
-
158
- EXPECTED_FILE_CONTENT
159
- end
160
- end
161
-
162
- it 'processes a feature empty config file' do
163
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'feature_empty_config.local.yml'))
164
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
165
- File.open(feature_file_path, 'r') do |file|
166
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
167
- defaults: &defaults
168
-
169
-
170
- development:
171
- <<: *defaults
172
-
173
- test:
174
- <<: *defaults
175
-
176
- staging:
177
- <<: *defaults
178
-
179
- production:
180
- <<: *defaults
181
-
182
- EXPECTED_FILE_CONTENT
183
- end
184
- end
185
-
186
- it 'processes an empty file without change or exceptions' do
187
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'empty.local.yml'))
188
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
189
- File.open(feature_file_path, 'r') do |file|
190
- file.readlines.join.should be_empty
191
- end
192
- end
193
-
194
- end
195
-
196
- context "a directory is specified" do
197
- it 'beautifies all YAML files under specified directory recursively' do
198
- feature_directory_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features'))
199
- AbstractFeatureBranch::FileBeautifier.process(feature_directory_path)
200
-
201
- ['public.yml', 'public.local.yml', 'admin.yml', 'admin.local.yml', 'internal/wiki.yml', 'internal/wiki.local.yml'].each do |file_path_suffix|
202
- file_path = File.join(feature_directory_path, file_path_suffix)
203
- File.open(file_path, 'r') do |file|
204
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
205
- defaults: &defaults
206
- FEATURE1: true
207
- Feature2: true
208
- feature3: false
209
- feature4: true
210
- feature4a: true
211
-
212
- development:
213
- <<: *defaults
214
- FEATURE1: true
215
- Feature2: true
216
- feature3: false
217
- feature4: true
218
- feature4a: true
219
-
220
- test:
221
- <<: *defaults
222
- FEATURE1: true
223
- Feature2: true
224
- feature3: false
225
- feature4: true
226
- feature4a: true
227
-
228
- staging:
229
- <<: *defaults
230
- FEATURE1: true
231
- Feature2: true
232
- feature3: false
233
- feature4: true
234
- feature4a: true
235
-
236
- production:
237
- <<: *defaults
238
- FEATURE1: true
239
- Feature2: true
240
- feature3: false
241
- feature4: true
242
- feature4a: true
243
-
244
- EXPECTED_FILE_CONTENT
245
- end
246
- end
247
- end
248
-
249
- context "no file or directory is specified (process all feature files)" do
250
- after do
251
- AbstractFeatureBranch.initialize_application_root
252
- AbstractFeatureBranch.load_application_features
253
- end
254
- it 'beautifies all feature files in the application' do
255
- AbstractFeatureBranch.application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
256
- AbstractFeatureBranch.load_application_features
257
- AbstractFeatureBranch::FileBeautifier.process
258
-
259
- [
260
- 'features.yml',
261
- 'features.local.yml',
262
- 'features/public.yml',
263
- 'features/public.local.yml',
264
- 'features/admin.yml',
265
- 'features/admin.local.yml',
266
- 'features/internal/wiki.yml',
267
- 'features/internal/wiki.local.yml'
268
- ].each do |file_path_suffix|
269
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', file_path_suffix)
270
- File.open(file_path, 'r') do |file|
271
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
272
- defaults: &defaults
273
- FEATURE1: true
274
- Feature2: true
275
- feature3: false
276
- feature4: true
277
- feature4a: true
278
-
279
- development:
280
- <<: *defaults
281
- FEATURE1: true
282
- Feature2: true
283
- feature3: false
284
- feature4: true
285
- feature4a: true
286
-
287
- test:
288
- <<: *defaults
289
- FEATURE1: true
290
- Feature2: true
291
- feature3: false
292
- feature4: true
293
- feature4a: true
294
-
295
- staging:
296
- <<: *defaults
297
- FEATURE1: true
298
- Feature2: true
299
- feature3: false
300
- feature4: true
301
- feature4a: true
302
-
303
- production:
304
- <<: *defaults
305
- FEATURE1: true
306
- Feature2: true
307
- feature3: false
308
- feature4: true
309
- feature4a: true
310
-
311
- EXPECTED_FILE_CONTENT
312
- end
313
- end
314
- end
315
-
316
- it 'does not beautify non-feature files in the application' do
317
- AbstractFeatureBranch.application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
318
- AbstractFeatureBranch.load_application_features
319
- AbstractFeatureBranch::FileBeautifier.process
320
-
321
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', 'another_application_configuration.yml')
322
- File.open(file_path, 'r') do |file|
323
- file.readlines.join.should == <<-ANOTHER_APPLICATION_CONFIGURATION_CONTENT
324
- common: &default_settings
325
- license_key: <%= ENV["LICENSE_KEY"] %>
326
- app_name: <%= ENV["APP_NAME"] %>
327
- monitor_mode: true
328
- developer_mode: false
329
- log_level: info
330
-
331
- browser_monitoring:
332
- auto_instrument: true
333
-
334
- audit_log:
335
- enabled: false
336
-
337
-
338
- development:
339
- <<: *default_settings
340
- monitor_mode: false
341
- developer_mode: true
342
-
343
- test:
344
- <<: *default_settings
345
- monitor_mode: false
346
-
347
- production:
348
- <<: *default_settings
349
- monitor_mode: true
350
-
351
- staging:
352
- <<: *default_settings
353
- monitor_mode: true
354
- app_name: <%= ENV["APP_NAME"] %> (Staging)
355
- ANOTHER_APPLICATION_CONFIGURATION_CONTENT
356
- end
357
-
358
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', 'database.yml')
359
- File.open(file_path, 'r') do |file|
360
- file.readlines.join.should == <<-DATABASE_CONFIGURATION_CONTENT
361
- development:
362
- adapter: sqlite3
363
- database: db/development.sqlite3
364
- pool: 5
365
- timeout: 5000
366
-
367
- test:
368
- adapter: sqlite3
369
- database: db/test.sqlite3
370
- pool: 5
371
- timeout: 5000
372
-
373
- production:
374
- adapter: sqlite3
375
- database: db/production.sqlite3
376
- pool: 5
377
- timeout: 5000
378
- DATABASE_CONFIGURATION_CONTENT
379
- end
380
- end
381
- end
382
- end
383
- end
384
- end
@@ -1,113 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'feature_branch object extensions' do
4
- before do
5
- @app_env_backup = AbstractFeatureBranch.application_environment
6
- @app_root_backup = AbstractFeatureBranch.application_root
7
- AbstractFeatureBranch.logger.warn 'Environment variable ABSTRACT_FEATURE_BRANCH_FEATURE1 already set, potentially conflicting with another test' if ENV.keys.include?('ABSTRACT_FEATURE_BRANCH_FEATURE1')
8
- AbstractFeatureBranch.logger.warn 'Environment variable Abstract_Feature_Branch_Feature2 already set, potentially conflicting with another test' if ENV.keys.include?('Abstract_Feature_Branch_Feature2')
9
- AbstractFeatureBranch.logger.warn 'Environment variable abstract_feature_branch_feature3 already set, potentially conflicting with another test' if ENV.keys.include?('abstract_feature_branch_feature3')
10
- begin
11
- AbstractFeatureBranch.user_features_storage.flushall
12
- rescue => e
13
- #noop
14
- end
15
- end
16
- after do
17
- ENV.delete('ABSTRACT_FEATURE_BRANCH_FEATURE1')
18
- ENV.delete('Abstract_Feature_Branch_Feature2')
19
- ENV.delete('abstract_feature_branch_feature3')
20
- AbstractFeatureBranch.application_root = @app_root_backup
21
- AbstractFeatureBranch.application_environment = @app_env_backup
22
- AbstractFeatureBranch.unload_application_features
23
- begin
24
- AbstractFeatureBranch.user_features_storage.flushall
25
- rescue => e
26
- #noop
27
- end
28
- end
29
- describe '#feature_branch' do
30
- context 'per user' do
31
- it 'feature branches correctly after storing feature configuration per user in a separate process (ensuring persistence)' do
32
- user_id = 'email1@example.com'
33
- Process.fork do
34
- AbstractFeatureBranch.initialize_user_features_storage
35
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature1 => false, :feature3 => true, :feature6 => true, :feature7 => false)
36
- end
37
- Process.wait
38
- features_enabled = []
39
- feature_branch :feature1, user_id do
40
- features_enabled << :feature1
41
- end
42
- feature_branch :feature3, user_id do
43
- features_enabled << :feature3
44
- end
45
- feature_branch :feature6, user_id do
46
- features_enabled << :feature6
47
- end
48
- feature_branch :feature6, 'otheruser@example.com' do
49
- features_enabled << :feature6_otheruser
50
- end
51
- feature_branch :feature6 do
52
- features_enabled << :feature6_nouserspecified
53
- end
54
- feature_branch :feature7, user_id do
55
- features_enabled << :feature7
56
- end
57
- features_enabled.should include(:feature1) #remains like features.yml
58
- features_enabled.should_not include(:feature3) #remains like features.yml
59
- features_enabled.should include(:feature6) #per user honored as true
60
- features_enabled.should_not include(:feature6_otheruser) #per user honored as false
61
- features_enabled.should_not include(:feature6_nouserspecified) #per user requires user id or it returns false
62
- features_enabled.should_not include(:feature7) #per user honored as false
63
- end
64
- it 'update feature branching (disabling some features) after having stored feature configuration per user in a separate process (ensuring persistence)' do
65
- user_id = 'email1@example.com'
66
- Process.fork do
67
- AbstractFeatureBranch.initialize_user_features_storage
68
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature6 => true, :feature7 => false)
69
- AbstractFeatureBranch.toggle_features_for_user(user_id, :feature6 => false, :feature7 => true)
70
- end
71
- Process.wait
72
- features_enabled = []
73
- feature_branch :feature6, user_id do
74
- features_enabled << :feature6
75
- end
76
- feature_branch :feature7, user_id do
77
- features_enabled << :feature7
78
- end
79
- features_enabled.should_not include(:feature6)
80
- features_enabled.should include(:feature7)
81
- end
82
-
83
- end
84
- end
85
- describe 'self#feature_branch' do
86
- after do
87
- Object.send(:remove_const, :TestObject)
88
- end
89
- # No need to retest all instance test cases, just a spot check due to implementation reuse
90
- it 'feature branches instance level behavior (case-insensitive feature names)' do
91
- class TestObject
92
- def self.features_enabled
93
- @features_enabled ||= []
94
- end
95
- def self.hit_me
96
- feature_branch :feature1 do
97
- self.features_enabled << :feature1
98
- end
99
- feature_branch :feature2 do
100
- self.features_enabled << :feature2
101
- end
102
- feature_branch :feature3 do
103
- self.features_enabled << :feature3
104
- end
105
- end
106
- end
107
- TestObject.hit_me
108
- TestObject.features_enabled.should include(:feature1)
109
- TestObject.features_enabled.should include(:feature2)
110
- TestObject.features_enabled.should_not include(:feature3)
111
- end
112
- end
113
- end
@@ -1,125 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'feature_branch object extensions' do
4
- before do
5
- @app_env_backup = AbstractFeatureBranch.application_environment
6
- @app_root_backup = AbstractFeatureBranch.application_root
7
- AbstractFeatureBranch.logger.warn 'Environment variable ABSTRACT_FEATURE_BRANCH_FEATURE1 already set, potentially conflicting with another test' if ENV.keys.include?('ABSTRACT_FEATURE_BRANCH_FEATURE1')
8
- AbstractFeatureBranch.logger.warn 'Environment variable Abstract_Feature_Branch_Feature2 already set, potentially conflicting with another test' if ENV.keys.include?('Abstract_Feature_Branch_Feature2')
9
- AbstractFeatureBranch.logger.warn 'Environment variable abstract_feature_branch_feature3 already set, potentially conflicting with another test' if ENV.keys.include?('abstract_feature_branch_feature3')
10
- end
11
- after do
12
- ENV.delete('ABSTRACT_FEATURE_BRANCH_FEATURE1')
13
- ENV.delete('Abstract_Feature_Branch_Feature2')
14
- ENV.delete('abstract_feature_branch_feature3')
15
- AbstractFeatureBranch.application_root = @app_root_backup
16
- AbstractFeatureBranch.application_environment = @app_env_backup
17
- AbstractFeatureBranch.unload_application_features
18
- end
19
- describe '#feature_branch' do
20
- context 'class level behavior (case-insensitive string or symbol feature names)' do
21
- {
22
- 'Feature1' => true,
23
- :FEATURE2 => true,
24
- :feature3 => false,
25
- :admin_feature1 => true,
26
- :admin_feature2 => false,
27
- :public_feature1 => true,
28
- :public_feature2 => false,
29
- :wiki_feature1 => true,
30
- :wiki_feature2 => false,
31
- }.each do |feature_name, expected_branch_run|
32
- it "feature branches correctly for feature #{feature_name} with expected branch run #{expected_branch_run}" do
33
- feature_branch_run = false
34
- feature_branch feature_name do
35
- feature_branch_run = true
36
- end
37
- feature_branch_run.should == expected_branch_run
38
- end
39
- end
40
- end
41
- it 'returns nil and does not execute block for an invalid feature name' do
42
- return_value = feature_branch :invalid_feature_that_does_not_exist do
43
- fail 'feature branch block must not execute, but did.'
44
- end
45
- return_value.should be_nil
46
- end
47
- it 'allows environment variables (case-insensitive booleans) to override configuration file' do
48
- ENV['ABSTRACT_FEATURE_BRANCH_FEATURE1'] = 'FALSE'
49
- ENV['Abstract_Feature_Branch_Feature2'] = 'False'
50
- ENV['abstract_feature_branch_feature3'] = 'true'
51
- AbstractFeatureBranch.load_application_features
52
- features_enabled = []
53
- feature_branch :feature1 do
54
- features_enabled << :feature1
55
- end
56
- feature_branch :feature2 do
57
- features_enabled << :feature2
58
- end
59
- feature_branch :feature3 do
60
- features_enabled << :feature3
61
- end
62
- features_enabled.should_not include(:feature1)
63
- features_enabled.should_not include(:feature2)
64
- features_enabled.should include(:feature3)
65
- end
66
- it 'allows local configuration file to override main configuration file' do
67
- features_enabled = []
68
- feature_branch :feature4 do
69
- features_enabled << :feature4
70
- end
71
- feature_branch :feature5 do
72
- features_enabled << :feature5
73
- end
74
- feature_branch :admin_feature3 do
75
- features_enabled << :admin_feature3
76
- end
77
- feature_branch :public_feature3 do
78
- features_enabled << :public_feature3
79
- end
80
- feature_branch :wiki_feature3 do
81
- features_enabled << :wiki_feature3
82
- end
83
- features_enabled.should_not include(:feature4)
84
- features_enabled.should include(:feature5)
85
- features_enabled.should include(:admin_feature3)
86
- features_enabled.should include(:public_feature3)
87
- features_enabled.should include(:wiki_feature3)
88
- end
89
- it 'works with an application that has no configuration files' do
90
- AbstractFeatureBranch.application_root = File.join(__FILE__, '..', '..', 'fixtures', 'application_no_config')
91
- AbstractFeatureBranch.load_application_features
92
- feature_branch :feature1 do
93
- fail 'feature branch block must not execute, but did.'
94
- end
95
- end
96
- end
97
- describe 'self#feature_branch' do
98
- after do
99
- Object.send(:remove_const, :TestObject)
100
- end
101
- # No need to retest all instance test cases, just a spot check due to implementation reuse
102
- it 'feature branches instance level behavior (case-insensitive feature names)' do
103
- class TestObject
104
- def self.features_enabled
105
- @features_enabled ||= []
106
- end
107
- def self.hit_me
108
- feature_branch :feature1 do
109
- self.features_enabled << :feature1
110
- end
111
- feature_branch :feature2 do
112
- self.features_enabled << :feature2
113
- end
114
- feature_branch :feature3 do
115
- self.features_enabled << :feature3
116
- end
117
- end
118
- end
119
- TestObject.hit_me
120
- TestObject.features_enabled.should include(:feature1)
121
- TestObject.features_enabled.should include(:feature2)
122
- TestObject.features_enabled.should_not include(:feature3)
123
- end
124
- end
125
- end