flip 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a4385dc45cee88a9a76ac1e4a95137f2cbc5a790
4
+ data.tar.gz: 99d8d801d5a81cf84419a5631cc2072bf2b45453
5
+ SHA512:
6
+ metadata.gz: 16474ee1caa55c414e4813ae31b16b76a51832b4e9e61ec719641122a087782883d5e19f83deed11c9851fa012648a5d22e7f22a1f3c662ccc62d4ee27c9abb1
7
+ data.tar.gz: 99c9fc607b5bb2dea98b01b19ec205c9a706a251ca0167cffcf5665306e5039918f368ea66b347980bc9702563d7a6c5e647d0ba3b1451ba9055041ae2e63054
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
6
+ - rbx-19mode
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Flip — flip your features
2
2
  ================
3
3
 
4
+ [![Build Status](https://travis-ci.org/pda/flip.png)](https://travis-ci.org/pda/flip)
5
+
4
6
  **Flip** provides a declarative, layered way of enabling and disabling application functionality at run-time.
5
7
 
6
8
  This gem optimizes for:
@@ -24,7 +26,7 @@ Flip has a dashboard UI that's easy to understand and use.
24
26
  Install
25
27
  -------
26
28
 
27
- **Rails 3.0 and 3.1+**
29
+ **Rails 3.0, 3.1 and 3.2+**
28
30
 
29
31
  # Gemfile
30
32
  gem "flip"
@@ -35,36 +37,40 @@ Install
35
37
  # Run the migration
36
38
  > rake db:migrate
37
39
 
40
+ # Include the Feature model, e.g. config/initializers/feature.rb:
41
+ require 'feature'
38
42
 
39
43
  Declaring Features
40
44
  ------------------
41
45
 
42
- # This is the model class generated by rails g flip:install
43
- class Feature < ActiveRecord::Base
44
- include Flip::Declarable
46
+ ```ruby
47
+ # This is the model class generated by rails g flip:install
48
+ class Feature < ActiveRecord::Base
49
+ include Flip::Declarable
45
50
 
46
- # The recommended Flip strategy stack.
47
- strategy Flip::CookieStrategy
48
- strategy Flip::DatabaseStrategy
49
- strategy Flip::DefaultStrategy
50
- default false
51
-
52
- # A basic feature declaration.
53
- feature :shiny_things
51
+ # The recommended Flip strategy stack.
52
+ strategy Flip::CookieStrategy
53
+ strategy Flip::DatabaseStrategy
54
+ strategy Flip::DefaultStrategy
55
+ default false
54
56
 
55
- # Override the system-wide default.
56
- feature :world_domination, default: true
57
+ # A basic feature declaration.
58
+ feature :shiny_things
57
59
 
58
- # Enabled half the time..? Sure, we can do that.
59
- feature :flakey,
60
- default: proc { rand(2).zero? }
60
+ # Override the system-wide default.
61
+ feature :world_domination, default: true
61
62
 
62
- # Provide a description, normally derived from the feature name.
63
- feature :something,
64
- default: true,
65
- description: "Ability to purchase enrollments in courses",
66
-
67
- end
63
+ # Enabled half the time..? Sure, we can do that.
64
+ feature :flakey,
65
+ default: proc { rand(2).zero? }
66
+
67
+ # Provide a description, normally derived from the feature name.
68
+ feature :something,
69
+ default: true,
70
+ description: "Ability to purchase enrollments in courses",
71
+
72
+ end
73
+ ```
68
74
 
69
75
 
70
76
  Checking Features
@@ -72,19 +78,23 @@ Checking Features
72
78
 
73
79
  `Flip.on?` or the dynamic predicate methods are used to check feature state:
74
80
 
75
- Flip.on? :world_domination # true
76
- Flip.world_domination? # true
77
-
78
- Flip.on? :shiny_things # false
79
- Flip.shiny_things? # false
81
+ ```ruby
82
+ Flip.on? :world_domination # true
83
+ Flip.world_domination? # true
84
+
85
+ Flip.on? :shiny_things # false
86
+ Flip.shiny_things? # false
87
+ ```
80
88
 
81
89
  Views and controllers use the `feature?(key)` method:
82
90
 
83
- <div>
84
- <% if feature? :world_domination %>
85
- <%= link_to "Dominate World", world_dominations_path %>
86
- <% end %>
87
- </div>
91
+ ```erb
92
+ <div>
93
+ <% if feature? :world_domination %>
94
+ <%= link_to "Dominate World", world_dominations_path %>
95
+ <% end %>
96
+ </div>
97
+ ```
88
98
 
89
99
 
90
100
  Feature Flipping Controllers
@@ -92,17 +102,19 @@ Feature Flipping Controllers
92
102
 
93
103
  The `Flip::ControllerFilters` module is mixed into the base `ApplicationController` class. The following controller will respond with 404 Page Not Found to all but the `index` action unless the :new_stuff feature is enabled:
94
104
 
95
- class SampleController < ApplicationController
96
-
97
- require_feature :something, :except => :index
98
-
99
- def show
100
- end
101
-
102
- def index
103
- end
104
-
105
- end
105
+ ```ruby
106
+ class SampleController < ApplicationController
107
+
108
+ require_feature :something, :except => :index
109
+
110
+ def show
111
+ end
112
+
113
+ def index
114
+ end
115
+
116
+ end
117
+ ```
106
118
 
107
119
  Dashboard
108
120
  ---------
@@ -111,32 +123,40 @@ The dashboard provides visibility and control over the features.
111
123
 
112
124
  The gem includes some basic styles:
113
125
 
114
- = content_for :stylesheets_head do
115
- = stylesheet_link_tag "flip"
126
+ ```haml
127
+ = content_for :stylesheets_head do
128
+ = stylesheet_link_tag "flip"
129
+ ```
116
130
 
117
131
  You probably don't want the dashboard to be public. Here's one way of implementing access control.
118
132
 
119
133
  app/controllers/admin/features_controller.rb:
120
134
 
121
- class Admin::FeaturesController < Flip::FeaturesController
122
- before_filter :assert_authenticated_as_admin
123
- end
135
+ ```ruby
136
+ class Admin::FeaturesController < Flip::FeaturesController
137
+ before_filter :assert_authenticated_as_admin
138
+ end
139
+ ```
124
140
 
125
141
  app/controllers/admin/feature_strategies_controller.rb:
126
142
 
127
- class Admin::FeatureStrategiesController < Flip::FeaturesController
128
- before_filter :assert_authenticated_as_admin
129
- end
143
+ ```ruby
144
+ class Admin::FeatureStrategiesController < Flip::FeaturesController
145
+ before_filter :assert_authenticated_as_admin
146
+ end
147
+ ```
130
148
 
131
149
  routes.rb:
132
150
 
133
- namespace :admin do
134
- resources :features, only: [ :index ] do
135
- resources :feature_strategies, only: [ :update, :destroy ]
136
- end
137
- end
151
+ ```ruby
152
+ namespace :admin do
153
+ resources :features, only: [ :index ] do
154
+ resources :feature_strategies, only: [ :update, :destroy ]
155
+ end
156
+ end
138
157
 
139
- mount Flip::Engine => "/admin/features"
158
+ mount Flip::Engine => "/admin/features"
159
+ ```
140
160
 
141
161
  ----
142
162
  Created by Paul Annesley
data/Rakefile CHANGED
@@ -6,5 +6,6 @@ task :default => :spec
6
6
 
7
7
  desc "Run specs"
8
8
  task :spec do
9
- system 'bundle exec rspec --color --format documentation spec/*_spec.rb'
9
+ command = "bundle exec rspec --color --format documentation spec/*_spec.rb"
10
+ system(command) || raise("specs returned non-zero code")
10
11
  end
@@ -1,6 +1,6 @@
1
1
  Flip::Engine.routes.draw do
2
2
 
3
- scope module: "Flip" do
3
+ scope module: "flip" do
4
4
 
5
5
  resources :features, path: "", only: [ :index ] do
6
6
 
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency("activesupport", "~> 3.0")
22
+ s.add_dependency("activesupport", ">= 3.0", "< 5")
23
23
  s.add_dependency("i18n")
24
24
 
25
25
  s.add_development_dependency("rspec", "~> 2.5")
@@ -23,17 +23,19 @@ module Flip
23
23
  end
24
24
 
25
25
  def switch! key, enable
26
- @klass.find_or_initialize_by_key(key).update_attributes! enabled: enable
26
+ @klass.where(key: key.to_s).first_or_initialize.update_attributes!(
27
+ enabled: enable
28
+ )
27
29
  end
28
30
 
29
31
  def delete! key
30
- @klass.find_by_key(key).try(:destroy)
32
+ @klass.where(key: key.to_s).first.try(:destroy)
31
33
  end
32
34
 
33
35
  private
34
36
 
35
37
  def feature(definition)
36
- @klass.find_by_key definition.key
38
+ @klass.where(key: definition.key.to_s).first
37
39
  end
38
40
 
39
41
  end
@@ -1,3 +1,3 @@
1
1
  module Flip
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Flip::DatabaseStrategy do
4
4
 
5
- let(:definition) { double("definition").tap{ |d| d.stub(:key) { :one } } }
5
+ let(:definition) { double("definition", key: "one") }
6
6
  let(:strategy) { Flip::DatabaseStrategy.new(model_klass) }
7
7
  let(:model_klass) do
8
8
  Class.new do
@@ -20,44 +20,56 @@ describe Flip::DatabaseStrategy do
20
20
  its(:switchable?) { should be_true }
21
21
  its(:description) { should be_present }
22
22
 
23
+ let(:db_result) { [] }
24
+ before do
25
+ allow(model_klass).to(receive(:where).with(key: "one").and_return(db_result))
26
+ end
27
+
23
28
  describe "#knows?" do
24
- it "does not know features that cannot be found" do
25
- model_klass.stub(:find_by_key) { nil }
26
- strategy.knows?(definition).should be_false
29
+ context "for unknown key" do
30
+ it "returns true" do
31
+ expect(strategy.knows?(definition)).to eq(false)
32
+ end
27
33
  end
28
- it "knows features that can be found" do
29
- model_klass.stub(:find_by_key) { disabled_record }
30
- strategy.knows?(definition).should be_true
34
+ context "for known key" do
35
+ let(:db_result) { [disabled_record] }
36
+ it "returns false" do
37
+ expect(strategy.knows?(definition)).to eq(true)
38
+ end
31
39
  end
32
40
  end
33
41
 
34
42
  describe "#on?" do
35
- it "is true for an enabled record from the database" do
36
- model_klass.stub(:find_by_key) { enabled_record }
37
- strategy.on?(definition).should be_true
43
+ context "for an enabled record" do
44
+ let(:db_result) { [enabled_record] }
45
+ it "returns true" do
46
+ expect(strategy.on?(definition)).to eq(true)
47
+ end
38
48
  end
39
- it "is false for a disabled record from the database" do
40
- model_klass.stub(:find_by_key) { disabled_record }
41
- strategy.on?(definition).should be_false
49
+ context "for a disabled record" do
50
+ let(:db_result) { [disabled_record] }
51
+ it "returns true" do
52
+ expect(strategy.on?(definition)).to eq(false)
53
+ end
42
54
  end
43
55
  end
44
56
 
45
57
  describe "#switch!" do
46
58
  it "can switch a feature on" do
47
- model_klass.should_receive(:find_or_initialize_by_key).with(:one).and_return(disabled_record)
59
+ expect(db_result).to receive(:first_or_initialize).and_return(disabled_record)
48
60
  disabled_record.should_receive(:update_attributes!).with(enabled: true)
49
61
  strategy.switch! :one, true
50
62
  end
51
63
  it "can switch a feature off" do
52
- model_klass.should_receive(:find_or_initialize_by_key).with(:one).and_return(enabled_record)
64
+ expect(db_result).to receive(:first_or_initialize).and_return(enabled_record)
53
65
  enabled_record.should_receive(:update_attributes!).with(enabled: false)
54
66
  strategy.switch! :one, false
55
67
  end
56
68
  end
57
69
 
58
70
  describe "#delete!" do
71
+ let(:db_result) { [enabled_record] }
59
72
  it "can delete a feature record" do
60
- model_klass.should_receive(:find_by_key).with(:one).and_return(enabled_record)
61
73
  enabled_record.should_receive(:try).with(:destroy)
62
74
  strategy.delete! :one
63
75
  end
@@ -23,7 +23,7 @@ describe Flip::Declarable do
23
23
  it { should be_on(:three) }
24
24
  end
25
25
  context "with default set to true" do
26
- before(:all) { model_class.send(:default, true) }
26
+ before { model_class.send(:default, true) }
27
27
  it { should be_on(:one) }
28
28
  it { should be_on(:three) }
29
29
  end
metadata CHANGED
@@ -1,80 +1,77 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Paul Annesley
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-02-19 00:00:00.000000000 Z
11
+ date: 2013-09-30 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
16
- prerelease: false
17
15
  requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ~>
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3.0'
22
- none: false
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
23
  type: :runtime
24
+ prerelease: false
24
25
  version_requirements: !ruby/object:Gem::Requirement
25
26
  requirements:
26
- - - ~>
27
+ - - '>='
27
28
  - !ruby/object:Gem::Version
28
29
  version: '3.0'
29
- none: false
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
30
33
  - !ruby/object:Gem::Dependency
31
34
  name: i18n
32
- prerelease: false
33
35
  requirement: !ruby/object:Gem::Requirement
34
36
  requirements:
35
- - - ! '>='
37
+ - - '>='
36
38
  - !ruby/object:Gem::Version
37
39
  version: '0'
38
- none: false
39
40
  type: :runtime
41
+ prerelease: false
40
42
  version_requirements: !ruby/object:Gem::Requirement
41
43
  requirements:
42
- - - ! '>='
44
+ - - '>='
43
45
  - !ruby/object:Gem::Version
44
46
  version: '0'
45
- none: false
46
47
  - !ruby/object:Gem::Dependency
47
48
  name: rspec
48
- prerelease: false
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
53
  version: '2.5'
54
- none: false
55
54
  type: :development
55
+ prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ~>
59
59
  - !ruby/object:Gem::Version
60
60
  version: '2.5'
61
- none: false
62
61
  - !ruby/object:Gem::Dependency
63
62
  name: rake
64
- prerelease: false
65
63
  requirement: !ruby/object:Gem::Requirement
66
64
  requirements:
67
- - - ! '>='
65
+ - - '>='
68
66
  - !ruby/object:Gem::Version
69
67
  version: '0'
70
- none: false
71
68
  type: :development
69
+ prerelease: false
72
70
  version_requirements: !ruby/object:Gem::Requirement
73
71
  requirements:
74
- - - ! '>='
72
+ - - '>='
75
73
  - !ruby/object:Gem::Version
76
74
  version: '0'
77
- none: false
78
75
  description: Declarative API for specifying features, switchable in declaration, database
79
76
  and cookies.
80
77
  email:
@@ -84,6 +81,7 @@ extensions: []
84
81
  extra_rdoc_files: []
85
82
  files:
86
83
  - .gitignore
84
+ - .travis.yml
87
85
  - Gemfile
88
86
  - README.md
89
87
  - Rakefile
@@ -129,27 +127,26 @@ files:
129
127
  - spec/spec_helper.rb
130
128
  homepage: https://github.com/pda/flip
131
129
  licenses: []
130
+ metadata: {}
132
131
  post_install_message:
133
132
  rdoc_options: []
134
133
  require_paths:
135
134
  - lib
136
135
  required_ruby_version: !ruby/object:Gem::Requirement
137
136
  requirements:
138
- - - ! '>='
137
+ - - '>='
139
138
  - !ruby/object:Gem::Version
140
139
  version: '0'
141
- none: false
142
140
  required_rubygems_version: !ruby/object:Gem::Requirement
143
141
  requirements:
144
- - - ! '>='
142
+ - - '>='
145
143
  - !ruby/object:Gem::Version
146
144
  version: '0'
147
- none: false
148
145
  requirements: []
149
146
  rubyforge_project: flip
150
- rubygems_version: 1.8.23
147
+ rubygems_version: 2.1.2
151
148
  signing_key:
152
- specification_version: 3
149
+ specification_version: 4
153
150
  summary: A feature flipper for Rails web applications.
154
151
  test_files:
155
152
  - spec/abstract_strategy_spec.rb