flip_the_switch 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Example/.gitignore +2 -1
- data/Example/Colors-iOS/ViewControlleriOS.m +27 -0
- data/Example/Colors.xcodeproj/project.pbxproj +4 -0
- data/Example/Rakefile +1 -0
- data/Example/features.yml +3 -2
- data/FlipTheSwitch.podspec +1 -1
- data/README.md +13 -3
- data/bin/flip-the-switch +6 -1
- data/flip_the_switch.gemspec +1 -1
- data/lib/flip_the_switch/cli.rb +28 -11
- data/lib/flip_the_switch/errors.rb +9 -0
- data/lib/flip_the_switch/generator/category.rb +1 -0
- data/lib/flip_the_switch/generator/plist.rb +1 -0
- data/lib/flip_the_switch/generator/settings.rb +121 -0
- data/lib/flip_the_switch/generator.rb +1 -1
- data/lib/flip_the_switch/reader/defaults.rb +43 -0
- data/lib/flip_the_switch/reader/features.rb +53 -0
- data/lib/flip_the_switch/reader.rb +2 -1
- data/spec/flip_the_switch/cli_spec.rb +12 -5
- data/spec/flip_the_switch/generator/category_spec.rb +1 -1
- data/spec/flip_the_switch/generator/plist_spec.rb +1 -1
- data/spec/flip_the_switch/generator/settings_spec.rb +80 -0
- data/spec/flip_the_switch/reader/defaults_spec.rb +96 -0
- data/spec/flip_the_switch/reader/{yaml_spec.rb → features_spec.rb} +17 -4
- data/spec/resources/ExistingSettingsRoot.plist +33 -0
- data/spec/resources/ExpectedSettingsBaseRoot.plist +23 -0
- data/spec/resources/ExpectedSettingsFeatures.plist +29 -0
- data/spec/resources/ExpectedSettingsMergeExistingRoot.plist +47 -0
- data/spec/resources/real/features.yml +6 -2
- metadata +20 -6
- data/lib/flip_the_switch/reader/yaml.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e9b8507bbc66a9479d3fe174c8a42fba3495200
|
4
|
+
data.tar.gz: 01f913063a72ab9a2bd670fe7600f0d4b16fc830
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8077a424aec23a34f08139b7213c8f17d8c650d980a3cea097c1d137609f08d5af256823eacf89b9fd67af9b5fd3255a6d7cf70e9a4a6d0a8e62a34bd7256144
|
7
|
+
data.tar.gz: a5a65e6aa1a43e8e22a4424a76efd73a90c99106c851ff5cfb2880ee4ea71529d7a159c352b57ebcfa02e34456c439661015f0fa86ebe9599f51dd5190489ce1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 0.4.0 / 2014-07-16
|
2
|
+
|
3
|
+
* [FEATURE] #17 Use environments for feature states
|
4
|
+
* [FEATURE] #16 Allow reading of CLI defaults from yml file
|
5
|
+
* [FEATURE] #14 Auto-create Settings.bundle from feature defaults
|
6
|
+
|
1
7
|
# 0.3.0 / 2014-07-02
|
2
8
|
|
3
9
|
* [FEATURE] #15 Auto-create category for features
|
data/Example/.gitignore
CHANGED
@@ -12,12 +12,39 @@
|
|
12
12
|
|
13
13
|
@implementation ViewControlleriOS
|
14
14
|
|
15
|
+
#pragma mark - Lifecycle
|
16
|
+
|
17
|
+
- (void)dealloc
|
18
|
+
{
|
19
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
20
|
+
}
|
21
|
+
|
15
22
|
#pragma mark - UIViewController Lifecycle
|
16
23
|
|
17
24
|
- (void)viewDidLoad
|
18
25
|
{
|
19
26
|
[super viewDidLoad];
|
20
27
|
[self setupView];
|
28
|
+
[self setupStateChangeNotifications];
|
29
|
+
}
|
30
|
+
|
31
|
+
- (void)setupStateChangeNotifications
|
32
|
+
{
|
33
|
+
[self setupNotification:UIApplicationWillEnterForegroundNotification];
|
34
|
+
[self setupNotification:UIApplicationDidBecomeActiveNotification];
|
35
|
+
}
|
36
|
+
|
37
|
+
- (void)setupNotification:(NSString *)notification
|
38
|
+
{
|
39
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
40
|
+
selector:@selector(applicationStateChanged:)
|
41
|
+
name:notification
|
42
|
+
object:nil];
|
43
|
+
}
|
44
|
+
|
45
|
+
- (void)applicationStateChanged:(UIApplication *)application
|
46
|
+
{
|
47
|
+
[self setupView];
|
21
48
|
}
|
22
49
|
|
23
50
|
#pragma mark - Actions
|
@@ -8,6 +8,7 @@
|
|
8
8
|
|
9
9
|
/* Begin PBXBuildFile section */
|
10
10
|
35D6E35AEAC9473FAAAB5BE5 /* libPods-Colors-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F7C4D132FE24A06ACC52E5F /* libPods-Colors-iOS.a */; };
|
11
|
+
5B13CA4919721395001D008A /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B13CA4819721395001D008A /* Settings.bundle */; };
|
11
12
|
5B20701A194237BF00D07667 /* Features.plist in Resources */ = {isa = PBXBuildFile; fileRef = F80321679CBE499FFA387688 /* Features.plist */; };
|
12
13
|
5B909898193A235E004C12B3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B909897193A235E004C12B3 /* Foundation.framework */; };
|
13
14
|
5B90989C193A235E004C12B3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B90989B193A235E004C12B3 /* UIKit.framework */; };
|
@@ -20,6 +21,7 @@
|
|
20
21
|
/* End PBXBuildFile section */
|
21
22
|
|
22
23
|
/* Begin PBXFileReference section */
|
24
|
+
5B13CA4819721395001D008A /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
23
25
|
5B909894193A235E004C12B3 /* Colors-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Colors-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
24
26
|
5B909897193A235E004C12B3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
25
27
|
5B90989B193A235E004C12B3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
@@ -93,6 +95,7 @@
|
|
93
95
|
F803243E8A66F29C3EA37B65 /* AppDelegateiOS.m */,
|
94
96
|
F8032EBDB675B3B788B1297F /* FlipTheSwitch+Features.h */,
|
95
97
|
F803287440254AB051D00DDB /* FlipTheSwitch+Features.m */,
|
98
|
+
5B13CA4819721395001D008A /* Settings.bundle */,
|
96
99
|
);
|
97
100
|
path = "Colors-iOS";
|
98
101
|
sourceTree = "<group>";
|
@@ -162,6 +165,7 @@
|
|
162
165
|
isa = PBXResourcesBuildPhase;
|
163
166
|
buildActionMask = 2147483647;
|
164
167
|
files = (
|
168
|
+
5B13CA4919721395001D008A /* Settings.bundle in Resources */,
|
165
169
|
5B20701A194237BF00D07667 /* Features.plist in Resources */,
|
166
170
|
5B9098B3193A235E004C12B3 /* Images.xcassets in Resources */,
|
167
171
|
5B9098AB193A235E004C12B3 /* Main_iPhone.storyboard in Resources */,
|
data/Example/Rakefile
CHANGED
@@ -19,5 +19,6 @@ end
|
|
19
19
|
task :test => podfile_lock do
|
20
20
|
sh 'bundle exec ../bin/flip-the-switch plist -o Colors-iOS'
|
21
21
|
sh 'bundle exec ../bin/flip-the-switch category -o Colors-iOS'
|
22
|
+
sh 'bundle exec ../bin/flip-the-switch settings -o Colors-iOS'
|
22
23
|
sh "xctool build -scheme #{workspace}-iOS -workspace #{workspace}.xcworkspace -sdk iphonesimulator OBJROOT=#{build} SHARED_PRECOMPS_DIR=#{build}"
|
23
24
|
end
|
data/Example/features.yml
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
default:
|
2
|
+
purple_color: Yes
|
3
|
+
red_color: No
|
data/FlipTheSwitch.podspec
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
A feature switching/toggling/flipping library for ObjectiveC.
|
4
4
|
|
5
|
-
# flip_the_switch [](https://travis-ci.org/michaelengland/FlipTheSwitch) [](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [](https://travis-ci.org/michaelengland/FlipTheSwitch) [](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [](http://badge.fury.io/rb/flip_the_switch)
|
6
6
|
|
7
7
|
A gem command line tool for generating the `Features.plist` & `FlipTheSwitch+Features.{h,m}` categories to help with the corresponding Pod.
|
8
8
|
|
@@ -63,6 +63,7 @@ If you install the gem, you will be able to use the Command-Line-Interface.
|
|
63
63
|
The CLI consists of 2 commands:
|
64
64
|
|
65
65
|
- `plist` - creates a `Features.plist` file for enabled/disabled features like that mentioned above.
|
66
|
+
- `settings` - creates a `Settings.bundle` used by the OS settings. These can then be used to enable/disable the features at runtime.
|
66
67
|
- `category` - creates `FlipTheSwitch+Features.{h,m}` files for features, thus giving compile-time checks for adding/removal of new features.
|
67
68
|
e.g:
|
68
69
|
|
@@ -83,7 +84,16 @@ e.g:
|
|
83
84
|
The features, along with their default enabled/disabled state, are read from a `features.yml` file. e.g.:
|
84
85
|
|
85
86
|
```yaml
|
86
|
-
|
87
|
+
default:
|
88
|
+
awesome_feature: Yes
|
89
|
+
```
|
90
|
+
|
91
|
+
In order to avoid typing in the same options all the time, you can create a `.flip.yml` file for the default options, e.g.:
|
92
|
+
|
93
|
+
```yaml
|
94
|
+
input: features
|
95
|
+
environment: development
|
96
|
+
category_output: Classes/Extensions
|
87
97
|
```
|
88
98
|
|
89
99
|
For more information, run `flip-the-switch help`
|
@@ -92,7 +102,7 @@ For more information, run `flip-the-switch help`
|
|
92
102
|
|
93
103
|
Add `pod 'FlipTheSwitch'` to your Podfile
|
94
104
|
|
95
|
-
Add `gem '
|
105
|
+
Add `gem 'flip_the_switch'` to your Gemfile
|
96
106
|
|
97
107
|
## Authors
|
98
108
|
|
data/bin/flip-the-switch
CHANGED
data/flip_the_switch.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.email = %w(mg.england@gmail.com rob@robsiwek.com)
|
5
5
|
s.summary = 'A simple library to help enabling/disabling features on iOS/Mac applications.'
|
6
6
|
s.homepage = 'https://github.com/michaelengland/FlipTheSwitch'
|
7
|
-
s.version = '0.
|
7
|
+
s.version = '0.4.0'
|
8
8
|
s.license = 'MIT'
|
9
9
|
|
10
10
|
s.add_dependency 'activesupport', '~> 3.2'
|
data/lib/flip_the_switch/cli.rb
CHANGED
@@ -3,22 +3,35 @@ require 'flip_the_switch'
|
|
3
3
|
|
4
4
|
module FlipTheSwitch
|
5
5
|
class Cli < Thor
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
private
|
7
|
+
def self.defaults
|
8
|
+
@defaults ||= Reader::Defaults.new.defaults
|
9
|
+
end
|
10
|
+
|
11
|
+
public
|
12
|
+
class_option :input, type: :string, aliases: '-i', default: defaults[:input], desc: 'Location of the directory containing features.yml file to read'
|
13
|
+
class_option :environment, type: :string, aliases: '-n', default: defaults[:environment], desc: 'Name of environment to read from in features.yml file'
|
14
|
+
class_option :enabled, type: :string, aliases: '-e', default: defaults[:enabled], desc: 'Extra features to be set as enabled'
|
15
|
+
class_option :disabled, type: :string, aliases: '-d', default: defaults[:disabled], desc: 'Extra features to be set as disabled'
|
9
16
|
|
10
17
|
desc 'plist', 'Auto-generates a Features.plist file for enabled/disabled features'
|
11
|
-
method_option :output, type: :string, aliases: '-o', default:
|
18
|
+
method_option :output, type: :string, aliases: '-o', default: defaults[:plist_output], desc: 'Location of the directory in which Features.plist file will be created'
|
12
19
|
def plist
|
13
20
|
plist_generator.generate
|
14
21
|
end
|
15
22
|
|
16
23
|
desc 'category', 'Auto-generates .h & .m files for enabled/disabled features'
|
17
|
-
method_option :output, type: :string, aliases: '-o', default:
|
24
|
+
method_option :output, type: :string, aliases: '-o', default: defaults[:category_output], desc: 'Location of the directory in which FlipTheSwitch+Features.{h,m} files will be created'
|
18
25
|
def category
|
19
26
|
category_generator.generate
|
20
27
|
end
|
21
28
|
|
29
|
+
desc 'settings', 'Auto-generates settings.bundle files for enabling/disabling features from iOS settings menu'
|
30
|
+
method_option :output, type: :string, aliases: '-o', default: defaults[:settings_output], desc: 'Location of the directory in which FlipTheSwitch+Features.{h,m} files will be created'
|
31
|
+
def settings
|
32
|
+
settings_generator.generate
|
33
|
+
end
|
34
|
+
|
22
35
|
private
|
23
36
|
|
24
37
|
def plist_generator
|
@@ -29,26 +42,30 @@ module FlipTheSwitch
|
|
29
42
|
Generator::Category.new(output, feature_states)
|
30
43
|
end
|
31
44
|
|
45
|
+
def settings_generator
|
46
|
+
Generator::Settings.new(output, feature_states)
|
47
|
+
end
|
48
|
+
|
32
49
|
def output
|
33
|
-
options
|
50
|
+
options['output']
|
34
51
|
end
|
35
52
|
|
36
53
|
def feature_states
|
37
|
-
|
54
|
+
feature_reader.feature_states.
|
38
55
|
merge(enabled_states).
|
39
56
|
merge(disabled_states)
|
40
57
|
end
|
41
58
|
|
42
|
-
def
|
43
|
-
Reader::
|
59
|
+
def feature_reader
|
60
|
+
Reader::Features.new(options['input'], options['environment'])
|
44
61
|
end
|
45
62
|
|
46
63
|
def enabled_states
|
47
|
-
states_for(options.
|
64
|
+
states_for(options['enabled'].split(','), true)
|
48
65
|
end
|
49
66
|
|
50
67
|
def disabled_states
|
51
|
-
states_for(options.
|
68
|
+
states_for(options['disabled'].split(','), false)
|
52
69
|
end
|
53
70
|
|
54
71
|
def states_for(array, default)
|
@@ -7,6 +7,15 @@ module FlipTheSwitch
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class InvalidFile < Base
|
10
|
+
def initialize(file)
|
11
|
+
super("Invalid file - #{file}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class InvalidEnvironment < Base
|
16
|
+
def initialize(environment)
|
17
|
+
super("Invalid environment - #{environment}")
|
18
|
+
end
|
10
19
|
end
|
11
20
|
end
|
12
21
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'flip_the_switch/generator/base'
|
2
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
3
|
+
require 'plist'
|
4
|
+
|
5
|
+
module FlipTheSwitch
|
6
|
+
module Generator
|
7
|
+
class Settings < Base
|
8
|
+
def generate
|
9
|
+
create_settings_bundle_if_not_exists
|
10
|
+
read_settings
|
11
|
+
delete_existing_settings_if_exist
|
12
|
+
write_settings
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def create_settings_bundle_if_not_exists
|
18
|
+
unless Dir.exists?(settings_bundle)
|
19
|
+
Dir.mkdir(settings_bundle)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_settings
|
24
|
+
current_plist
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_existing_settings_if_exist
|
28
|
+
delete_root_plist_if_exists
|
29
|
+
delete_features_plist_if_exists
|
30
|
+
end
|
31
|
+
|
32
|
+
def write_settings
|
33
|
+
write_root_plist
|
34
|
+
write_features_plist
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete_root_plist_if_exists
|
38
|
+
delete_file(root_plist)
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_features_plist_if_exists
|
42
|
+
delete_file(features_plist)
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_root_plist
|
46
|
+
::Plist::Emit.save_plist(root, root_plist)
|
47
|
+
end
|
48
|
+
|
49
|
+
def write_features_plist
|
50
|
+
::Plist::Emit.save_plist(features, features_plist)
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete_file(file)
|
54
|
+
File.delete(file) if File.exists?(file)
|
55
|
+
end
|
56
|
+
|
57
|
+
def root
|
58
|
+
current_plist.with_indifferent_access.merge(PreferenceSpecifiers: root_preferences)
|
59
|
+
end
|
60
|
+
|
61
|
+
def root_preferences
|
62
|
+
existing_root_preferences.delete_if { |root_preference|
|
63
|
+
root_preference[:Title] == 'Features'
|
64
|
+
} + feature_root_preferences
|
65
|
+
end
|
66
|
+
|
67
|
+
def existing_root_preferences
|
68
|
+
current_plist.with_indifferent_access[:PreferenceSpecifiers] || []
|
69
|
+
end
|
70
|
+
|
71
|
+
def feature_root_preferences
|
72
|
+
[
|
73
|
+
{
|
74
|
+
Title: 'Features',
|
75
|
+
Type: 'PSGroupSpecifier'
|
76
|
+
},
|
77
|
+
{
|
78
|
+
File: 'Features',
|
79
|
+
Title: 'Features',
|
80
|
+
Type: 'PSChildPaneSpecifier'
|
81
|
+
}
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
85
|
+
def features
|
86
|
+
{PreferenceSpecifiers: feature_toggles}
|
87
|
+
end
|
88
|
+
|
89
|
+
def feature_toggles
|
90
|
+
feature_states.map { |feature, state|
|
91
|
+
{
|
92
|
+
Type: 'PSToggleSwitchSpecifier',
|
93
|
+
Title: feature,
|
94
|
+
Key: "FTS_FEATURE_#{feature}",
|
95
|
+
DefaultValue: state
|
96
|
+
}
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def current_plist
|
101
|
+
@current_plist ||= if File.exists?(root_plist)
|
102
|
+
::Plist::parse_xml(root_plist)
|
103
|
+
else
|
104
|
+
{}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def root_plist
|
109
|
+
File.join(settings_bundle, 'Root.plist')
|
110
|
+
end
|
111
|
+
|
112
|
+
def features_plist
|
113
|
+
File.join(settings_bundle, 'Features.plist')
|
114
|
+
end
|
115
|
+
|
116
|
+
def settings_bundle
|
117
|
+
File.join(output, 'Settings.bundle')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
|
3
|
+
module FlipTheSwitch
|
4
|
+
module Reader
|
5
|
+
class Defaults
|
6
|
+
def defaults
|
7
|
+
if valid_file?
|
8
|
+
base_defaults.merge(file_defaults)
|
9
|
+
else
|
10
|
+
raise Error::InvalidFile.new(defaults_file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def valid_file?
|
17
|
+
file_defaults.is_a?(Hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_defaults
|
21
|
+
{
|
22
|
+
input: Dir.pwd,
|
23
|
+
environment: 'default',
|
24
|
+
enabled: '',
|
25
|
+
disabled: '',
|
26
|
+
category_output: Dir.pwd,
|
27
|
+
plist_output: Dir.pwd,
|
28
|
+
settings_output: Dir.pwd
|
29
|
+
}.with_indifferent_access
|
30
|
+
end
|
31
|
+
|
32
|
+
def file_defaults
|
33
|
+
@file_defaults ||= YAML.load_file(defaults_file)
|
34
|
+
rescue SystemCallError
|
35
|
+
{}
|
36
|
+
end
|
37
|
+
|
38
|
+
def defaults_file
|
39
|
+
'.flip.yml'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module FlipTheSwitch
|
4
|
+
module Reader
|
5
|
+
class Features
|
6
|
+
def initialize(input, environment)
|
7
|
+
@input = input
|
8
|
+
@environment = environment
|
9
|
+
end
|
10
|
+
|
11
|
+
def feature_states
|
12
|
+
if valid_file?
|
13
|
+
environment_states
|
14
|
+
else
|
15
|
+
raise Error::InvalidFile.new(input_file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
attr_reader :input, :environment
|
21
|
+
|
22
|
+
def valid_file?
|
23
|
+
file_states.is_a?(Hash) && file_states.all? { |environment, feature|
|
24
|
+
environment.is_a?(String) && valid_feature_hash?(feature)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid_feature_hash?(feature_hash)
|
29
|
+
feature_hash.is_a?(Hash) && feature_hash.all? { |feature, state|
|
30
|
+
feature.is_a?(String) && !!state == state
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def environment_states
|
35
|
+
if file_states.has_key?(environment)
|
36
|
+
file_states[environment]
|
37
|
+
else
|
38
|
+
raise Error::InvalidEnvironment.new(environment)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def file_states
|
43
|
+
@file_states ||= YAML.load_file(input_file)
|
44
|
+
rescue SystemCallError => e
|
45
|
+
raise Error::UnreadableFile.new(e)
|
46
|
+
end
|
47
|
+
|
48
|
+
def input_file
|
49
|
+
File.join(input, 'features.yml')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1 +1,2 @@
|
|
1
|
-
require 'flip_the_switch/reader/
|
1
|
+
require 'flip_the_switch/reader/features'
|
2
|
+
require 'flip_the_switch/reader/defaults'
|
@@ -16,14 +16,14 @@ describe FlipTheSwitch::Cli do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
shared_examples_for 'generator' do
|
19
|
-
let(:
|
19
|
+
let(:feature_reader) { double(FlipTheSwitch::Reader::Features, feature_states: {'something' => true}) }
|
20
20
|
let(:generator) { double(generator_class) }
|
21
21
|
|
22
22
|
context 'when no options given' do
|
23
23
|
let(:options) { [] }
|
24
24
|
|
25
25
|
before do
|
26
|
-
FlipTheSwitch::Reader::
|
26
|
+
FlipTheSwitch::Reader::Features.stub(:new).with(Dir.pwd, 'default').and_return(feature_reader)
|
27
27
|
generator_class.stub(:new).with(Dir.pwd, 'something' => true).and_return(generator)
|
28
28
|
end
|
29
29
|
|
@@ -35,7 +35,7 @@ describe FlipTheSwitch::Cli do
|
|
35
35
|
|
36
36
|
context 'when options given' do
|
37
37
|
before do
|
38
|
-
FlipTheSwitch::Reader::
|
38
|
+
FlipTheSwitch::Reader::Features.stub(:new).with('input', 'environment').and_return(feature_reader)
|
39
39
|
generator_class.stub(:new).with('output', {
|
40
40
|
'something' => true,
|
41
41
|
'en' => true,
|
@@ -46,7 +46,7 @@ describe FlipTheSwitch::Cli do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
context 'using full name' do
|
49
|
-
let(:options) { %w(--input=input --output=output --enabled=en
|
49
|
+
let(:options) { %w(--input=input --environment=environment --output=output --enabled=en,abled --disabled=dis,appointing) }
|
50
50
|
|
51
51
|
it 'generates using the options given' do
|
52
52
|
expect(generator).to receive(:generate)
|
@@ -55,7 +55,7 @@ describe FlipTheSwitch::Cli do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
context 'using aliases' do
|
58
|
-
let(:options) { %w(-i=input -o=output -e=en
|
58
|
+
let(:options) { %w(-i=input -n=environment -o=output -e=en,abled -d=dis,appointing) }
|
59
59
|
|
60
60
|
it 'generates using the options given' do
|
61
61
|
expect(generator).to receive(:generate)
|
@@ -78,4 +78,11 @@ describe FlipTheSwitch::Cli do
|
|
78
78
|
|
79
79
|
it_behaves_like 'generator'
|
80
80
|
end
|
81
|
+
|
82
|
+
context 'when settings command called' do
|
83
|
+
let(:command) { 'settings' }
|
84
|
+
let(:generator_class) { FlipTheSwitch::Generator::Settings }
|
85
|
+
|
86
|
+
it_behaves_like 'generator'
|
87
|
+
end
|
81
88
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe FlipTheSwitch::Generator::Category do
|
4
|
-
subject(:category) {
|
4
|
+
subject(:category) { described_class.new(output, feature_states) }
|
5
5
|
let(:output) { 'spec/resources' }
|
6
6
|
let(:feature_states) { {'first_feature' => true, 'second_feature' => false} }
|
7
7
|
let(:expected_header_file) { File.read('spec/resources/expected_header.h') }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe FlipTheSwitch::Generator::Plist do
|
4
|
-
subject(:plist) {
|
4
|
+
subject(:plist) { described_class.new(output, feature_states) }
|
5
5
|
let(:output) { 'spec/resources' }
|
6
6
|
let(:feature_states) { {enabled_feature: true, disabled_feature: false} }
|
7
7
|
let(:output_file) { 'spec/resources/Features.plist' }
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe FlipTheSwitch::Generator::Settings do
|
5
|
+
subject(:settings) { described_class.new(output, feature_states) }
|
6
|
+
let(:output) { 'spec/resources' }
|
7
|
+
let(:settings_bundle) { File.join(output, 'Settings.bundle') }
|
8
|
+
let(:feature_states) { {'first_feature' => true, 'second_feature' => false} }
|
9
|
+
let(:root_output_file) { File.read(File.join(settings_bundle, 'Root.plist')) }
|
10
|
+
let(:features_output_file) { File.read(File.join(settings_bundle, 'Features.plist')) }
|
11
|
+
let(:features_output_file) { File.read(File.join(settings_bundle, 'Features.plist')) }
|
12
|
+
let(:expected_features_file) { File.read('spec/resources/ExpectedSettingsFeatures.plist')}
|
13
|
+
|
14
|
+
after do
|
15
|
+
delete_settings_bundle_if_exists
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when settings already exist' do
|
19
|
+
let(:expected_root_file) { File.read('spec/resources/ExpectedSettingsMergeExistingRoot.plist') }
|
20
|
+
|
21
|
+
before do
|
22
|
+
Dir.mkdir(settings_bundle)
|
23
|
+
File.write(File.join(settings_bundle, 'Root.plist'), File.read('spec/resources/ExistingSettingsRoot.plist'))
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'adds child page link to existing settings' do
|
27
|
+
subject.generate
|
28
|
+
|
29
|
+
expect(root_output_file).to eql(expected_root_file)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'creates a features settings page' do
|
33
|
+
subject.generate
|
34
|
+
|
35
|
+
expect(features_output_file).to eql(expected_features_file)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when settings already exist and have already got features' do
|
40
|
+
let(:expected_root_file) { File.read('spec/resources/ExpectedSettingsMergeExistingRoot.plist') }
|
41
|
+
|
42
|
+
before do
|
43
|
+
Dir.mkdir(settings_bundle)
|
44
|
+
File.write(File.join(settings_bundle, 'Root.plist'), File.read('spec/resources/ExpectedSettingsMergeExistingRoot.plist'))
|
45
|
+
File.write(File.join(settings_bundle, 'Features.plist'), File.read('spec/resources/ExpectedFeatures.plist'))
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'creates settings with features child page link' do
|
49
|
+
subject.generate
|
50
|
+
|
51
|
+
expect(root_output_file).to eql(expected_root_file)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'creates a features settings page' do
|
55
|
+
subject.generate
|
56
|
+
|
57
|
+
expect(features_output_file).to eql(expected_features_file)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when no settings already exist' do
|
62
|
+
let(:expected_root_file) { File.read('spec/resources/ExpectedSettingsBaseRoot.plist') }
|
63
|
+
|
64
|
+
it 'creates settings with features child page link' do
|
65
|
+
subject.generate
|
66
|
+
|
67
|
+
expect(root_output_file).to eql(expected_root_file)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'creates a features settings page' do
|
71
|
+
subject.generate
|
72
|
+
|
73
|
+
expect(features_output_file).to eql(expected_features_file)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete_settings_bundle_if_exists
|
78
|
+
FileUtils.rm_rf(settings_bundle) if Dir.exists?(settings_bundle)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FlipTheSwitch::Reader::Defaults do
|
4
|
+
subject(:reader) { described_class.new }
|
5
|
+
let(:defaults_file) { '.flip.yml' }
|
6
|
+
|
7
|
+
after do
|
8
|
+
File.delete(defaults_file) if File.exists?(defaults_file)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when defaults file exists' do
|
12
|
+
context 'when valid' do
|
13
|
+
before do
|
14
|
+
File.write(defaults_file, YAML.dump({
|
15
|
+
input: 'input',
|
16
|
+
environment: 'environment',
|
17
|
+
enabled: 'enabled',
|
18
|
+
disabled: 'disabled',
|
19
|
+
category_output: 'category_output',
|
20
|
+
plist_output: 'plist_output',
|
21
|
+
settings_output: 'settings_output'
|
22
|
+
}))
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns file input default' do
|
26
|
+
expect(subject.defaults[:input]).to eql('input')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns file environment default' do
|
30
|
+
expect(subject.defaults[:environment]).to eql('environment')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns file enabled default' do
|
34
|
+
expect(subject.defaults[:enabled]).to eql('enabled')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns file disabled default' do
|
38
|
+
expect(subject.defaults[:disabled]).to eql('disabled')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns file category output default' do
|
42
|
+
expect(subject.defaults[:category_output]).to eql('category_output')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns file plist output default' do
|
46
|
+
expect(subject.defaults[:plist_output]).to eql('plist_output')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns file settings output default' do
|
50
|
+
expect(subject.defaults[:settings_output]).to eql('settings_output')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when invalid' do
|
55
|
+
before do
|
56
|
+
File.write(defaults_file, 'this is not what we want')
|
57
|
+
end
|
58
|
+
|
59
|
+
specify do
|
60
|
+
expect {
|
61
|
+
subject.defaults
|
62
|
+
}.to raise_error(FlipTheSwitch::Error::InvalidFile)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when defaults file does NOT exist' do
|
68
|
+
it 'returns base input default' do
|
69
|
+
expect(subject.defaults[:input]).to eql(Dir.pwd)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns base environment default' do
|
73
|
+
expect(subject.defaults[:environment]).to eql('default')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns base enabled default' do
|
77
|
+
expect(subject.defaults[:enabled]).to eql('')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns base disabled default' do
|
81
|
+
expect(subject.defaults[:disabled]).to eql('')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns base category output default' do
|
85
|
+
expect(subject.defaults[:category_output]).to eql(Dir.pwd)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns base plist output default' do
|
89
|
+
expect(subject.defaults[:plist_output]).to eql(Dir.pwd)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns base settings output default' do
|
93
|
+
expect(subject.defaults[:settings_output]).to eql(Dir.pwd)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -1,13 +1,26 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe FlipTheSwitch::Reader::
|
4
|
-
subject(:reader) { described_class.new(input) }
|
3
|
+
describe FlipTheSwitch::Reader::Features do
|
4
|
+
subject(:reader) { described_class.new(input, environment) }
|
5
|
+
let(:environment) { 'beta' }
|
5
6
|
|
6
7
|
context 'when given a real file' do
|
7
8
|
let(:input) { 'spec/resources/real' }
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
context 'when given an valid environment' do
|
11
|
+
it 'reads the enabled/disabled states of the features for the environment' do
|
12
|
+
expect(subject.feature_states).to eql('enabled_feature' => true, 'disabled_feature' => false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when given an invalid environment' do
|
17
|
+
let(:environment) { 'invalid' }
|
18
|
+
|
19
|
+
specify do
|
20
|
+
expect {
|
21
|
+
subject.feature_states
|
22
|
+
}.to raise_error(FlipTheSwitch::Error::InvalidEnvironment)
|
23
|
+
end
|
11
24
|
end
|
12
25
|
end
|
13
26
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>PreferenceSpecifiers</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>Type</key>
|
9
|
+
<string>PSSliderSpecifier</string>
|
10
|
+
<key>Key</key>
|
11
|
+
<string>SomeThing</string>
|
12
|
+
<key>DefaultValue</key>
|
13
|
+
<integer>0</integer>
|
14
|
+
<key>MinimumValue</key>
|
15
|
+
<integer>0</integer>
|
16
|
+
<key>MaximumValue</key>
|
17
|
+
<integer>0</integer>
|
18
|
+
</dict>
|
19
|
+
<dict>
|
20
|
+
<key>Type</key>
|
21
|
+
<string>PSToggleSwitchSpecifier</string>
|
22
|
+
<key>Title</key>
|
23
|
+
<string>On/Off</string>
|
24
|
+
<key>Key</key>
|
25
|
+
<string>whatever</string>
|
26
|
+
<key>DefaultValue</key>
|
27
|
+
<false/>
|
28
|
+
</dict>
|
29
|
+
</array>
|
30
|
+
<key>StringsTable</key>
|
31
|
+
<string>Root</string>
|
32
|
+
</dict>
|
33
|
+
</plist>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>PreferenceSpecifiers</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>Title</key>
|
9
|
+
<string>Features</string>
|
10
|
+
<key>Type</key>
|
11
|
+
<string>PSGroupSpecifier</string>
|
12
|
+
</dict>
|
13
|
+
<dict>
|
14
|
+
<key>File</key>
|
15
|
+
<string>Features</string>
|
16
|
+
<key>Title</key>
|
17
|
+
<string>Features</string>
|
18
|
+
<key>Type</key>
|
19
|
+
<string>PSChildPaneSpecifier</string>
|
20
|
+
</dict>
|
21
|
+
</array>
|
22
|
+
</dict>
|
23
|
+
</plist>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>PreferenceSpecifiers</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>DefaultValue</key>
|
9
|
+
<true/>
|
10
|
+
<key>Key</key>
|
11
|
+
<string>FTS_FEATURE_first_feature</string>
|
12
|
+
<key>Title</key>
|
13
|
+
<string>first_feature</string>
|
14
|
+
<key>Type</key>
|
15
|
+
<string>PSToggleSwitchSpecifier</string>
|
16
|
+
</dict>
|
17
|
+
<dict>
|
18
|
+
<key>DefaultValue</key>
|
19
|
+
<false/>
|
20
|
+
<key>Key</key>
|
21
|
+
<string>FTS_FEATURE_second_feature</string>
|
22
|
+
<key>Title</key>
|
23
|
+
<string>second_feature</string>
|
24
|
+
<key>Type</key>
|
25
|
+
<string>PSToggleSwitchSpecifier</string>
|
26
|
+
</dict>
|
27
|
+
</array>
|
28
|
+
</dict>
|
29
|
+
</plist>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>PreferenceSpecifiers</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>DefaultValue</key>
|
9
|
+
<integer>0</integer>
|
10
|
+
<key>Key</key>
|
11
|
+
<string>SomeThing</string>
|
12
|
+
<key>MaximumValue</key>
|
13
|
+
<integer>0</integer>
|
14
|
+
<key>MinimumValue</key>
|
15
|
+
<integer>0</integer>
|
16
|
+
<key>Type</key>
|
17
|
+
<string>PSSliderSpecifier</string>
|
18
|
+
</dict>
|
19
|
+
<dict>
|
20
|
+
<key>DefaultValue</key>
|
21
|
+
<false/>
|
22
|
+
<key>Key</key>
|
23
|
+
<string>whatever</string>
|
24
|
+
<key>Title</key>
|
25
|
+
<string>On/Off</string>
|
26
|
+
<key>Type</key>
|
27
|
+
<string>PSToggleSwitchSpecifier</string>
|
28
|
+
</dict>
|
29
|
+
<dict>
|
30
|
+
<key>Title</key>
|
31
|
+
<string>Features</string>
|
32
|
+
<key>Type</key>
|
33
|
+
<string>PSGroupSpecifier</string>
|
34
|
+
</dict>
|
35
|
+
<dict>
|
36
|
+
<key>File</key>
|
37
|
+
<string>Features</string>
|
38
|
+
<key>Title</key>
|
39
|
+
<string>Features</string>
|
40
|
+
<key>Type</key>
|
41
|
+
<string>PSChildPaneSpecifier</string>
|
42
|
+
</dict>
|
43
|
+
</array>
|
44
|
+
<key>StringsTable</key>
|
45
|
+
<string>Root</string>
|
46
|
+
</dict>
|
47
|
+
</plist>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flip_the_switch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael England
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-07-
|
12
|
+
date: 2014-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -115,13 +115,21 @@ files:
|
|
115
115
|
- lib/flip_the_switch/generator/header.h.erb
|
116
116
|
- lib/flip_the_switch/generator/implementation.m.erb
|
117
117
|
- lib/flip_the_switch/generator/plist.rb
|
118
|
+
- lib/flip_the_switch/generator/settings.rb
|
118
119
|
- lib/flip_the_switch/reader.rb
|
119
|
-
- lib/flip_the_switch/reader/
|
120
|
+
- lib/flip_the_switch/reader/defaults.rb
|
121
|
+
- lib/flip_the_switch/reader/features.rb
|
120
122
|
- spec/flip_the_switch/cli_spec.rb
|
121
123
|
- spec/flip_the_switch/generator/category_spec.rb
|
122
124
|
- spec/flip_the_switch/generator/plist_spec.rb
|
123
|
-
- spec/flip_the_switch/
|
125
|
+
- spec/flip_the_switch/generator/settings_spec.rb
|
126
|
+
- spec/flip_the_switch/reader/defaults_spec.rb
|
127
|
+
- spec/flip_the_switch/reader/features_spec.rb
|
128
|
+
- spec/resources/ExistingSettingsRoot.plist
|
124
129
|
- spec/resources/ExpectedFeatures.plist
|
130
|
+
- spec/resources/ExpectedSettingsBaseRoot.plist
|
131
|
+
- spec/resources/ExpectedSettingsFeatures.plist
|
132
|
+
- spec/resources/ExpectedSettingsMergeExistingRoot.plist
|
125
133
|
- spec/resources/expected_header.h
|
126
134
|
- spec/resources/expected_implementation.m
|
127
135
|
- spec/resources/invalid_layout/features.yml
|
@@ -148,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
156
|
version: '0'
|
149
157
|
requirements: []
|
150
158
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.
|
159
|
+
rubygems_version: 2.0.3
|
152
160
|
signing_key:
|
153
161
|
specification_version: 4
|
154
162
|
summary: A simple library to help enabling/disabling features on iOS/Mac applications.
|
@@ -156,8 +164,14 @@ test_files:
|
|
156
164
|
- spec/flip_the_switch/cli_spec.rb
|
157
165
|
- spec/flip_the_switch/generator/category_spec.rb
|
158
166
|
- spec/flip_the_switch/generator/plist_spec.rb
|
159
|
-
- spec/flip_the_switch/
|
167
|
+
- spec/flip_the_switch/generator/settings_spec.rb
|
168
|
+
- spec/flip_the_switch/reader/defaults_spec.rb
|
169
|
+
- spec/flip_the_switch/reader/features_spec.rb
|
170
|
+
- spec/resources/ExistingSettingsRoot.plist
|
160
171
|
- spec/resources/ExpectedFeatures.plist
|
172
|
+
- spec/resources/ExpectedSettingsBaseRoot.plist
|
173
|
+
- spec/resources/ExpectedSettingsFeatures.plist
|
174
|
+
- spec/resources/ExpectedSettingsMergeExistingRoot.plist
|
161
175
|
- spec/resources/expected_header.h
|
162
176
|
- spec/resources/expected_implementation.m
|
163
177
|
- spec/resources/invalid_layout/features.yml
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module FlipTheSwitch
|
4
|
-
module Reader
|
5
|
-
class Yaml
|
6
|
-
def initialize(input)
|
7
|
-
@input = input
|
8
|
-
end
|
9
|
-
|
10
|
-
def feature_states
|
11
|
-
if valid_file?
|
12
|
-
file_states
|
13
|
-
else
|
14
|
-
raise Error::InvalidFile.new
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
attr_reader :input
|
20
|
-
|
21
|
-
def valid_file?
|
22
|
-
file_states.is_a?(Hash) && file_states.all? { |feature, state|
|
23
|
-
feature.is_a?(String) && !!state == state
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
def file_states
|
28
|
-
@file_states ||= YAML.load_file(input_file)
|
29
|
-
rescue SystemCallError => e
|
30
|
-
raise Error::UnreadableFile.new(e)
|
31
|
-
end
|
32
|
-
|
33
|
-
def input_file
|
34
|
-
File.join(input, 'features.yml')
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|