flip_the_switch 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/michaelengland/FlipTheSwitch.svg?branch=master)](https://travis-ci.org/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch/coverage.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Gem Version](https://badge.fury.io/rb/
|
5
|
+
# flip_the_switch [![Build Status](https://travis-ci.org/michaelengland/FlipTheSwitch.svg?branch=master)](https://travis-ci.org/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch/coverage.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Gem Version](https://badge.fury.io/rb/flip_the_switch.svg)](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
|
-
|