flip_the_switch 0.3.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +146 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGELOG.md +14 -0
  6. data/Classes/FlipTheSwitch/FlipTheSwitch.h +9 -0
  7. data/Classes/FlipTheSwitch/FlipTheSwitch.m +88 -0
  8. data/Example/.gitignore +2 -0
  9. data/Example/Colors-iOS/AppDelegateiOS.h +3 -0
  10. data/Example/Colors-iOS/AppDelegateiOS.m +4 -0
  11. data/Example/Colors-iOS/Base.lproj/Main_iPhone.storyboard +76 -0
  12. data/Example/Colors-iOS/Colors-iOS-Info.plist +49 -0
  13. data/Example/Colors-iOS/Colors-iOS-Prefix.pch +16 -0
  14. data/Example/Colors-iOS/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  15. data/Example/Colors-iOS/Images.xcassets/LaunchImage.launchimage/Contents.json +51 -0
  16. data/Example/Colors-iOS/ViewControlleriOS.h +2 -0
  17. data/Example/Colors-iOS/ViewControlleriOS.m +78 -0
  18. data/Example/Colors-iOS/main.m +8 -0
  19. data/Example/Colors.xcodeproj/project.pbxproj +358 -0
  20. data/Example/Colors.xcodeproj/xcshareddata/xcschemes/Colors-iOS.xcscheme +77 -0
  21. data/Example/Podfile +4 -0
  22. data/Example/Rakefile +23 -0
  23. data/Example/features.yml +2 -0
  24. data/FlipTheSwitch.podspec +16 -0
  25. data/Gemfile +17 -0
  26. data/Guardfile.example +15 -0
  27. data/LICENSE +21 -0
  28. data/README.md +104 -0
  29. data/Rakefile +35 -0
  30. data/Tests/FlipTheSwitchSpec-Mac/Features.plist +8 -0
  31. data/Tests/FlipTheSwitchSpec-Mac/FlipTheSwitchSpec-Mac-Info.plist +22 -0
  32. data/Tests/FlipTheSwitchSpec-Mac/FlipTheSwitchSpec-Mac-Prefix.pch +13 -0
  33. data/Tests/FlipTheSwitchSpec-iOS/Features.plist +8 -0
  34. data/Tests/FlipTheSwitchSpec-iOS/FlipTheSwitchSpec-iOS-Info.plist +22 -0
  35. data/Tests/FlipTheSwitchSpec-iOS/FlipTheSwitchSpec-iOS-Prefix.pch +14 -0
  36. data/Tests/FlipTheSwitchSpec.xcodeproj/project.pbxproj +605 -0
  37. data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-Mac.xcscheme +75 -0
  38. data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-iOS.xcscheme +75 -0
  39. data/Tests/Podfile +15 -0
  40. data/Tests/Rakefile +22 -0
  41. data/Tests/Spec/Classes/FlipTheSwitch/FlipTheSwitchSpec.m +88 -0
  42. data/Tests/Spec/Helpers/GcovTestObserver.h +4 -0
  43. data/Tests/Spec/Helpers/GcovTestObserver.m +12 -0
  44. data/bin/flip-the-switch +4 -0
  45. data/flip_the_switch.gemspec +17 -0
  46. data/lib/flip_the_switch/cli.rb +61 -0
  47. data/lib/flip_the_switch/errors.rb +12 -0
  48. data/lib/flip_the_switch/generator/base.rb +13 -0
  49. data/lib/flip_the_switch/generator/category.rb +71 -0
  50. data/lib/flip_the_switch/generator/header.h.erb +11 -0
  51. data/lib/flip_the_switch/generator/implementation.m.erb +26 -0
  52. data/lib/flip_the_switch/generator/plist.rb +17 -0
  53. data/lib/flip_the_switch/generator.rb +3 -0
  54. data/lib/flip_the_switch/reader/yaml.rb +39 -0
  55. data/lib/flip_the_switch/reader.rb +1 -0
  56. data/lib/flip_the_switch.rb +3 -0
  57. data/spec/flip_the_switch/cli_spec.rb +81 -0
  58. data/spec/flip_the_switch/generator/category_spec.rb +44 -0
  59. data/spec/flip_the_switch/generator/plist_spec.rb +19 -0
  60. data/spec/flip_the_switch/reader/yaml_spec.rb +43 -0
  61. data/spec/resources/ExpectedFeatures.plist +10 -0
  62. data/spec/resources/expected_header.h +16 -0
  63. data/spec/resources/expected_implementation.m +46 -0
  64. data/spec/resources/invalid_layout/features.yml +4 -0
  65. data/spec/resources/invalid_type/features.yml +7 -0
  66. data/spec/resources/real/features.yml +2 -0
  67. data/spec/spec_helper.rb +15 -0
  68. metadata +166 -0
@@ -0,0 +1,75 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ version = "1.3">
4
+ <BuildAction
5
+ parallelizeBuildables = "YES"
6
+ buildImplicitDependencies = "YES">
7
+ <BuildActionEntries>
8
+ <BuildActionEntry
9
+ buildForTesting = "YES"
10
+ buildForRunning = "YES"
11
+ buildForProfiling = "YES"
12
+ buildForArchiving = "YES"
13
+ buildForAnalyzing = "YES">
14
+ <BuildableReference
15
+ BuildableIdentifier = "primary"
16
+ BlueprintIdentifier = "5B87AFE9193A80F20082F7A1"
17
+ BuildableName = "FlipTheSwitchSpec-iOS.xctest"
18
+ BlueprintName = "FlipTheSwitchSpec-iOS"
19
+ ReferencedContainer = "container:FlipTheSwitchSpec.xcodeproj">
20
+ </BuildableReference>
21
+ </BuildActionEntry>
22
+ </BuildActionEntries>
23
+ </BuildAction>
24
+ <TestAction
25
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
26
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
27
+ shouldUseLaunchSchemeArgsEnv = "YES"
28
+ buildConfiguration = "Debug">
29
+ <Testables>
30
+ <TestableReference
31
+ skipped = "NO">
32
+ <BuildableReference
33
+ BuildableIdentifier = "primary"
34
+ BlueprintIdentifier = "5B87AFE9193A80F20082F7A1"
35
+ BuildableName = "FlipTheSwitchSpec-iOS.xctest"
36
+ BlueprintName = "FlipTheSwitchSpec-iOS"
37
+ ReferencedContainer = "container:FlipTheSwitchSpec.xcodeproj">
38
+ </BuildableReference>
39
+ </TestableReference>
40
+ </Testables>
41
+ </TestAction>
42
+ <LaunchAction
43
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
44
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
45
+ launchStyle = "0"
46
+ useCustomWorkingDirectory = "NO"
47
+ buildConfiguration = "Debug"
48
+ ignoresPersistentStateOnLaunch = "NO"
49
+ debugDocumentVersioning = "YES"
50
+ allowLocationSimulation = "YES">
51
+ <EnvironmentVariables>
52
+ <EnvironmentVariable
53
+ key = "SPECTA_REPORTER_CLASS"
54
+ value = "GcovTestObserver"
55
+ isEnabled = "YES">
56
+ </EnvironmentVariable>
57
+ </EnvironmentVariables>
58
+ <AdditionalOptions>
59
+ </AdditionalOptions>
60
+ </LaunchAction>
61
+ <ProfileAction
62
+ shouldUseLaunchSchemeArgsEnv = "YES"
63
+ savedToolIdentifier = ""
64
+ useCustomWorkingDirectory = "NO"
65
+ buildConfiguration = "Release"
66
+ debugDocumentVersioning = "YES">
67
+ </ProfileAction>
68
+ <AnalyzeAction
69
+ buildConfiguration = "Debug">
70
+ </AnalyzeAction>
71
+ <ArchiveAction
72
+ buildConfiguration = "Release"
73
+ revealArchiveInOrganizer = "YES">
74
+ </ArchiveAction>
75
+ </Scheme>
data/Tests/Podfile ADDED
@@ -0,0 +1,15 @@
1
+ def needed_pods
2
+ pod 'Specta'
3
+ pod 'Expecta'
4
+ pod 'OCMockito'
5
+ end
6
+
7
+ target 'FlipTheSwitchSpec-iOS' do
8
+ platform :ios, :deployment_target => 6.0
9
+ needed_pods
10
+ end
11
+
12
+ target 'FlipTheSwitchSpec-Mac' do
13
+ platform :osx, :deployment_target => 10.8
14
+ needed_pods
15
+ end
data/Tests/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake/clean'
2
+
3
+ def pods; 'Pods'; end
4
+ def podfile_lock; 'Podfile.lock'; end
5
+ def build; 'build'; end
6
+ def workspace; 'FlipTheSwitchSpec'; end
7
+
8
+ CLOBBER.include(podfile_lock)
9
+ CLOBBER.include(pods)
10
+
11
+ CLEAN.include(build)
12
+
13
+ task :default => :test
14
+
15
+ file podfile_lock do
16
+ sh 'pod install'
17
+ end
18
+
19
+ task :test => podfile_lock do
20
+ sh "xctool test -scheme #{workspace}-Mac -workspace #{workspace}.xcworkspace OBJROOT=#{build} SHARED_PRECOMPS_DIR=#{build}"
21
+ sh "xctool test -scheme #{workspace}-iOS -workspace #{workspace}.xcworkspace -sdk iphonesimulator OBJROOT=#{build} SHARED_PRECOMPS_DIR=#{build}"
22
+ end
@@ -0,0 +1,88 @@
1
+ #import "FlipTheSwitch.h"
2
+
3
+ @interface FlipTheSwitch (Spec)
4
+ - (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults
5
+ bundle:(NSBundle *)bundle;
6
+ @end
7
+
8
+ SpecBegin(FlipTheSwitch)
9
+ __block FlipTheSwitch *subject;
10
+
11
+ __block NSUserDefaults *userDefaults;
12
+
13
+ __block NSString *standardFeature;
14
+ __block NSString *plistEnabledFeature;
15
+
16
+ before(^{
17
+ userDefaults = [[NSUserDefaults alloc] init];
18
+
19
+ standardFeature = @"standard_feature";
20
+ plistEnabledFeature = @"plist_enabled_feature";
21
+
22
+ subject = [[FlipTheSwitch alloc] initWithUserDefaults:userDefaults
23
+ bundle:[NSBundle bundleForClass:[self class]]];
24
+ });
25
+
26
+ after(^{
27
+ for (NSString *key in [userDefaults dictionaryRepresentation]) {
28
+ [userDefaults removeObjectForKey:key];
29
+ }
30
+ [userDefaults synchronize];
31
+ });
32
+
33
+ it(@"is a singleton", ^{
34
+ expect([FlipTheSwitch sharedInstance]).to.beIdenticalTo([FlipTheSwitch sharedInstance]);
35
+ });
36
+
37
+ context(@"when feature is NOT set", ^{
38
+ context(@"when feature defaults to enabled through plist", ^{
39
+ it(@"is enabled", ^{
40
+ expect([subject isFeatureEnabled:plistEnabledFeature]).to.beTruthy();
41
+ });
42
+ });
43
+
44
+ context(@"when feature does not default to enabled through plist", ^{
45
+ it(@"is disabled", ^{
46
+ expect([subject isFeatureEnabled:standardFeature]).to.beFalsy();
47
+ });
48
+ });
49
+ });
50
+
51
+ context(@"when feature is manually enabled", ^{
52
+ before(^{
53
+ [subject enableFeature:standardFeature];
54
+ [subject enableFeature:plistEnabledFeature];
55
+ });
56
+
57
+ it(@"is enabled", ^{
58
+ expect([subject isFeatureEnabled:standardFeature]).to.beTruthy();
59
+ expect([subject isFeatureEnabled:plistEnabledFeature]).to.beTruthy();
60
+ });
61
+ });
62
+
63
+ context(@"when feature is manually enabled", ^{
64
+ before(^{
65
+ [subject enableFeature:standardFeature];
66
+ [subject enableFeature:plistEnabledFeature];
67
+ [subject disableFeature:standardFeature];
68
+ [subject disableFeature:plistEnabledFeature];
69
+ });
70
+
71
+ it(@"is enabled", ^{
72
+ expect([subject isFeatureEnabled:standardFeature]).to.beFalsy();
73
+ expect([subject isFeatureEnabled:plistEnabledFeature]).to.beFalsy();
74
+ });
75
+ });
76
+
77
+ context(@"when feature is manually set", ^{
78
+ before(^{
79
+ [subject setFeature:standardFeature enabled:YES];
80
+ [subject setFeature:plistEnabledFeature enabled:YES];
81
+ });
82
+
83
+ it(@"is enabled", ^{
84
+ expect([subject isFeatureEnabled:standardFeature]).to.beTruthy();
85
+ expect([subject isFeatureEnabled:plistEnabledFeature]).to.beTruthy();
86
+ });
87
+ });
88
+ SpecEnd
@@ -0,0 +1,4 @@
1
+ #import <Specta/SPTNestedReporter.h>
2
+
3
+ @interface GcovTestObserver : SPTNestedReporter
4
+ @end
@@ -0,0 +1,12 @@
1
+ #import "GcovTestObserver.h"
2
+
3
+ @implementation GcovTestObserver
4
+
5
+ - (void)stopObserving
6
+ {
7
+ [super stopObserving];
8
+ extern void __gcov_flush(void);
9
+ __gcov_flush();
10
+ }
11
+
12
+ @end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'flip_the_switch/cli'
3
+
4
+ FlipTheSwitch::Cli.start
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'flip_the_switch'
3
+ s.authors = ['Michael England', 'Rob Siwek']
4
+ s.email = %w(mg.england@gmail.com rob@robsiwek.com)
5
+ s.summary = 'A simple library to help enabling/disabling features on iOS/Mac applications.'
6
+ s.homepage = 'https://github.com/michaelengland/FlipTheSwitch'
7
+ s.version = '0.3.0'
8
+ s.license = 'MIT'
9
+
10
+ s.add_dependency 'activesupport', '~> 3.2'
11
+ s.add_dependency 'thor', '~> 0.19'
12
+ s.add_dependency 'plist', '~> 3.1'
13
+
14
+ s.files = `git ls-files`.split($\)
15
+ s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ end
@@ -0,0 +1,61 @@
1
+ require 'thor'
2
+ require 'flip_the_switch'
3
+
4
+ module FlipTheSwitch
5
+ class Cli < Thor
6
+ class_option :input, type: :string, aliases: '-i', default: Dir.pwd, desc: 'Location of the directory containing features.yml file to read'
7
+ class_option :enabled, type: :array, aliases: '-e', default: [], desc: 'Extra features to be set as enabled'
8
+ class_option :disabled, type: :array, aliases: '-d', default: [], desc: 'Extra features to be set as disabled'
9
+
10
+ desc 'plist', 'Auto-generates a Features.plist file for enabled/disabled features'
11
+ method_option :output, type: :string, aliases: '-o', default: Dir.pwd, desc: 'Location of the directory in which Features.plist file will be created'
12
+ def plist
13
+ plist_generator.generate
14
+ end
15
+
16
+ desc 'category', 'Auto-generates .h & .m files for enabled/disabled features'
17
+ method_option :output, type: :string, aliases: '-o', default: Dir.pwd, desc: 'Location of the directory in which FlipTheSwitch+Features.{h,m} files will be created'
18
+ def category
19
+ category_generator.generate
20
+ end
21
+
22
+ private
23
+
24
+ def plist_generator
25
+ Generator::Plist.new(output, feature_states)
26
+ end
27
+
28
+ def category_generator
29
+ Generator::Category.new(output, feature_states)
30
+ end
31
+
32
+ def output
33
+ options.output
34
+ end
35
+
36
+ def feature_states
37
+ yaml_reader.feature_states.
38
+ merge(enabled_states).
39
+ merge(disabled_states)
40
+ end
41
+
42
+ def yaml_reader
43
+ Reader::Yaml.new(options.input)
44
+ end
45
+
46
+ def enabled_states
47
+ states_for(options.enabled, true)
48
+ end
49
+
50
+ def disabled_states
51
+ states_for(options.disabled, false)
52
+ end
53
+
54
+ def states_for(array, default)
55
+ array.inject({}) do |h, feature|
56
+ h[feature] = default
57
+ h
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,12 @@
1
+ module FlipTheSwitch
2
+ module Error
3
+ class Base < StandardError
4
+ end
5
+
6
+ class UnreadableFile < Base
7
+ end
8
+
9
+ class InvalidFile < Base
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module FlipTheSwitch
2
+ module Generator
3
+ class Base
4
+ def initialize(output, feature_states)
5
+ @output = output
6
+ @feature_states = feature_states
7
+ end
8
+
9
+ protected
10
+ attr_reader :output, :feature_states
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ require 'active_support/inflector'
2
+ require 'erb'
3
+
4
+ module FlipTheSwitch
5
+ module Generator
6
+ class Category < Base
7
+ def generate
8
+ delete_existing
9
+ write_files
10
+ end
11
+
12
+ private
13
+
14
+ def delete_existing
15
+ delete_file(header_file)
16
+ delete_file(implementation_file)
17
+ end
18
+
19
+ def write_files
20
+ write_file(header_file, header)
21
+ write_file(implementation_file, implementation)
22
+ end
23
+
24
+ def write_file(file, text)
25
+ File.open(file, 'w') do |f|
26
+ f.syswrite(text)
27
+ end
28
+ end
29
+
30
+ def delete_file(file)
31
+ File.delete(file) if File.exists?(file)
32
+ end
33
+
34
+ def header_file
35
+ File.join(output, 'FlipTheSwitch+Features.h')
36
+ end
37
+
38
+ def implementation_file
39
+ File.join(output, 'FlipTheSwitch+Features.m')
40
+ end
41
+
42
+ def header
43
+ render(header_template)
44
+ end
45
+
46
+ def implementation
47
+ render(implementation_template)
48
+ end
49
+
50
+ def render(template)
51
+ ERB.new(template).result(binding)
52
+ end
53
+
54
+ def header_template
55
+ file_template('header.h')
56
+ end
57
+
58
+ def implementation_template
59
+ file_template('implementation.m')
60
+ end
61
+
62
+ def file_template(name)
63
+ File.read(File.expand_path("../#{name}.erb", __FILE__))
64
+ end
65
+
66
+ def feature_names
67
+ feature_states.keys.map(&:to_s)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,11 @@
1
+ /* AUTO-GENERATED. DO NOT ALTER */
2
+ #import <FlipTheSwitch/FlipTheSwitch.h>
3
+
4
+ @interface FlipTheSwitch (Features)
5
+ <% for feature in feature_names %>
6
+ + (BOOL)is<%= feature.camelize %>Enabled;
7
+ + (void)enable<%= feature.camelize %>;
8
+ + (void)disable<%= feature.camelize %>;
9
+ + (void)set<%= feature.camelize %>Enabled:(BOOL)enabled;
10
+ <% end %>
11
+ @end
@@ -0,0 +1,26 @@
1
+ /* AUTO-GENERATED. DO NOT ALTER */
2
+ #import "FlipTheSwitch+Features.h"
3
+
4
+ @implementation FlipTheSwitch (Features)
5
+ <% for feature in feature_names %>
6
+ + (BOOL)is<%= feature.camelize %>Enabled
7
+ {
8
+ return [[FlipTheSwitch sharedInstance] isFeatureEnabled:@"<%= feature %>"];
9
+ }
10
+
11
+ + (void)enable<%= feature.camelize %>
12
+ {
13
+ [[FlipTheSwitch sharedInstance] enableFeature:@"<%= feature %>"];
14
+ }
15
+
16
+ + (void)disable<%= feature.camelize %>
17
+ {
18
+ [[FlipTheSwitch sharedInstance] disableFeature:@"<%= feature %>"];
19
+ }
20
+
21
+ + (void)set<%= feature.camelize %>Enabled:(BOOL)enabled
22
+ {
23
+ [[FlipTheSwitch sharedInstance] setFeature:@"<%= feature %>" enabled:enabled];
24
+ }
25
+ <% end %>
26
+ @end
@@ -0,0 +1,17 @@
1
+ require 'plist'
2
+
3
+ module FlipTheSwitch
4
+ module Generator
5
+ class Plist < Base
6
+ def generate
7
+ ::Plist::Emit.save_plist(feature_states, output_file)
8
+ end
9
+
10
+ private
11
+
12
+ def output_file
13
+ File.join(output, 'Features.plist')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ require 'flip_the_switch/generator/base'
2
+ require 'flip_the_switch/generator/category'
3
+ require 'flip_the_switch/generator/plist'
@@ -0,0 +1,39 @@
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
+
@@ -0,0 +1 @@
1
+ require 'flip_the_switch/reader/yaml'
@@ -0,0 +1,3 @@
1
+ require 'flip_the_switch/errors'
2
+ require 'flip_the_switch/reader'
3
+ require 'flip_the_switch/generator'
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe FlipTheSwitch::Cli do
4
+ subject(:cli) { described_class }
5
+ let(:perform) { subject.start([command] + options, debug: true) }
6
+
7
+ context 'when invalid command called' do
8
+ let(:command) { 'invalid' }
9
+ let(:options) { [] }
10
+
11
+ it 'throws an error' do
12
+ expect {
13
+ perform
14
+ }.to raise_error
15
+ end
16
+ end
17
+
18
+ shared_examples_for 'generator' do
19
+ let(:yaml_reader) { double(FlipTheSwitch::Reader::Yaml, feature_states: {'something' => true}) }
20
+ let(:generator) { double(generator_class) }
21
+
22
+ context 'when no options given' do
23
+ let(:options) { [] }
24
+
25
+ before do
26
+ FlipTheSwitch::Reader::Yaml.stub(:new).with(Dir.pwd).and_return(yaml_reader)
27
+ generator_class.stub(:new).with(Dir.pwd, 'something' => true).and_return(generator)
28
+ end
29
+
30
+ it 'generates using default options' do
31
+ expect(generator).to receive(:generate)
32
+ perform
33
+ end
34
+ end
35
+
36
+ context 'when options given' do
37
+ before do
38
+ FlipTheSwitch::Reader::Yaml.stub(:new).with('input').and_return(yaml_reader)
39
+ generator_class.stub(:new).with('output', {
40
+ 'something' => true,
41
+ 'en' => true,
42
+ 'abled' => true,
43
+ 'dis' => false,
44
+ 'appointing' => false
45
+ }).and_return(generator)
46
+ end
47
+
48
+ context 'using full name' do
49
+ let(:options) { %w(--input=input --output=output --enabled=en abled --disabled=dis appointing) }
50
+
51
+ it 'generates using the options given' do
52
+ expect(generator).to receive(:generate)
53
+ perform
54
+ end
55
+ end
56
+
57
+ context 'using aliases' do
58
+ let(:options) { %w(-i=input -o=output -e=en abled -d=dis appointing) }
59
+
60
+ it 'generates using the options given' do
61
+ expect(generator).to receive(:generate)
62
+ perform
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ context 'when plist command called' do
69
+ let(:command) { 'plist' }
70
+ let(:generator_class) { FlipTheSwitch::Generator::Plist }
71
+
72
+ it_behaves_like 'generator'
73
+ end
74
+
75
+ context 'when category command called' do
76
+ let(:command) { 'category' }
77
+ let(:generator_class) { FlipTheSwitch::Generator::Category }
78
+
79
+ it_behaves_like 'generator'
80
+ end
81
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe FlipTheSwitch::Generator::Category do
4
+ subject(:category) { FlipTheSwitch::Generator::Category.new(output, feature_states) }
5
+ let(:output) { 'spec/resources' }
6
+ let(:feature_states) { {'first_feature' => true, 'second_feature' => false} }
7
+ let(:expected_header_file) { File.read('spec/resources/expected_header.h') }
8
+ let(:expected_implementation_file) { File.read('spec/resources/expected_implementation.m') }
9
+
10
+ after do
11
+ delete_header_if_exists
12
+ delete_implementation_if_exists
13
+ end
14
+
15
+ it 'writes a FlipTheSwitch+Features.h file with the category header' do
16
+ subject.generate
17
+
18
+ expect(File.read(output_name_with('h'))).to eql(expected_header_file)
19
+ end
20
+
21
+ it 'writes a FlipTheSwitch+Features.m file with the category implementation' do
22
+ subject.generate
23
+
24
+ expect(File.read(output_name_with('m'))).to eql(expected_implementation_file)
25
+ end
26
+
27
+ private
28
+
29
+ def delete_header_if_exists
30
+ delete_output_if_exists_with('h')
31
+ end
32
+
33
+ def delete_implementation_if_exists
34
+ delete_output_if_exists_with('m')
35
+ end
36
+
37
+ def delete_output_if_exists_with(suffix)
38
+ File.delete(output_name_with(suffix)) if File.exists?(output_name_with(suffix))
39
+ end
40
+
41
+ def output_name_with(suffix)
42
+ "#{output}/FlipTheSwitch+Features.#{suffix}"
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe FlipTheSwitch::Generator::Plist do
4
+ subject(:plist) { FlipTheSwitch::Generator::Plist.new(output, feature_states) }
5
+ let(:output) { 'spec/resources' }
6
+ let(:feature_states) { {enabled_feature: true, disabled_feature: false} }
7
+ let(:output_file) { 'spec/resources/Features.plist' }
8
+ let(:expected_plist_file) { File.read('spec/resources/ExpectedFeatures.plist') }
9
+
10
+ after do
11
+ File.delete(output_file) if File.exists?(output_file)
12
+ end
13
+
14
+ it 'writes a Features.plist file with the enabled features set' do
15
+ subject.generate
16
+
17
+ expect(File.read(output_file)).to eql(expected_plist_file)
18
+ end
19
+ end