flip 0.1.0 → 0.2.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.
@@ -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