feature 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +11 -0
- data/Gemfile +4 -0
- data/README.md +26 -0
- data/Rakefile +10 -0
- data/lib/feature.rb +90 -0
- data/lib/feature/repository.rb +7 -0
- data/lib/feature/repository/abstract_repository.rb +37 -0
- data/lib/feature/repository/simple_repository.rb +86 -0
- data/lib/feature/repository/yaml_repository.rb +81 -0
- data/spec/feature/abstract_repository_spec.rb +9 -0
- data/spec/feature/feature_spec.rb +161 -0
- data/spec/feature/simple_repository_spec.rb +67 -0
- data/spec/feature/yaml_repository_spec.rb +74 -0
- data/spec/spec_helper.rb +9 -0
- metadata +80 -0
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Feature
|
2
|
+
|
3
|
+
Feature is a [feature toggle](http://martinfowler.com/bliki/FeatureToggle.html) library for ruby.
|
4
|
+
|
5
|
+
The feature toggle functionality has to be configured by feature repositories. A feature repository simply provides lists of active and inctive features.
|
6
|
+
With this approach Feature is higly configurable and not bound to a specific kind of configuration.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
gem install feature
|
11
|
+
|
12
|
+
## Example usage
|
13
|
+
|
14
|
+
require 'feature'
|
15
|
+
|
16
|
+
repo = Feature::Repository::SimpleRepository.new
|
17
|
+
repo.add_active_feature :be_nice
|
18
|
+
|
19
|
+
Feature.set_repository repo
|
20
|
+
|
21
|
+
Feature.active?(:be_nice)
|
22
|
+
# => true
|
23
|
+
|
24
|
+
Feature.with(:be_nice) do
|
25
|
+
puts "you can read this"
|
26
|
+
end
|
data/Rakefile
ADDED
data/lib/feature.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
##
|
2
|
+
# Feature module provides all methods
|
3
|
+
# - to set a feature repository
|
4
|
+
# - to check if a feature (represented by a symbol) is acitve or inactive
|
5
|
+
# - for conditional block execution with or without a feature
|
6
|
+
# - to refresh the feature lists (request them from repository)
|
7
|
+
#
|
8
|
+
module Feature
|
9
|
+
require 'feature/repository'
|
10
|
+
|
11
|
+
@repository = nil
|
12
|
+
@active_features = nil
|
13
|
+
@inactive_features = nil
|
14
|
+
|
15
|
+
##
|
16
|
+
# Set the feature repository
|
17
|
+
#
|
18
|
+
# @param Feature::Repository::AbstractRepository, repository
|
19
|
+
#
|
20
|
+
def self.set_repository(repository)
|
21
|
+
if !repository.is_a?(Feature::Repository::AbstractRepository)
|
22
|
+
raise ArgumentError, "given argument is not a repository"
|
23
|
+
end
|
24
|
+
|
25
|
+
@repository = repository
|
26
|
+
refresh!
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Obtains list of active and inactive features from repository
|
31
|
+
#
|
32
|
+
def self.refresh!
|
33
|
+
@active_features = @repository.active_features
|
34
|
+
@inactive_features = @repository.inactive_features
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Requests if feature is active
|
39
|
+
#
|
40
|
+
# @param Symbol, feature
|
41
|
+
# @return Boolean
|
42
|
+
#
|
43
|
+
def self.active?(feature)
|
44
|
+
if !@repository
|
45
|
+
raise "Feature is missing Repository for obtaining feature lists"
|
46
|
+
end
|
47
|
+
|
48
|
+
@active_features.include?(feature)
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Requests if feature is inactive
|
53
|
+
#
|
54
|
+
# @param Symbol, feature
|
55
|
+
# @return Boolean
|
56
|
+
#
|
57
|
+
def self.inactive?(feature)
|
58
|
+
if !@repository
|
59
|
+
raise "Feature is missing Repository for obtaining feature lists"
|
60
|
+
end
|
61
|
+
|
62
|
+
@inactive_features.include?(feature)
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Execute the given block if feature is active
|
67
|
+
#
|
68
|
+
def self.with(feature)
|
69
|
+
if !block_given?
|
70
|
+
raise ArgumentError, "no block given to #{__method__}"
|
71
|
+
end
|
72
|
+
|
73
|
+
if active?(feature)
|
74
|
+
yield
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Execute the given block if feature is inactive
|
80
|
+
#
|
81
|
+
def self.without(feature)
|
82
|
+
if !block_given?
|
83
|
+
raise ArgumentError, "no block given to #{__method__}"
|
84
|
+
end
|
85
|
+
|
86
|
+
if inactive?(feature)
|
87
|
+
yield
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Feature
|
2
|
+
module Repository
|
3
|
+
##
|
4
|
+
# Abstract class for subclassing and building repository classes which
|
5
|
+
# provide lists of active and inactive features
|
6
|
+
#
|
7
|
+
class AbstractRepository
|
8
|
+
|
9
|
+
##
|
10
|
+
# Constructor
|
11
|
+
#
|
12
|
+
# Should be overridden in derived class to initialize repository with all data needed
|
13
|
+
#
|
14
|
+
def initialize
|
15
|
+
raise "abstract class #{self.class.name}!"
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns list of active features
|
20
|
+
#
|
21
|
+
# @return Array<Symbol>
|
22
|
+
#
|
23
|
+
def active_features
|
24
|
+
raise "#{__method__} has to be overridden in derived class"
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Returns list of inactive features
|
29
|
+
#
|
30
|
+
# @return Array<Symbol>
|
31
|
+
#
|
32
|
+
def inactive_features
|
33
|
+
raise "#{__method__} has to be overridden in derived class"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Feature
|
2
|
+
module Repository
|
3
|
+
##
|
4
|
+
# SimpleRepository for active and inactive feature list
|
5
|
+
# Simply add features to both lists, not config or data sources required
|
6
|
+
#
|
7
|
+
class SimpleRepository < AbstractRepository
|
8
|
+
##
|
9
|
+
# Constructor
|
10
|
+
#
|
11
|
+
def initialize
|
12
|
+
@active_features = []
|
13
|
+
@inactive_features = []
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns list of active features
|
18
|
+
#
|
19
|
+
# @return Array<Symbol>
|
20
|
+
#
|
21
|
+
def active_features
|
22
|
+
@active_features.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Returns list of inactive features
|
27
|
+
#
|
28
|
+
# @return Array<Symbol>
|
29
|
+
#
|
30
|
+
def inactive_features
|
31
|
+
@inactive_features.dup
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Add an active feature
|
36
|
+
#
|
37
|
+
# @param Sybmol, feature
|
38
|
+
#
|
39
|
+
def add_active_feature(feature)
|
40
|
+
check_feature_is_symbol(feature)
|
41
|
+
check_feature_already_in_lists(feature)
|
42
|
+
@active_features << feature
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Add an inactive feature
|
47
|
+
#
|
48
|
+
# @param Sybmol, feature
|
49
|
+
#
|
50
|
+
def add_inactive_feature(feature)
|
51
|
+
check_feature_is_symbol(feature)
|
52
|
+
check_feature_already_in_lists(feature)
|
53
|
+
@inactive_features << feature
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Checks if the given feature is a symbol and raises and raises an exception if so
|
58
|
+
#
|
59
|
+
# @param Sybmol, feature
|
60
|
+
#
|
61
|
+
def check_feature_is_symbol(feature)
|
62
|
+
if !feature.is_a?(Symbol)
|
63
|
+
raise ArgumentError, "given feature #{feature} is not a symbol"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
private :check_feature_is_symbol
|
67
|
+
|
68
|
+
##
|
69
|
+
# Checks if given feature is already added to list of active or inactive features
|
70
|
+
# and raises an exception if so
|
71
|
+
#
|
72
|
+
# @param Symbol, feature
|
73
|
+
#
|
74
|
+
def check_feature_already_in_lists(feature)
|
75
|
+
if @active_features.include?(feature)
|
76
|
+
raise ArgumentError, "feature :#{feature} already added to list of active features"
|
77
|
+
end
|
78
|
+
|
79
|
+
if @inactive_features.include?(feature)
|
80
|
+
raise ArgumentError, "feature :#{feature} already added to list of inactive features"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
private :check_feature_already_in_lists
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Feature
|
2
|
+
module Repository
|
3
|
+
##
|
4
|
+
# YamlRepository for active and inactive feature list
|
5
|
+
# The yaml config file should look like this:
|
6
|
+
#
|
7
|
+
# features:
|
8
|
+
# an_active_feature: true
|
9
|
+
# an_inactive_feature: false
|
10
|
+
#
|
11
|
+
class YamlRepository < AbstractRepository
|
12
|
+
require 'yaml'
|
13
|
+
|
14
|
+
##
|
15
|
+
# Constructor
|
16
|
+
#
|
17
|
+
# @param String, yaml_file_name
|
18
|
+
#
|
19
|
+
def initialize(yaml_file_name)
|
20
|
+
@yaml_file_name = yaml_file_name
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Returns list of active features
|
25
|
+
#
|
26
|
+
# @return Array<Symbol>
|
27
|
+
#
|
28
|
+
def active_features
|
29
|
+
get_active_features_from_file
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Return a list of active features read from the config file
|
34
|
+
#
|
35
|
+
# @return Array<Symbol>
|
36
|
+
#
|
37
|
+
def get_active_features_from_file
|
38
|
+
features_hash = read_and_parse_file_data
|
39
|
+
features = features_hash.keys.select { |feature_key| features_hash[feature_key] }
|
40
|
+
features.sort.map(&:to_sym)
|
41
|
+
end
|
42
|
+
private :get_active_features_from_file
|
43
|
+
|
44
|
+
##
|
45
|
+
# Returns list of inactive features
|
46
|
+
#
|
47
|
+
# @return Array<Symbol>
|
48
|
+
#
|
49
|
+
def inactive_features
|
50
|
+
get_inactive_features_from_file
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Return a list of inactive features read from the config file
|
55
|
+
#
|
56
|
+
# @return Array<Symbol>
|
57
|
+
#
|
58
|
+
def get_inactive_features_from_file
|
59
|
+
features_hash = read_and_parse_file_data
|
60
|
+
features = features_hash.keys.select { |feature_key| !features_hash[feature_key] }
|
61
|
+
features.sort.map(&:to_sym)
|
62
|
+
end
|
63
|
+
private :get_inactive_features_from_file
|
64
|
+
|
65
|
+
##
|
66
|
+
# Read and parses the feature config file
|
67
|
+
#
|
68
|
+
# @return Hash (with :feature => true/false meaning active/inactive)
|
69
|
+
#
|
70
|
+
def read_and_parse_file_data
|
71
|
+
raw_data = File.read(@yaml_file_name)
|
72
|
+
data = YAML.load(raw_data)
|
73
|
+
if !data.is_a?(Hash) or !data.has_key?('features')
|
74
|
+
raise ArgumentError, "content of #{@yaml_file_name} does not contain proper config"
|
75
|
+
end
|
76
|
+
data['features']
|
77
|
+
end
|
78
|
+
private :read_and_parse_file_data
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Feature::Repository::AbstractRepository do
|
4
|
+
it "should raise error on creating a new instance" do
|
5
|
+
lambda do
|
6
|
+
Feature::Repository::AbstractRepository.new
|
7
|
+
end.should raise_error("abstract class Feature::Repository::AbstractRepository!")
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Feature do
|
4
|
+
context "without FeatureRepository" do
|
5
|
+
it "should raise an exception when calling active?" do
|
6
|
+
lambda do
|
7
|
+
Feature.active?(:feature_a)
|
8
|
+
end.should raise_error("Feature is missing Repository for obtaining feature lists")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise an exception when calling inactive?" do
|
12
|
+
lambda do
|
13
|
+
Feature.inactive?(:feature_a)
|
14
|
+
end.should raise_error("Feature is missing Repository for obtaining feature lists")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should raise an exception when calling with" do
|
18
|
+
lambda do
|
19
|
+
Feature.with(:feature_a) do
|
20
|
+
end
|
21
|
+
end.should raise_error("Feature is missing Repository for obtaining feature lists")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise an exception when calling without" do
|
25
|
+
lambda do
|
26
|
+
Feature.without(:feature_a) do
|
27
|
+
end
|
28
|
+
end.should raise_error("Feature is missing Repository for obtaining feature lists")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "setting Repository" do
|
33
|
+
before(:each) do
|
34
|
+
@repository = Feature::Repository::SimpleRepository.new
|
35
|
+
Feature.set_repository @repository
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an exception when add repository with wrong class" do
|
39
|
+
lambda do
|
40
|
+
Feature.set_repository("not a repository")
|
41
|
+
end.should raise_error(ArgumentError, "given argument is not a repository")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should set a feature repository" do
|
45
|
+
lambda do
|
46
|
+
Feature.active?(:feature_a)
|
47
|
+
end.should_not raise_error
|
48
|
+
|
49
|
+
lambda do
|
50
|
+
Feature.inactive?(:feature_a)
|
51
|
+
end.should_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should get active features from repository once" do
|
55
|
+
@repository.add_active_feature(:feature_a)
|
56
|
+
Feature.active?(:feature_a).should be_false
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should get inactive features from repository once" do
|
60
|
+
@repository.add_inactive_feature(:feature_a)
|
61
|
+
Feature.inactive?(:feature_a).should be_false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "refresh features" do
|
66
|
+
before(:each) do
|
67
|
+
@repository = Feature::Repository::SimpleRepository.new
|
68
|
+
Feature.set_repository @repository
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should refresh active feature lists from repository" do
|
72
|
+
@repository.add_active_feature(:feature_a)
|
73
|
+
Feature.refresh!
|
74
|
+
Feature.active?(:feature_a).should be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should refresh inactive feature lists from repository" do
|
78
|
+
@repository.add_inactive_feature(:feature_a)
|
79
|
+
Feature.refresh!
|
80
|
+
Feature.inactive?(:feature_a).should be_true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "request features" do
|
85
|
+
before(:each) do
|
86
|
+
repository = Feature::Repository::SimpleRepository.new
|
87
|
+
repository.add_active_feature :feature_active
|
88
|
+
repository.add_inactive_feature :feature_inactive
|
89
|
+
Feature.set_repository repository
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should affirm active feature is active" do
|
93
|
+
Feature.active?(:feature_active).should be_true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should not affirm active feature is inactive" do
|
97
|
+
Feature.inactive?(:feature_active).should be_false
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should affirm inactive feature is inactive" do
|
101
|
+
Feature.inactive?(:feature_inactive).should be_true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should not affirm inactive feature is active" do
|
105
|
+
Feature.active?(:feature_inactive).should be_false
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should call block with active feature in active list" do
|
109
|
+
reached = false
|
110
|
+
|
111
|
+
Feature.with(:feature_active) do
|
112
|
+
reached = true
|
113
|
+
end
|
114
|
+
|
115
|
+
reached.should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not call block with active feature not in active list" do
|
119
|
+
reached = false
|
120
|
+
|
121
|
+
Feature.with(:feature_inactive) do
|
122
|
+
reached = true
|
123
|
+
end
|
124
|
+
|
125
|
+
reached.should be_false
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should raise exception when no block given to with" do
|
129
|
+
lambda do
|
130
|
+
Feature.with(:feature_active)
|
131
|
+
end.should raise_error(ArgumentError, "no block given to with")
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should call block without inactive feature in inactive list" do
|
135
|
+
reached = false
|
136
|
+
|
137
|
+
Feature.without(:feature_inactive) do
|
138
|
+
reached = true
|
139
|
+
end
|
140
|
+
|
141
|
+
reached.should be_true
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not call block without inactive feature in inactive list" do
|
145
|
+
reached = false
|
146
|
+
|
147
|
+
Feature.without(:feature_active) do
|
148
|
+
reached = true
|
149
|
+
end
|
150
|
+
|
151
|
+
reached.should be_false
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should raise exception when no block given to without" do
|
155
|
+
lambda do
|
156
|
+
Feature.without(:feature_inactive)
|
157
|
+
end.should raise_error(ArgumentError, "no block given to without")
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Feature::Repository
|
4
|
+
|
5
|
+
describe Feature::Repository::SimpleRepository do
|
6
|
+
before(:each) do
|
7
|
+
@repository = SimpleRepository.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have no active features after initialization" do
|
11
|
+
@repository.active_features.should == []
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have no inactive features after initialization" do
|
15
|
+
@repository.inactive_features.should == []
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should add an active feature" do
|
19
|
+
@repository.add_active_feature :feature_a
|
20
|
+
@repository.active_features.should == [:feature_a]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should raise an exception when adding not a symbol as active feature" do
|
24
|
+
lambda do
|
25
|
+
@repository.add_active_feature 'feature_a'
|
26
|
+
end.should raise_error(ArgumentError, "given feature feature_a is not a symbol")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an exception when adding a active feature already added as active" do
|
30
|
+
@repository.add_active_feature :feature_a
|
31
|
+
lambda do
|
32
|
+
@repository.add_active_feature :feature_a
|
33
|
+
end.should raise_error(ArgumentError, "feature :feature_a already added to list of active features")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an exception when adding a active feature already added as inactive" do
|
37
|
+
@repository.add_inactive_feature :feature_a
|
38
|
+
lambda do
|
39
|
+
@repository.add_active_feature :feature_a
|
40
|
+
end.should raise_error(ArgumentError, "feature :feature_a already added to list of inactive features")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should add an inactive feature" do
|
44
|
+
@repository.add_inactive_feature :feature_a
|
45
|
+
@repository.inactive_features.should == [:feature_a]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise an exception when adding not a symbol as inactive feature" do
|
49
|
+
lambda do
|
50
|
+
@repository.add_inactive_feature 'feature_a'
|
51
|
+
end.should raise_error(ArgumentError, "given feature feature_a is not a symbol")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise an exception when adding a inactive feature already added as inactive" do
|
55
|
+
@repository.add_inactive_feature :feature_a
|
56
|
+
lambda do
|
57
|
+
@repository.add_inactive_feature :feature_a
|
58
|
+
end.should raise_error(ArgumentError, "feature :feature_a already added to list of inactive features")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should raise an exception when adding a inactive feature already added as active" do
|
62
|
+
@repository.add_active_feature :feature_a
|
63
|
+
lambda do
|
64
|
+
@repository.add_inactive_feature :feature_a
|
65
|
+
end.should raise_error(ArgumentError, "feature :feature_a already added to list of active features")
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
include Feature::Repository
|
5
|
+
|
6
|
+
describe Feature::Repository::YamlRepository do
|
7
|
+
context "proper config file" do
|
8
|
+
before(:each) do
|
9
|
+
@filename = Tempfile.new(['feature_config', '.yaml']).path
|
10
|
+
fp = File.new(@filename, 'w')
|
11
|
+
fp.write <<"EOF";
|
12
|
+
features:
|
13
|
+
feature_a_active: true
|
14
|
+
feature_b_active: true
|
15
|
+
feature_c_inactive: false
|
16
|
+
feature_d_inactive: false
|
17
|
+
EOF
|
18
|
+
fp.close
|
19
|
+
|
20
|
+
@repo = YamlRepository.new(@filename)
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:each) do
|
24
|
+
File.delete(@filename)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should read active features from a config file" do
|
28
|
+
@repo.active_features.should == [:feature_a_active, :feature_b_active]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should read inactive features from a config file" do
|
32
|
+
@repo.inactive_features.should == [:feature_c_inactive, :feature_d_inactive]
|
33
|
+
end
|
34
|
+
|
35
|
+
context "re-read config file" do
|
36
|
+
before(:each) do
|
37
|
+
fp = File.new(@filename, 'w')
|
38
|
+
fp.write <<"EOF";
|
39
|
+
features:
|
40
|
+
feature_a_active: true
|
41
|
+
feature_c_inactive: false
|
42
|
+
EOF
|
43
|
+
fp.close
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should read active features new on each request" do
|
47
|
+
@repo.active_features.should == [:feature_a_active]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should read inactive features new on each request" do
|
51
|
+
@repo.inactive_features.should == [:feature_c_inactive]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should raise exception on no file found" do
|
57
|
+
repo = YamlRepository.new("/this/file/should/not/exist")
|
58
|
+
lambda do
|
59
|
+
repo.active_features
|
60
|
+
end.should raise_error(Errno::ENOENT, "No such file or directory - /this/file/should/not/exist")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should raise exception on invalid yaml" do
|
64
|
+
@filename = Tempfile.new(['feature_config', '.yaml']).path
|
65
|
+
fp = File.new(@filename, 'w')
|
66
|
+
fp.write "this is not valid feature config"
|
67
|
+
fp.close
|
68
|
+
|
69
|
+
repo = YamlRepository.new(@filename)
|
70
|
+
lambda do
|
71
|
+
repo.active_features
|
72
|
+
end.should raise_error(ArgumentError, "content of #{@filename} does not contain proper config")
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: feature
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Markus Gerdes
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-11-22 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email: github@mgsnova.de
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- lib/feature.rb
|
32
|
+
- lib/feature/repository/simple_repository.rb
|
33
|
+
- lib/feature/repository/abstract_repository.rb
|
34
|
+
- lib/feature/repository/yaml_repository.rb
|
35
|
+
- lib/feature/repository.rb
|
36
|
+
- spec/feature/simple_repository_spec.rb
|
37
|
+
- spec/feature/yaml_repository_spec.rb
|
38
|
+
- spec/feature/abstract_repository_spec.rb
|
39
|
+
- spec/feature/feature_spec.rb
|
40
|
+
- spec/spec_helper.rb
|
41
|
+
- Rakefile
|
42
|
+
- Gemfile
|
43
|
+
- README.md
|
44
|
+
- CHANGELOG.md
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/mgsnova/feature
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Feature Toggle library for ruby
|
79
|
+
test_files: []
|
80
|
+
|