flip 0.0.4 → 0.1.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.
- data/Gemfile +1 -1
- data/README.md +49 -18
- data/app/assets/stylesheets/flip.css +30 -24
- data/app/views/flip/features/index.html.erb +51 -49
- data/lib/flip/version.rb +1 -1
- metadata +42 -21
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
gemspec
|
data/README.md
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
Flip — flip your features
|
2
2
|
================
|
3
3
|
|
4
|
-
|
4
|
+
**Flip** provides a declarative, layered way of enabling and disabling application functionality at run-time.
|
5
5
|
|
6
|
-
|
6
|
+
This gem optimizes for:
|
7
7
|
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
8
|
+
* developer ease-of-use,
|
9
|
+
* visibility and control for other stakeholders (like marketing); and
|
10
|
+
* run-time performance
|
11
11
|
|
12
|
-
|
12
|
+
There are three layers of strategies per feature:
|
13
|
+
|
14
|
+
* default
|
15
|
+
* database, to flip features site-wide for all users
|
16
|
+
* cookie, to flip features just for you (or someone else)
|
17
|
+
|
18
|
+
There is also a configurable system-wide default - !Rails.env.production?` works nicely.
|
19
|
+
|
20
|
+
Flip has a dashboard UI that's easy to understand and use.
|
21
|
+
|
22
|
+

|
13
23
|
|
14
24
|
Install
|
15
25
|
-------
|
16
26
|
|
17
|
-
Note: the alpha version number indicates Flip is currently being extracted from its host application. **The process described here is currently fictional.** But it does have a happy ending.
|
18
|
-
|
19
27
|
**Rails 3.0 and 3.1+**
|
20
28
|
|
21
29
|
# Gemfile
|
@@ -27,8 +35,6 @@ Note: the alpha version number indicates Flip is currently being extracted from
|
|
27
35
|
# Run the migration
|
28
36
|
> rake db:migrate
|
29
37
|
|
30
|
-
# They lived happily ever after.
|
31
|
-
|
32
38
|
|
33
39
|
Declaring Features
|
34
40
|
------------------
|
@@ -64,7 +70,7 @@ Declaring Features
|
|
64
70
|
Checking Features
|
65
71
|
-----------------
|
66
72
|
|
67
|
-
|
73
|
+
`Flip.on?` or the dynamic predicate methods are used to check feature state:
|
68
74
|
|
69
75
|
Flip.on? :world_domination # true
|
70
76
|
Flip.world_domination? # true
|
@@ -72,7 +78,7 @@ Feature status can be checked by any code using `on?` or using the dynamic predi
|
|
72
78
|
Flip.on? :shiny_things # false
|
73
79
|
Flip.shiny_things? # false
|
74
80
|
|
75
|
-
|
81
|
+
Views and controllers use the `feature?(key)` method:
|
76
82
|
|
77
83
|
<div>
|
78
84
|
<% if feature? :world_domination %>
|
@@ -98,15 +104,40 @@ The `Flip::ControllerFilters` module is mixed into the base `ApplicationControll
|
|
98
104
|
|
99
105
|
end
|
100
106
|
|
101
|
-
|
107
|
+
Dashboard
|
108
|
+
---------
|
109
|
+
|
110
|
+
The dashboard provides visibility and control over the features.
|
111
|
+
|
112
|
+
The gem includes some basic styles:
|
113
|
+
|
114
|
+
= content_for :stylesheets_head do
|
115
|
+
= stylesheet_link_tag "flip"
|
102
116
|
|
117
|
+
You probably don't want the dashboard to be public. Here's one way of implementing access control.
|
103
118
|
|
104
|
-
|
105
|
-
--------------
|
119
|
+
app/controllers/admin/features_controller.rb:
|
106
120
|
|
107
|
-
|
121
|
+
class Admin::FeaturesController < Flip::FeaturesController
|
122
|
+
before_filter :assert_authenticated_as_admin
|
123
|
+
end
|
124
|
+
|
125
|
+
app/controllers/admin/feature_strategies_controller.rb:
|
126
|
+
|
127
|
+
class Admin::FeatureStrategiesController < Flip::FeaturesController
|
128
|
+
before_filter :assert_authenticated_as_admin
|
129
|
+
end
|
130
|
+
|
131
|
+
routes.rb:
|
132
|
+
|
133
|
+
namespace :admin do
|
134
|
+
resources :features, only: [ :index ] do
|
135
|
+
resources :feature_strategies, only: [ :update, :destroy ]
|
136
|
+
end
|
137
|
+
end
|
108
138
|
|
139
|
+
mount Flip::Engine => "/admin/features"
|
109
140
|
|
110
141
|
----
|
111
|
-
Created by Paul Annesley
|
112
|
-
Copyright © 2011 Learnable Pty Ltd, [MIT Licence](http://www.opensource.org/licenses/mit-license.php).
|
142
|
+
Created by Paul Annesley
|
143
|
+
Copyright © 2011-2013 Learnable Pty Ltd, [MIT Licence](http://www.opensource.org/licenses/mit-license.php).
|
@@ -1,64 +1,70 @@
|
|
1
1
|
/* Flip */
|
2
2
|
|
3
3
|
.flip {
|
4
|
-
margin:
|
4
|
+
margin: 0;
|
5
|
+
}
|
6
|
+
|
7
|
+
.flip h1 {
|
8
|
+
color:#666666;
|
9
|
+
font-size: 229%;
|
10
|
+
line-height: 44.928px;
|
11
|
+
margin: 13.5px 0;
|
5
12
|
}
|
6
13
|
|
7
14
|
.flip th.name, .flip th.description, .flip th.status {
|
8
|
-
|
15
|
+
visibility: hidden;
|
9
16
|
}
|
10
17
|
|
11
18
|
.flip td.name {
|
12
|
-
|
13
|
-
|
19
|
+
font-family: Monaco, sans-serif;
|
20
|
+
font-weight: bold;
|
14
21
|
}
|
15
22
|
|
16
23
|
.flip td.name, .flip td.description {
|
17
|
-
|
24
|
+
vertical-align: top;
|
18
25
|
}
|
19
26
|
|
20
27
|
.flip th {
|
21
|
-
|
22
|
-
|
23
|
-
|
28
|
+
font-weight: normal;
|
29
|
+
text-align: left;
|
30
|
+
vertical-align: top;
|
24
31
|
}
|
25
32
|
|
26
33
|
.flip th .description {
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
font-weight: normal;
|
35
|
+
display: block;
|
36
|
+
font-size: 80%;
|
30
37
|
}
|
31
38
|
|
32
39
|
.flip th, .flip td {
|
33
|
-
|
34
|
-
|
35
|
-
|
40
|
+
padding: 5px 10px;
|
41
|
+
width: 160px;
|
42
|
+
height: 40px;
|
36
43
|
}
|
37
44
|
|
38
45
|
.flip td.off, .flip td.on, .flip td.pass {
|
39
|
-
|
40
|
-
|
46
|
+
text-align: center;
|
47
|
+
text-transform: capitalize;
|
41
48
|
}
|
42
49
|
|
43
50
|
.flip td.off {
|
44
|
-
|
51
|
+
background-color: #fbb;
|
45
52
|
}
|
46
53
|
|
47
54
|
.flip td.on {
|
48
|
-
|
55
|
+
background-color: #cfc;
|
49
56
|
}
|
50
57
|
|
51
58
|
.flip td.pass {
|
52
|
-
|
59
|
+
background-color: #eef;
|
53
60
|
}
|
54
61
|
|
55
62
|
.flip form {
|
56
|
-
|
63
|
+
display: inline;
|
57
64
|
}
|
58
65
|
|
59
66
|
.flip form input[type=submit] {
|
60
|
-
|
61
|
-
|
62
|
-
|
67
|
+
font-size: 80%;
|
68
|
+
padding: 2px 5px;
|
69
|
+
margin: 0;
|
63
70
|
}
|
64
|
-
|
@@ -1,60 +1,62 @@
|
|
1
|
-
<
|
2
|
-
|
3
|
-
|
4
|
-
<
|
5
|
-
<
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
<div class="flip">
|
2
|
+
<h1>Feature Flippers</h1>
|
3
|
+
|
4
|
+
<table>
|
5
|
+
<thead>
|
6
|
+
<th class="name">Feature Name</th>
|
7
|
+
<th class="description">Description</th>
|
8
|
+
<th class="status">Status</th>
|
9
|
+
<% @p.strategies.each do |strategy| %>
|
10
|
+
<th>
|
11
|
+
<%= strategy.name %>
|
12
|
+
<span class="description"><%= strategy.description %></span>
|
13
|
+
</th>
|
14
|
+
<% end %>
|
9
15
|
<th>
|
10
|
-
|
11
|
-
<span class="description"
|
16
|
+
Default
|
17
|
+
<span class="description">The system default when no strategies match.</span>
|
12
18
|
</th>
|
13
|
-
|
14
|
-
<
|
15
|
-
|
16
|
-
<
|
17
|
-
|
18
|
-
</thead>
|
19
|
-
<tbody>
|
20
|
-
<% @p.definitions.each do |definition| %>
|
21
|
-
<tr>
|
22
|
-
<td class="name"><%= definition.name %></td>
|
23
|
-
|
24
|
-
<td class="description"><%= definition.description %></td>
|
25
|
-
|
26
|
-
<%= content_tag :td, class: @p.status(definition) do %>
|
27
|
-
<%= @p.status definition %>
|
28
|
-
<% end %>
|
19
|
+
</thead>
|
20
|
+
<tbody>
|
21
|
+
<% @p.definitions.each do |definition| %>
|
22
|
+
<tr>
|
23
|
+
<td class="name"><%= definition.name %></td>
|
29
24
|
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
<td class="description"><%= definition.description %></td>
|
26
|
+
|
27
|
+
<%= content_tag :td, class: @p.status(definition) do %>
|
28
|
+
<%= @p.status definition %>
|
29
|
+
<% end %>
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
<% @p.strategies.each do |strategy| %>
|
32
|
+
<%= content_tag :td, class: @p.strategy_status(strategy, definition) || "pass" do %>
|
33
|
+
<%= @p.strategy_status strategy, definition %>
|
34
|
+
|
35
|
+
<% if strategy.switchable? %>
|
36
|
+
<%= form_tag(@p.switch_url(strategy, definition), method: :put) do %>
|
37
|
+
<% unless @p.strategy_status(strategy, definition) == "on" %>
|
38
|
+
<%= submit_tag "Switch On" %>
|
39
|
+
<% end %>
|
40
|
+
<% unless @p.strategy_status(strategy, definition) == "off" %>
|
41
|
+
<%= submit_tag "Switch Off" %>
|
42
|
+
<% end %>
|
38
43
|
<% end %>
|
39
|
-
<% unless @p.strategy_status(strategy, definition)
|
40
|
-
<%=
|
44
|
+
<% unless @p.strategy_status(strategy, definition).blank? %>
|
45
|
+
<%= form_tag(@p.switch_url(strategy, definition), method: :delete) do %>
|
46
|
+
<%= submit_tag "Delete" %>
|
47
|
+
<% end %>
|
41
48
|
<% end %>
|
42
49
|
<% end %>
|
43
|
-
<% unless @p.strategy_status(strategy, definition).blank? %>
|
44
|
-
<%= form_tag(@p.switch_url(strategy, definition), method: :delete) do %>
|
45
|
-
<%= submit_tag "Delete" %>
|
46
|
-
<% end %>
|
47
|
-
<% end %>
|
48
|
-
<% end %>
|
49
50
|
|
51
|
+
<% end %>
|
50
52
|
<% end %>
|
51
|
-
<% end %>
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
<%= content_tag :td, class: @p.default_status(definition) do %>
|
55
|
+
<%= @p.default_status definition %>
|
56
|
+
<% end %>
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
</table>
|
58
|
+
</tr>
|
59
|
+
<% end %>
|
60
|
+
</tbody>
|
61
|
+
</table>
|
62
|
+
</div>
|
data/lib/flip/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,52 +9,72 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-02-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
|
17
|
-
|
16
|
+
prerelease: false
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '3.0'
|
22
|
+
none: false
|
22
23
|
type: :runtime
|
23
|
-
|
24
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '3.0'
|
29
|
+
none: false
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: i18n
|
27
|
-
|
28
|
-
|
32
|
+
prerelease: false
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
31
36
|
- !ruby/object:Gem::Version
|
32
37
|
version: '0'
|
38
|
+
none: false
|
33
39
|
type: :runtime
|
34
|
-
|
35
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
none: false
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rspec
|
38
|
-
|
39
|
-
|
48
|
+
prerelease: false
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
42
52
|
- !ruby/object:Gem::Version
|
43
53
|
version: '2.5'
|
54
|
+
none: false
|
44
55
|
type: :development
|
45
|
-
|
46
|
-
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.5'
|
61
|
+
none: false
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rake
|
49
|
-
|
50
|
-
|
64
|
+
prerelease: false
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
53
68
|
- !ruby/object:Gem::Version
|
54
69
|
version: '0'
|
70
|
+
none: false
|
55
71
|
type: :development
|
56
|
-
|
57
|
-
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
none: false
|
58
78
|
description: Declarative API for specifying features, switchable in declaration, database
|
59
79
|
and cookies.
|
60
80
|
email:
|
@@ -114,20 +134,20 @@ rdoc_options: []
|
|
114
134
|
require_paths:
|
115
135
|
- lib
|
116
136
|
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
-
none: false
|
118
137
|
requirements:
|
119
138
|
- - ! '>='
|
120
139
|
- !ruby/object:Gem::Version
|
121
140
|
version: '0'
|
122
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
141
|
none: false
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
143
|
requirements:
|
125
144
|
- - ! '>='
|
126
145
|
- !ruby/object:Gem::Version
|
127
146
|
version: '0'
|
147
|
+
none: false
|
128
148
|
requirements: []
|
129
149
|
rubyforge_project: flip
|
130
|
-
rubygems_version: 1.8.
|
150
|
+
rubygems_version: 1.8.23
|
131
151
|
signing_key:
|
132
152
|
specification_version: 3
|
133
153
|
summary: A feature flipper for Rails web applications.
|
@@ -142,3 +162,4 @@ test_files:
|
|
142
162
|
- spec/feature_set_spec.rb
|
143
163
|
- spec/flip_spec.rb
|
144
164
|
- spec/spec_helper.rb
|
165
|
+
has_rdoc:
|