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 CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
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
- [Learnable](https://learnable.com) uses feature flippers ([so does Flickr](http://code.flickr.com/blog/2009/12/02/flipping-out/)) as a tool to help achieve [continuous deployment](http://timothyfitz.wordpress.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/).
4
+ **Flip** provides a declarative, layered way of enabling and disabling application functionality at run-time.
5
5
 
6
- **Flip** gives us a declarative, layered mechanism to enable and disable features. There's a configurable system-wide default (`default: !Rails.env.production?` works nicely), plus three layers of strategies to determine status per-feature:
6
+ This gem optimizes for:
7
7
 
8
- * The declared default, e.g. `feature :world_domination, default: true`,
9
- * A database-backed strategy, for flipping features site-wide for all users.
10
- * A cookie-backed strategy, for privately previewing features in your own browser only.
8
+ * developer ease-of-use,
9
+ * visibility and control for other stakeholders (like marketing); and
10
+ * run-time performance
11
11
 
12
- (Hint: that last one is a a killer feature..)
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
+ ![Feature Flipper Dashboard](https://dl.dropbox.com/u/13833591/flip-gem-dashboard.png "Feature Flipper Dashboard")
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
- Feature status can be checked by any code using `on?` or using the dynamic predicate methods:
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
- Within view and controller methods, the `FlipHelper` module provides a `feature?(key)` method:
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
- Note that conditionally declared routes require a server restart to notice changes to feature flags, so they're not a good idea; database/cookie feature flipping will be ignored.
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
- Command Center
105
- --------------
119
+ app/controllers/admin/features_controller.rb:
106
120
 
107
- A dashboard allows you to view the current state of the feature set, and flip any switchable strategies (database, cookie). *Screenshot coming&hellip;*
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: 2em 1em 4em 1em;
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
- visibility: hidden;
15
+ visibility: hidden;
9
16
  }
10
17
 
11
18
  .flip td.name {
12
- font-family: Monaco, sans-serif;
13
- font-weight: bold;
19
+ font-family: Monaco, sans-serif;
20
+ font-weight: bold;
14
21
  }
15
22
 
16
23
  .flip td.name, .flip td.description {
17
- vertical-align: top;
24
+ vertical-align: top;
18
25
  }
19
26
 
20
27
  .flip th {
21
- font-weight: normal;
22
- text-align: left;
23
- vertical-align: top;
28
+ font-weight: normal;
29
+ text-align: left;
30
+ vertical-align: top;
24
31
  }
25
32
 
26
33
  .flip th .description {
27
- font-weight: normal;
28
- display: block;
29
- font-size: 80%;
34
+ font-weight: normal;
35
+ display: block;
36
+ font-size: 80%;
30
37
  }
31
38
 
32
39
  .flip th, .flip td {
33
- padding: 5px 10px;
34
- width: 160px;
35
- height: 40px;
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
- text-align: center;
40
- text-transform: capitalize;
46
+ text-align: center;
47
+ text-transform: capitalize;
41
48
  }
42
49
 
43
50
  .flip td.off {
44
- background-color: #fbb;
51
+ background-color: #fbb;
45
52
  }
46
53
 
47
54
  .flip td.on {
48
- background-color: #cfc;
55
+ background-color: #cfc;
49
56
  }
50
57
 
51
58
  .flip td.pass {
52
- background-color: #eef;
59
+ background-color: #eef;
53
60
  }
54
61
 
55
62
  .flip form {
56
- display: inline;
63
+ display: inline;
57
64
  }
58
65
 
59
66
  .flip form input[type=submit] {
60
- font-size: 80%;
61
- padding: 2px 5px;
62
- margin: 0;
67
+ font-size: 80%;
68
+ padding: 2px 5px;
69
+ margin: 0;
63
70
  }
64
-
@@ -1,60 +1,62 @@
1
- <h1>Feature Flippers</h1>
2
-
3
- <table class="flip">
4
- <thead>
5
- <th class="name">Feature Name</th>
6
- <th class="description">Description</th>
7
- <th class="status">Status</th>
8
- <% @p.strategies.each do |strategy| %>
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
- <%= strategy.name %>
11
- <span class="description"><%= strategy.description %></span>
16
+ Default
17
+ <span class="description">The system default when no strategies match.</span>
12
18
  </th>
13
- <% end %>
14
- <th>
15
- Default
16
- <span class="description">The system default when no strategies match.</span>
17
- </th>
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
- <% @p.strategies.each do |strategy| %>
31
- <%= content_tag :td, class: @p.strategy_status(strategy, definition) || "pass" do %>
32
- <%= @p.strategy_status strategy, definition %>
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
- <% if strategy.switchable? %>
35
- <%= form_tag(@p.switch_url(strategy, definition), method: :put) do %>
36
- <% unless @p.strategy_status(strategy, definition) == "on" %>
37
- <%= submit_tag "Switch On" %>
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) == "off" %>
40
- <%= submit_tag "Switch Off" %>
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
- <%= content_tag :td, class: @p.default_status(definition) do %>
54
- <%= @p.default_status definition %>
55
- <% end %>
54
+ <%= content_tag :td, class: @p.default_status(definition) do %>
55
+ <%= @p.default_status definition %>
56
+ <% end %>
56
57
 
57
- </tr>
58
- <% end %>
59
- </tbody>
60
- </table>
58
+ </tr>
59
+ <% end %>
60
+ </tbody>
61
+ </table>
62
+ </div>
data/lib/flip/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Flip
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
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
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: 2011-12-04 00:00:00.000000000 Z
12
+ date: 2013-02-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70160385209800 !ruby/object:Gem::Requirement
17
- none: false
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
- prerelease: false
24
- version_requirements: *70160385209800
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
- requirement: &70160385207660 !ruby/object:Gem::Requirement
28
- none: false
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
- prerelease: false
35
- version_requirements: *70160385207660
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
- requirement: &70160380032000 !ruby/object:Gem::Requirement
39
- none: false
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
- prerelease: false
46
- version_requirements: *70160380032000
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
- requirement: &70160380031580 !ruby/object:Gem::Requirement
50
- none: false
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
- prerelease: false
57
- version_requirements: *70160380031580
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.11
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: