feature_flipper 1.3.0 → 2.0.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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/README.md +61 -84
- data/Rakefile +4 -8
- data/examples/dynamic_states.rb +24 -9
- data/examples/features.rb +5 -5
- data/examples/static_states.rb +2 -2
- data/feature_flipper.gemspec +23 -0
- data/lib/feature_flipper/config.rb +28 -30
- data/lib/feature_flipper/show.rb +3 -3
- metadata +60 -46
- data/lib/feature_flipper/version.rb +0 -3
- data/test/feature_flipper_test.rb +0 -126
- data/test/features.rb +0 -20
- data/test/features_dsl.rb +0 -23
- data/test/test_helper.rb +0 -38
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1c3632c7d610b676c1221bcfa84bedd1bc95847e
|
4
|
+
data.tar.gz: 449a0a967eba941e1fad80ded4d69d142fe2d0a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6420b8810495627b15340ae99042546f4887a8ee6e0427178ea75c23b2ccdfdda816ec26f8307cf3513e40fa74eeafaa6a08392310ac91bde215b672740c5eef
|
7
|
+
data.tar.gz: 6da97940ac703df35ca10d8f5c923c67c1aa1c2088abe9368e3aa41c9d473ed774c8a74c154955808e1dc2b2903f5930c34939511822a3ed1fba92ad3692a9b8
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
FeatureFlipper
|
2
2
|
==============
|
3
3
|
|
4
|
+
[](https://rubygems.org/gems/feature_flipper)
|
5
|
+
[](https://travis-ci.org/theflow/feature_flipper)
|
6
|
+
|
4
7
|
FeatureFlipper is a simple library that allows you to restrict certain blocks
|
5
8
|
of code to certain environments. This is mainly useful in projects where
|
6
9
|
you deploy your application from HEAD and don't use branches.
|
7
10
|
|
8
|
-
Read more about
|
9
|
-
[
|
11
|
+
Read more about using feature flips here:
|
12
|
+
[Feature Toggles](http://martinfowler.com/articles/feature-toggles.html).
|
10
13
|
|
11
14
|
Install
|
12
15
|
-------
|
@@ -18,35 +21,39 @@ FeatureFlipper is packaged as a gem:
|
|
18
21
|
In your project you have to configure the path to the app specific
|
19
22
|
configuration file after requiring FeatureFlipper:
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
```ruby
|
25
|
+
require 'feature_flipper'
|
26
|
+
FeatureFlipper::Config.path_to_file = "#{Rails.root}/config/features.rb"
|
27
|
+
```
|
23
28
|
|
24
29
|
Example config file
|
25
30
|
-------------------
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
```ruby
|
33
|
+
FeatureFlipper.features do
|
34
|
+
in_state :development do
|
35
|
+
feature :rating_game, :description => 'play a game to get recommendations'
|
36
|
+
end
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
in_state :live do
|
39
|
+
feature :city_feed, :description => 'stream of content for each city'
|
40
|
+
end
|
41
|
+
end
|
36
42
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
43
|
+
FeatureFlipper.states do
|
44
|
+
state :development, ['development', 'test'].include?(Rails.env)
|
45
|
+
state :live, true
|
46
|
+
end
|
47
|
+
```
|
41
48
|
|
42
49
|
This is your complete features.rb config file. In the example there are two
|
43
|
-
states: `:development` is active on development
|
50
|
+
states: `:development` is active on development servers and `:live` is always active
|
44
51
|
(this is the last state a feature goes through).
|
45
52
|
|
46
53
|
The feature `:rating_game` is still in development and not shown on the
|
47
54
|
production site. The feature `:city_feed` is done and already enabled
|
48
55
|
everywhere. You transition features between states by just moving the line to
|
49
|
-
the new state block.
|
56
|
+
the new state block and deploying your code.
|
50
57
|
|
51
58
|
You can take a look at the `static_states.rb` in the examples folder to
|
52
59
|
see this in detail.
|
@@ -61,7 +68,7 @@ FeatureFlipper cares about:
|
|
61
68
|
* features
|
62
69
|
|
63
70
|
You first define multiple 'states' which normally depend on the environment
|
64
|
-
(for example: the state 'development' is only active on development
|
71
|
+
(for example: the state 'development' is only active on development servers).
|
65
72
|
After that you add 'features' which correspond to logical chunks of work in
|
66
73
|
your project. These features then move through the different states
|
67
74
|
as they get developed (for example: :development -> :staging -> :live).
|
@@ -73,18 +80,23 @@ more detailed description, a ticket number, a date when it was started, etc.
|
|
73
80
|
Features are always defined in a state, you cannot define a feature which
|
74
81
|
doesn't belong to a state.
|
75
82
|
|
76
|
-
|
77
|
-
|
78
|
-
|
83
|
+
```ruby
|
84
|
+
in_state :development do
|
85
|
+
feature :rating_game, :description => 'play a game to get recommendations'
|
86
|
+
end
|
87
|
+
```
|
79
88
|
|
80
89
|
### Defining states
|
81
90
|
|
82
91
|
A state is just a name and a boolean check. The check needs to evaluate to
|
83
92
|
`true` when it is active. For a Rails app you can just use environments:
|
84
93
|
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
```ruby
|
95
|
+
FeatureFlipper.states do
|
96
|
+
state :development, ['development', 'test'].include?(Rails.env)
|
97
|
+
state :staging, ['staging', development', 'test'].include?(Rails.env)
|
98
|
+
end
|
99
|
+
```
|
88
100
|
|
89
101
|
Usage
|
90
102
|
-----
|
@@ -92,21 +104,16 @@ Usage
|
|
92
104
|
In your code you then use the `show_feature?` method to branch depending on
|
93
105
|
wether a feature is active or not:
|
94
106
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
107
|
+
```ruby
|
108
|
+
if show_feature?(:rating_game)
|
109
|
+
# new code
|
110
|
+
else
|
111
|
+
# old code
|
112
|
+
end
|
113
|
+
```
|
100
114
|
|
101
115
|
The `show_feature?` method is defined on Object, so you can use it everywhere.
|
102
116
|
|
103
|
-
Cleaning up
|
104
|
-
-----------
|
105
|
-
|
106
|
-
The drawback of this approach is that your code can get quite ugly with all
|
107
|
-
these if/else branches. So you have to be strict about removing features
|
108
|
-
(we call it de-featurizing) after they have gone live.
|
109
|
-
|
110
117
|
Dynamic feature groups
|
111
118
|
----------------------
|
112
119
|
|
@@ -117,41 +124,20 @@ employees only or to a private beta group, etc.
|
|
117
124
|
|
118
125
|
### Defining dynamic states
|
119
126
|
|
120
|
-
A dynamic state is defined
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
The feature group is set globally and is active for the whole thread.
|
136
|
-
In Rails you would define a before_filter like this:
|
137
|
-
|
138
|
-
class ApplicationController < ActionController::Base
|
139
|
-
before_filter :set_active_feature_group
|
140
|
-
|
141
|
-
def set_active_feature_group
|
142
|
-
# we need to reset the feature group in each request,
|
143
|
-
# otherwise it's also active for the following requests.
|
144
|
-
FeatureFlipper.reset_active_feature_groups
|
145
|
-
|
146
|
-
if logged_in? && current_user.employee?
|
147
|
-
FeatureFlipper.active_feature_groups << :employees
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
Don't forget to reset the feature group, without it the feature group
|
152
|
-
is active forever. The condition if someone is in a feature group
|
153
|
-
can be anything: You can store it in the database, in Redis,
|
154
|
-
look at request parameters, based on the current time, etc.
|
127
|
+
A dynamic state is defined using a Proc:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
FeatureFlipper.states do
|
131
|
+
state :development, ['development', 'test'].include?(Rails.env)
|
132
|
+
state :employees, Proc.new { |feature_name| respond_to?(:current_user, true) && current_user.employee? }
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
The Proc get's evaluated in the context of where you call the `show_feature?`
|
137
|
+
method from, so it depends on your app what you can do there. In a typical Rails
|
138
|
+
app you could do checks on the current user, as shown above. This way the condition
|
139
|
+
if someone should see a feature or not can be anything: You can store it in the
|
140
|
+
database, in Redis, look at request parameters, based on the current time, etc.
|
155
141
|
|
156
142
|
Take a look at `dynamic_states.rb` in the examples folder to see this
|
157
143
|
in detail.
|
@@ -159,16 +145,7 @@ in detail.
|
|
159
145
|
Meta
|
160
146
|
----
|
161
147
|
|
162
|
-
*
|
163
|
-
*
|
164
|
-
* Bugs: <http://github.com/qype/feature_flipper/issues>
|
165
|
-
|
166
|
-
This project uses [Semantic Versioning][sv].
|
167
|
-
|
168
|
-
Author
|
169
|
-
------
|
170
|
-
|
171
|
-
Florian Munz, Qype GmbH - florian@qype.com
|
172
|
-
|
148
|
+
* Home: <https://github.com/theflow/feature_flipper>
|
149
|
+
* Bugs: <https://github.com/theflow/feature_flipper/issues>
|
173
150
|
|
174
|
-
[
|
151
|
+
This project uses [Semantic Versioning](http://semver.org/).
|
data/Rakefile
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
require 'rake'
|
2
1
|
require 'rake/testtask'
|
3
2
|
|
4
|
-
desc 'Default: run unit tests'
|
5
|
-
task :default => :test
|
6
|
-
|
7
|
-
desc 'run the feature_flipper tests'
|
8
3
|
Rake::TestTask.new(:test) do |t|
|
9
|
-
t.libs << 'lib'
|
10
4
|
t.libs << 'test'
|
11
|
-
t.
|
12
|
-
t.
|
5
|
+
t.libs << 'lib'
|
6
|
+
t.test_files = FileList['test/**/*_test.rb']
|
13
7
|
end
|
8
|
+
|
9
|
+
task :default => :test
|
data/examples/dynamic_states.rb
CHANGED
@@ -1,16 +1,30 @@
|
|
1
1
|
# Setup
|
2
2
|
#
|
3
3
|
|
4
|
-
# just need this to make it
|
4
|
+
# just need this to make it works from within the library
|
5
5
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
6
6
|
|
7
|
-
#
|
7
|
+
# stub production Rails environment
|
8
8
|
module Rails
|
9
9
|
def self.env
|
10
10
|
'production'
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
# stub current_user method
|
15
|
+
class User
|
16
|
+
def initialize(employee)
|
17
|
+
@employee = employee
|
18
|
+
end
|
19
|
+
|
20
|
+
def employee?
|
21
|
+
@employee == true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def current_user
|
26
|
+
@current_user
|
27
|
+
end
|
14
28
|
|
15
29
|
# Configuration
|
16
30
|
#
|
@@ -18,7 +32,7 @@ end
|
|
18
32
|
require 'feature_flipper'
|
19
33
|
|
20
34
|
# set the path to your app specific config file
|
21
|
-
FeatureFlipper::Config.path_to_file =
|
35
|
+
FeatureFlipper::Config.path_to_file = File.expand_path('features.rb', File.dirname(__FILE__))
|
22
36
|
|
23
37
|
|
24
38
|
# Usage
|
@@ -26,7 +40,10 @@ FeatureFlipper::Config.path_to_file = "features.rb"
|
|
26
40
|
|
27
41
|
puts "=== first example:"
|
28
42
|
|
29
|
-
#
|
43
|
+
# mock current user to not be a employee
|
44
|
+
@current_user = User.new(false)
|
45
|
+
|
46
|
+
# current user it not an employee and we are on prod, so no new badges
|
30
47
|
if show_feature?(:badges)
|
31
48
|
puts "shiny new badges not live on prod yet"
|
32
49
|
else
|
@@ -35,13 +52,11 @@ end
|
|
35
52
|
|
36
53
|
puts "\n=== second example:"
|
37
54
|
|
38
|
-
#
|
39
|
-
|
40
|
-
FeatureFlipper.reset_active_feature_groups
|
41
|
-
FeatureFlipper.active_feature_groups << :employees
|
55
|
+
# mock current user to be a employee
|
56
|
+
@current_user = User.new(true)
|
42
57
|
|
43
58
|
if show_feature?(:badges)
|
44
|
-
puts "shiny new badges for this
|
59
|
+
puts "shiny new badges for this employee"
|
45
60
|
else
|
46
61
|
puts "no new badges"
|
47
62
|
end
|
data/examples/features.rb
CHANGED
@@ -17,8 +17,8 @@ FeatureFlipper.features do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
FeatureFlipper
|
21
|
-
:development
|
22
|
-
:employees
|
23
|
-
:live
|
24
|
-
|
20
|
+
FeatureFlipper.states do
|
21
|
+
state :development, ['development', 'test'].include?(Rails.env)
|
22
|
+
state :employees, Proc.new { |feature_name| respond_to?(:current_user, true) && current_user.employee? }
|
23
|
+
state :live, true
|
24
|
+
end
|
data/examples/static_states.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Setup
|
2
2
|
#
|
3
3
|
|
4
|
-
# just need this to make it
|
4
|
+
# just need this to make it works from within the library
|
5
5
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
6
6
|
|
7
7
|
# fake production Rails environment
|
@@ -18,7 +18,7 @@ end
|
|
18
18
|
require 'feature_flipper'
|
19
19
|
|
20
20
|
# set the path to your app specific config file
|
21
|
-
FeatureFlipper::Config.path_to_file =
|
21
|
+
FeatureFlipper::Config.path_to_file = File.expand_path('features.rb', File.dirname(__FILE__))
|
22
22
|
|
23
23
|
|
24
24
|
# Usage
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'feature_flipper'
|
3
|
+
s.version = '2.0.0'
|
4
|
+
s.authors = ['Florian Munz']
|
5
|
+
s.email = 'surf@theflow.de'
|
6
|
+
|
7
|
+
s.summary = 'FeatureFlipper helps you flipping features'
|
8
|
+
s.description = <<desc
|
9
|
+
FeatureFlipper is a simple library that allows you to restrict certain blocks
|
10
|
+
of code to certain environments. This is mainly useful in projects where
|
11
|
+
you deploy your application from HEAD and don't use branches.
|
12
|
+
desc
|
13
|
+
s.homepage = 'http://github.com/theflow/feature_flipper'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'minitest', "~> 5.0"
|
23
|
+
end
|
@@ -4,7 +4,7 @@ module FeatureFlipper
|
|
4
4
|
@states = {}
|
5
5
|
|
6
6
|
def self.path_to_file
|
7
|
-
@path_to_file
|
7
|
+
@path_to_file
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.path_to_file=(path_to_file)
|
@@ -19,6 +19,9 @@ module FeatureFlipper
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.reload_config
|
22
|
+
@features = {}
|
23
|
+
@states = {}
|
24
|
+
|
22
25
|
@config_loaded = false
|
23
26
|
end
|
24
27
|
|
@@ -38,44 +41,37 @@ module FeatureFlipper
|
|
38
41
|
@states = states
|
39
42
|
end
|
40
43
|
|
41
|
-
def self.active_features
|
42
|
-
features.keys.select { |feature| is_active?(feature) }
|
43
|
-
end
|
44
|
-
|
45
44
|
def self.get_state(feature_name)
|
46
45
|
feature = features[feature_name]
|
47
46
|
feature ? feature[:state] : nil
|
48
47
|
end
|
49
48
|
|
50
|
-
def self.active_state?(state)
|
51
|
-
|
52
|
-
if
|
53
|
-
if
|
54
|
-
|
49
|
+
def self.active_state?(state, feature_name, context = nil)
|
50
|
+
condition = states[state]
|
51
|
+
if condition.is_a?(Proc)
|
52
|
+
if context
|
53
|
+
context.instance_exec(feature_name, &condition)
|
55
54
|
else
|
56
|
-
|
55
|
+
condition.call(feature_name) == true
|
57
56
|
end
|
58
|
-
(FeatureFlipper.active_feature_groups.include?(group)) || (states[required_state] == true)
|
59
57
|
else
|
60
|
-
|
58
|
+
condition == true
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
|
-
def self.is_active?(feature_name)
|
62
|
+
def self.is_active?(feature_name, context = nil)
|
65
63
|
ensure_config_is_loaded
|
66
64
|
|
67
65
|
state = get_state(feature_name)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
state == true
|
74
|
-
end
|
66
|
+
active_state?(state, feature_name, context)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.active_features(context = nil)
|
70
|
+
self.features.collect { |key, value| self.is_active?(key, context) ? key : nil }.compact
|
75
71
|
end
|
76
72
|
end
|
77
73
|
|
78
|
-
class
|
74
|
+
class FeatureMapper
|
79
75
|
def initialize(state)
|
80
76
|
@state = state
|
81
77
|
end
|
@@ -85,21 +81,23 @@ module FeatureFlipper
|
|
85
81
|
end
|
86
82
|
end
|
87
83
|
|
88
|
-
class
|
84
|
+
class FeaturesMapper
|
89
85
|
def in_state(state, &block)
|
90
|
-
|
86
|
+
FeatureMapper.new(state).instance_eval(&block)
|
91
87
|
end
|
92
88
|
end
|
93
89
|
|
94
|
-
|
95
|
-
|
90
|
+
class StatesMapper
|
91
|
+
def state(name, condition = false)
|
92
|
+
FeatureFlipper::Config.states[name] = condition
|
93
|
+
end
|
96
94
|
end
|
97
95
|
|
98
|
-
def self.
|
99
|
-
|
96
|
+
def self.features(&block)
|
97
|
+
FeaturesMapper.new.instance_eval(&block)
|
100
98
|
end
|
101
99
|
|
102
|
-
def self.
|
103
|
-
|
100
|
+
def self.states(&block)
|
101
|
+
StatesMapper.new.instance_eval(&block)
|
104
102
|
end
|
105
103
|
end
|
data/lib/feature_flipper/show.rb
CHANGED
@@ -7,11 +7,11 @@ module FeatureFlipper
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def show_feature?(feature_name)
|
10
|
-
FeatureFlipper::Config.is_active?(feature_name)
|
10
|
+
FeatureFlipper::Config.is_active?(feature_name, self)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def active_features
|
14
|
-
FeatureFlipper::Config.active_features
|
14
|
+
FeatureFlipper::Config.active_features(self)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
metadata
CHANGED
@@ -1,73 +1,87 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: feature_flipper
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 1.3.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Florian Munz
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
date: 2017-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
17
41
|
description: |
|
18
42
|
FeatureFlipper is a simple library that allows you to restrict certain blocks
|
19
43
|
of code to certain environments. This is mainly useful in projects where
|
20
44
|
you deploy your application from HEAD and don't use branches.
|
21
|
-
|
22
45
|
email: surf@theflow.de
|
23
46
|
executables: []
|
24
|
-
|
25
47
|
extensions: []
|
26
|
-
|
27
48
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
49
|
+
files:
|
50
|
+
- .gitignore
|
51
|
+
- .travis.yml
|
52
|
+
- Gemfile
|
53
|
+
- LICENSE
|
30
54
|
- README.md
|
31
55
|
- Rakefile
|
32
|
-
- LICENSE
|
33
|
-
- lib/feature_flipper/config.rb
|
34
|
-
- lib/feature_flipper/show.rb
|
35
|
-
- lib/feature_flipper/version.rb
|
36
|
-
- lib/feature_flipper.rb
|
37
|
-
- test/feature_flipper_test.rb
|
38
|
-
- test/features.rb
|
39
|
-
- test/features_dsl.rb
|
40
|
-
- test/test_helper.rb
|
41
56
|
- examples/dynamic_states.rb
|
42
57
|
- examples/features.rb
|
43
58
|
- examples/static_states.rb
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
59
|
+
- feature_flipper.gemspec
|
60
|
+
- lib/feature_flipper.rb
|
61
|
+
- lib/feature_flipper/config.rb
|
62
|
+
- lib/feature_flipper/show.rb
|
63
|
+
homepage: http://github.com/theflow/feature_flipper
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
48
67
|
post_install_message:
|
49
68
|
rdoc_options: []
|
50
|
-
|
51
|
-
require_paths:
|
69
|
+
require_paths:
|
52
70
|
- lib
|
53
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: "0"
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
65
81
|
requirements: []
|
66
|
-
|
67
82
|
rubyforge_project:
|
68
|
-
rubygems_version:
|
83
|
+
rubygems_version: 2.0.14
|
69
84
|
signing_key:
|
70
|
-
specification_version:
|
85
|
+
specification_version: 4
|
71
86
|
summary: FeatureFlipper helps you flipping features
|
72
87
|
test_files: []
|
73
|
-
|
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
context 'hash based FeatureFlipper' do
|
4
|
-
setup do
|
5
|
-
FeatureFlipper::Config.path_to_file = 'features.rb'
|
6
|
-
FeatureFlipper::Config.reload_config
|
7
|
-
end
|
8
|
-
|
9
|
-
test 'should show enabled features' do
|
10
|
-
assert show_feature?(:live_feature)
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'should not show disabled features' do
|
14
|
-
assert !show_feature?(:disabled_feature)
|
15
|
-
end
|
16
|
-
|
17
|
-
test 'should not show a feature when on a higher environment' do
|
18
|
-
Rails.stubs(:env).returns('production')
|
19
|
-
assert !show_feature?(:dev_feature)
|
20
|
-
end
|
21
|
-
|
22
|
-
test 'show feature should work with booleans' do
|
23
|
-
assert show_feature?(:boolean_feature)
|
24
|
-
end
|
25
|
-
|
26
|
-
test 'show feature should work with procs' do
|
27
|
-
assert show_feature?(:proc_feature)
|
28
|
-
end
|
29
|
-
|
30
|
-
test 'should be able to get features' do
|
31
|
-
FeatureFlipper::Config.ensure_config_is_loaded
|
32
|
-
all_features = FeatureFlipper::Config.features
|
33
|
-
|
34
|
-
assert_not_nil all_features
|
35
|
-
assert all_features.is_a?(Hash)
|
36
|
-
assert_equal :dev, all_features[:dev_feature][:state]
|
37
|
-
assert_equal 'dev feature', all_features[:dev_feature][:description]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'DSL based FeatureFlipper' do
|
42
|
-
setup do
|
43
|
-
FeatureFlipper::Config.path_to_file = 'features_dsl.rb'
|
44
|
-
FeatureFlipper::Config.reload_config
|
45
|
-
end
|
46
|
-
|
47
|
-
test 'should show enabled features' do
|
48
|
-
assert show_feature?(:live_feature)
|
49
|
-
end
|
50
|
-
|
51
|
-
test 'should not show a feature when on a higher environment' do
|
52
|
-
Rails.stubs(:env).returns('production')
|
53
|
-
assert !show_feature?(:dev_feature)
|
54
|
-
end
|
55
|
-
|
56
|
-
test 'show feature should work with booleans' do
|
57
|
-
assert show_feature?(:boolean_feature)
|
58
|
-
end
|
59
|
-
|
60
|
-
test 'show feature should work with procs' do
|
61
|
-
assert show_feature?(:proc_feature)
|
62
|
-
end
|
63
|
-
|
64
|
-
test 'should be able to get features' do
|
65
|
-
FeatureFlipper::Config.ensure_config_is_loaded
|
66
|
-
all_features = FeatureFlipper::Config.features
|
67
|
-
|
68
|
-
assert_not_nil all_features
|
69
|
-
assert all_features.is_a?(Hash)
|
70
|
-
assert_equal :dev, all_features[:dev_feature][:state]
|
71
|
-
assert_equal 'dev feature', all_features[:dev_feature][:description]
|
72
|
-
end
|
73
|
-
|
74
|
-
test 'should be able to get active features' do
|
75
|
-
Rails.stubs(:env).returns('production')
|
76
|
-
FeatureFlipper::Config.ensure_config_is_loaded
|
77
|
-
active_features = FeatureFlipper::Config.active_features
|
78
|
-
|
79
|
-
assert_equal 3, active_features.size
|
80
|
-
assert active_features.include?(:live_feature)
|
81
|
-
assert active_features.include?(:boolean_feature)
|
82
|
-
assert active_features.include?(:proc_feature)
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
context 'dynamic feature groups' do
|
88
|
-
setup do
|
89
|
-
FeatureFlipper::Config.path_to_file = 'features.rb'
|
90
|
-
FeatureFlipper::Config.reload_config
|
91
|
-
FeatureFlipper.reset_active_feature_groups
|
92
|
-
end
|
93
|
-
|
94
|
-
test 'should show a beta feature to the feature group' do
|
95
|
-
Rails.stubs(:env).returns('production')
|
96
|
-
FeatureFlipper.active_feature_groups << :beta_users
|
97
|
-
|
98
|
-
assert show_feature?(:beta_feature_old)
|
99
|
-
assert show_feature?(:beta_feature_new)
|
100
|
-
end
|
101
|
-
|
102
|
-
test 'should not show a beta feature if not in the group' do
|
103
|
-
Rails.stubs(:env).returns('production')
|
104
|
-
FeatureFlipper.active_feature_groups << :different_feature_group
|
105
|
-
|
106
|
-
assert !show_feature?(:beta_feature_old)
|
107
|
-
assert !show_feature?(:beta_feature_new)
|
108
|
-
end
|
109
|
-
|
110
|
-
test 'should always show a beta feature on dev' do
|
111
|
-
Rails.stubs(:env).returns('development')
|
112
|
-
FeatureFlipper.active_feature_groups << nil
|
113
|
-
|
114
|
-
assert show_feature?(:beta_feature_old)
|
115
|
-
assert show_feature?(:beta_feature_new)
|
116
|
-
end
|
117
|
-
|
118
|
-
test 'can be in two feature groups at the same time' do
|
119
|
-
Rails.stubs(:env).returns('production')
|
120
|
-
FeatureFlipper.active_feature_groups << :beta_users
|
121
|
-
FeatureFlipper.active_feature_groups << :employees
|
122
|
-
|
123
|
-
assert show_feature?(:beta_feature_new)
|
124
|
-
assert show_feature?(:employee_feature)
|
125
|
-
end
|
126
|
-
end
|
data/test/features.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
FeatureFlipper::Config.features = {
|
2
|
-
:live_feature => { :state => :live },
|
3
|
-
:disabled_feature => { :state => :disabled },
|
4
|
-
:dev_feature => { :state => :dev, :description => 'dev feature' },
|
5
|
-
:boolean_feature => { :state => true },
|
6
|
-
:proc_feature => { :state => Proc.new { Date.today > Date.today - 84000 } },
|
7
|
-
:beta_feature_old => { :state => :beta_old },
|
8
|
-
:beta_feature_new => { :state => :beta_new },
|
9
|
-
:employee_feature => { :state => :employees }
|
10
|
-
}
|
11
|
-
|
12
|
-
|
13
|
-
FeatureFlipper::Config.states = {
|
14
|
-
:disabled => false,
|
15
|
-
:dev => ['development', 'test'].include?(Rails.env),
|
16
|
-
:beta_old => { :beta_users => :dev },
|
17
|
-
:beta_new => { :required_state => :dev, :feature_group => :beta_users },
|
18
|
-
:employees => { :required_state => :dev, :feature_group => :employees },
|
19
|
-
:live => true
|
20
|
-
}
|
data/test/features_dsl.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
FeatureFlipper.features do
|
2
|
-
in_state :dev do
|
3
|
-
feature :dev_feature, :description => 'dev feature'
|
4
|
-
end
|
5
|
-
|
6
|
-
in_state :live do
|
7
|
-
feature :live_feature
|
8
|
-
end
|
9
|
-
|
10
|
-
in_state true do
|
11
|
-
feature :boolean_feature
|
12
|
-
end
|
13
|
-
|
14
|
-
in_state Proc.new { Date.today > Date.today - 84000 } do
|
15
|
-
feature :proc_feature
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
FeatureFlipper::Config.states = {
|
21
|
-
:dev => ['development', 'test'].include?(Rails.env),
|
22
|
-
:live => true
|
23
|
-
}
|
data/test/test_helper.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rubygems'
|
3
|
-
|
4
|
-
require 'mocha'
|
5
|
-
|
6
|
-
##
|
7
|
-
# test/spec/mini 5
|
8
|
-
# http://gist.github.com/307649
|
9
|
-
# chris@ozmm.org
|
10
|
-
#
|
11
|
-
def context(*args, &block)
|
12
|
-
return super unless (name = args.first) && block
|
13
|
-
require 'test/unit'
|
14
|
-
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
15
|
-
def self.test(name, &block)
|
16
|
-
define_method("test_#{name.to_s.gsub(/\W/,'_')}", &block) if block
|
17
|
-
end
|
18
|
-
def self.xtest(*args) end
|
19
|
-
def self.context(*args, &block) instance_eval(&block) end
|
20
|
-
def self.setup(&block)
|
21
|
-
define_method(:setup) { self.class.setups.each { |s| instance_eval(&s) } }
|
22
|
-
setups << block
|
23
|
-
end
|
24
|
-
def self.setups; @setups ||= [] end
|
25
|
-
def self.teardown(&block) define_method(:teardown, &block) end
|
26
|
-
end
|
27
|
-
(class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
|
28
|
-
klass.class_eval &block
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
module Rails
|
33
|
-
def self.env
|
34
|
-
'test'
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
require 'feature_flipper'
|