feature_gate 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 255bbc8862c9ffe2ee0423555cb80fda831609ee
4
- data.tar.gz: 0f4de315061a2d378a224915a6282c1a4d60b60a
3
+ metadata.gz: e187e63d24ae3b5361f106b9bec9447d2b0d18ac
4
+ data.tar.gz: 4a194e22810c9e87b39a16b9a725f6743dfac712
5
5
  SHA512:
6
- metadata.gz: 0794de4ccd8bc0b87a78d43637bc2175b219e201c9fd099134fef35bde34cf06989105951144bdad61e47ece2d42de266b2f645e0e5706a8ca2a41a61f568f40
7
- data.tar.gz: db1220d039ea0eed0db994a4b0578077e473527a5a85327c4bf0bec7e5bdb749a55ecd77158a83c7894ef5c405f1bdf37e279574500d52cd4c7d743438798f55
6
+ metadata.gz: 6c32a616311c119c7e68d69192c5207ce82b14ecc0a373168a13f42b73f85d63fb81a67e7bfd4728047885b2b98129ff941bfdd1dee992b4182d0207edd009cb
7
+ data.tar.gz: 771f991a6fc664aff138a9ad627b27f45a4b994e3668fd3acfdfbf4b1d81530f0c84588dc209edf990b537781e24ffbc069cbf5c7900e1926a81461a92e967e1
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  # ignore .gem files
2
2
  *.gem
3
3
  .DS_Store
4
+ log/
data/Gemfile.lock CHANGED
@@ -1,93 +1,135 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- feature_gate (0.0.3)
5
- rails (~> 3.2.18)
4
+ feature_gate (0.0.7)
5
+ rails (~> 4.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actionmailer (3.2.22.2)
11
- actionpack (= 3.2.22.2)
12
- mail (~> 2.5.4)
13
- actionpack (3.2.22.2)
14
- activemodel (= 3.2.22.2)
15
- activesupport (= 3.2.22.2)
16
- builder (~> 3.0.0)
10
+ actionmailer (4.2.6)
11
+ actionpack (= 4.2.6)
12
+ actionview (= 4.2.6)
13
+ activejob (= 4.2.6)
14
+ mail (~> 2.5, >= 2.5.4)
15
+ rails-dom-testing (~> 1.0, >= 1.0.5)
16
+ actionpack (4.2.6)
17
+ actionview (= 4.2.6)
18
+ activesupport (= 4.2.6)
19
+ rack (~> 1.6)
20
+ rack-test (~> 0.6.2)
21
+ rails-dom-testing (~> 1.0, >= 1.0.5)
22
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
23
+ actionview (4.2.6)
24
+ activesupport (= 4.2.6)
25
+ builder (~> 3.1)
17
26
  erubis (~> 2.7.0)
18
- journey (~> 1.0.4)
19
- rack (~> 1.4.5)
20
- rack-cache (~> 1.2)
21
- rack-test (~> 0.6.1)
22
- sprockets (~> 2.2.1)
23
- activemodel (3.2.22.2)
24
- activesupport (= 3.2.22.2)
25
- builder (~> 3.0.0)
26
- activerecord (3.2.22.2)
27
- activemodel (= 3.2.22.2)
28
- activesupport (= 3.2.22.2)
29
- arel (~> 3.0.2)
30
- tzinfo (~> 0.3.29)
31
- activeresource (3.2.22.2)
32
- activemodel (= 3.2.22.2)
33
- activesupport (= 3.2.22.2)
34
- activesupport (3.2.22.2)
35
- i18n (~> 0.6, >= 0.6.4)
36
- multi_json (~> 1.0)
37
- arel (3.0.3)
38
- builder (3.0.4)
27
+ rails-dom-testing (~> 1.0, >= 1.0.5)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
29
+ activejob (4.2.6)
30
+ activesupport (= 4.2.6)
31
+ globalid (>= 0.3.0)
32
+ activemodel (4.2.6)
33
+ activesupport (= 4.2.6)
34
+ builder (~> 3.1)
35
+ activerecord (4.2.6)
36
+ activemodel (= 4.2.6)
37
+ activesupport (= 4.2.6)
38
+ arel (~> 6.0)
39
+ activesupport (4.2.6)
40
+ i18n (~> 0.7)
41
+ json (~> 1.7, >= 1.7.7)
42
+ minitest (~> 5.1)
43
+ thread_safe (~> 0.3, >= 0.3.4)
44
+ tzinfo (~> 1.1)
45
+ arel (6.0.3)
46
+ builder (3.2.2)
47
+ concurrent-ruby (1.0.2)
48
+ diff-lcs (1.2.5)
39
49
  erubis (2.7.0)
40
- hike (1.2.3)
50
+ factory_girl (4.7.0)
51
+ activesupport (>= 3.0.0)
52
+ factory_girl_rails (4.7.0)
53
+ factory_girl (~> 4.7.0)
54
+ railties (>= 3.0.0)
55
+ globalid (0.3.6)
56
+ activesupport (>= 4.1.0)
41
57
  i18n (0.7.0)
42
- journey (1.0.4)
43
58
  json (1.8.3)
44
- mail (2.5.4)
45
- mime-types (~> 1.16)
46
- treetop (~> 1.4.8)
47
- mime-types (1.25.1)
48
- multi_json (1.11.3)
49
- polyglot (0.3.5)
50
- rack (1.4.7)
51
- rack-cache (1.6.1)
52
- rack (>= 0.4)
53
- rack-ssl (1.3.4)
54
- rack
59
+ loofah (2.0.3)
60
+ nokogiri (>= 1.5.9)
61
+ mail (2.6.4)
62
+ mime-types (>= 1.16, < 4)
63
+ mime-types (3.0)
64
+ mime-types-data (~> 3.2015)
65
+ mime-types-data (3.2016.0221)
66
+ mini_portile2 (2.0.0)
67
+ minitest (5.8.4)
68
+ nokogiri (1.6.7.2)
69
+ mini_portile2 (~> 2.0.0.rc2)
70
+ rack (1.6.4)
55
71
  rack-test (0.6.3)
56
72
  rack (>= 1.0)
57
- rails (3.2.22.2)
58
- actionmailer (= 3.2.22.2)
59
- actionpack (= 3.2.22.2)
60
- activerecord (= 3.2.22.2)
61
- activeresource (= 3.2.22.2)
62
- activesupport (= 3.2.22.2)
63
- bundler (~> 1.0)
64
- railties (= 3.2.22.2)
65
- railties (3.2.22.2)
66
- actionpack (= 3.2.22.2)
67
- activesupport (= 3.2.22.2)
68
- rack-ssl (~> 1.3.2)
73
+ rails (4.2.6)
74
+ actionmailer (= 4.2.6)
75
+ actionpack (= 4.2.6)
76
+ actionview (= 4.2.6)
77
+ activejob (= 4.2.6)
78
+ activemodel (= 4.2.6)
79
+ activerecord (= 4.2.6)
80
+ activesupport (= 4.2.6)
81
+ bundler (>= 1.3.0, < 2.0)
82
+ railties (= 4.2.6)
83
+ sprockets-rails
84
+ rails-deprecated_sanitizer (1.0.3)
85
+ activesupport (>= 4.2.0.alpha)
86
+ rails-dom-testing (1.0.7)
87
+ activesupport (>= 4.2.0.beta, < 5.0)
88
+ nokogiri (~> 1.6.0)
89
+ rails-deprecated_sanitizer (>= 1.0.1)
90
+ rails-html-sanitizer (1.0.3)
91
+ loofah (~> 2.0)
92
+ railties (4.2.6)
93
+ actionpack (= 4.2.6)
94
+ activesupport (= 4.2.6)
69
95
  rake (>= 0.8.7)
70
- rdoc (~> 3.4)
71
- thor (>= 0.14.6, < 2.0)
96
+ thor (>= 0.18.1, < 2.0)
72
97
  rake (11.1.2)
73
- rdoc (3.12.2)
74
- json (~> 1.4)
75
- sprockets (2.2.3)
76
- hike (~> 1.2)
77
- multi_json (~> 1.0)
78
- rack (~> 1.0)
79
- tilt (~> 1.1, != 1.3.0)
98
+ rspec-core (3.4.4)
99
+ rspec-support (~> 3.4.0)
100
+ rspec-expectations (3.4.0)
101
+ diff-lcs (>= 1.2.0, < 2.0)
102
+ rspec-support (~> 3.4.0)
103
+ rspec-mocks (3.4.1)
104
+ diff-lcs (>= 1.2.0, < 2.0)
105
+ rspec-support (~> 3.4.0)
106
+ rspec-rails (3.4.2)
107
+ actionpack (>= 3.0, < 4.3)
108
+ activesupport (>= 3.0, < 4.3)
109
+ railties (>= 3.0, < 4.3)
110
+ rspec-core (~> 3.4.0)
111
+ rspec-expectations (~> 3.4.0)
112
+ rspec-mocks (~> 3.4.0)
113
+ rspec-support (~> 3.4.0)
114
+ rspec-support (3.4.1)
115
+ sprockets (3.6.0)
116
+ concurrent-ruby (~> 1.0)
117
+ rack (> 1, < 3)
118
+ sprockets-rails (3.0.4)
119
+ actionpack (>= 4.0)
120
+ activesupport (>= 4.0)
121
+ sprockets (>= 3.0.0)
80
122
  sqlite3 (1.3.11)
81
123
  thor (0.19.1)
82
- tilt (1.4.1)
83
- treetop (1.4.15)
84
- polyglot
85
- polyglot (>= 0.3.1)
86
- tzinfo (0.3.49)
124
+ thread_safe (0.3.5)
125
+ tzinfo (1.2.2)
126
+ thread_safe (~> 0.1)
87
127
 
88
128
  PLATFORMS
89
129
  ruby
90
130
 
91
131
  DEPENDENCIES
132
+ factory_girl_rails (~> 4.5)
92
133
  feature_gate!
134
+ rspec-rails (~> 3.1)
93
135
  sqlite3 (~> 1.3)
data/README.md CHANGED
@@ -1,2 +1,50 @@
1
1
  # feature_gate
2
- A gem to help toggle feature gates on and off
2
+
3
+ A gem to help toggle features on and off in Rails applications without having to re-deploy.
4
+
5
+ ## Installation
6
+
7
+ Include gem in Gemfile:
8
+
9
+ gem 'feature_gate'
10
+
11
+ Run generator to create the migration needed
12
+
13
+ rails generate feature_gate
14
+
15
+ Migrate to create the table in your DB:
16
+
17
+ rake db:migrate
18
+
19
+ ## Usage
20
+
21
+ All gates are closed by default, meaning the features you gate will be hidden until you toggle the gates open.
22
+
23
+ In view files:
24
+
25
+ <% FeatureGate::Manager.gate('gate-name') do %>
26
+ <h1>This is my gated content</h1>
27
+ <p>I am not seen if the gate is on</p>
28
+ <% end %>
29
+
30
+ In controller actions:
31
+
32
+ def index
33
+ FeatureGate::Manager.gate_page('gate-name') # 404s if gate is closed
34
+ end
35
+
36
+ To deploy your feature:
37
+
38
+ FeatureGate::Manager.open!('gate-name')
39
+
40
+ To gate your feature:
41
+
42
+ FeatureGate::Manager.close!('gate-name')
43
+
44
+ To see the names of all opened gates:
45
+
46
+ FeatureGate::Manager.opened_gates
47
+
48
+ To see the names of all closed gates:
49
+
50
+ FeatureGate::Manager.closed_gates
@@ -0,0 +1,19 @@
1
+ module FeatureGate
2
+ class GatedFeature < ActiveRecord::Base
3
+ validates :name, presence: true
4
+ validates :gated, inclusion: { in: [true, false] }
5
+
6
+ scope :opened, -> { where(gated: false) }
7
+ scope :closed, -> { where(gated: true) }
8
+
9
+ def deploy_feature!
10
+ self.gated = false
11
+ save!
12
+ end
13
+
14
+ def gate_feature!
15
+ self.gated = true
16
+ save!
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ module FeatureGate
2
+ class Manager
3
+ def self.gate_page(name)
4
+ gated_feature = GatedFeature.where(name: name).first_or_create
5
+ if gated_feature.gated?
6
+ raise ActionController::RoutingError.new('Not Found')
7
+ end
8
+ end
9
+
10
+ def self.gate(name)
11
+ gated_feature = GatedFeature.where(name: name).first_or_create
12
+ if !gated_feature.gated?
13
+ yield
14
+ end
15
+ end
16
+
17
+ def self.opened_gates
18
+ GatedFeature.opened.pluck(:name)
19
+ end
20
+
21
+ def self.closed_gates
22
+ GatedFeature.closed.pluck(:name)
23
+ end
24
+
25
+ def self.open!(name)
26
+ gated_feature = GatedFeature.find_by_name!(name)
27
+ gated_feature.deploy_feature!
28
+ end
29
+
30
+ def self.close!(name)
31
+ gated_feature = GatedFeature.find_by_name!(name)
32
+ gated_feature.gate_feature!
33
+ end
34
+ end
35
+ end
data/feature_gate.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.summary = 'A gem to toggle feature gates on and off'
9
9
  s.description = 'A gem to toggle feature gates on and off'
10
10
  s.authors = ['Tiffany Huang']
11
- s.email = 'little.huang@gmail.'
11
+ s.email = 'little.huang@gmail.com'
12
12
  s.files = `git ls-files`.split("\n")
13
13
  s.homepage = 'https://github.com/tiffling/feature_gate'
14
14
  s.license = 'MIT'
@@ -16,4 +16,6 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.add_dependency 'rails', '~> 4.0'
18
18
  s.add_development_dependency('sqlite3', '~> 1.3')
19
+ s.add_development_dependency('rspec-rails', '~> 3.1')
20
+ s.add_development_dependency('factory_girl_rails', '~> 4.5')
19
21
  end
@@ -1,3 +1,3 @@
1
1
  module FeatureGate
2
- VERSION = '0.0.7'.freeze
2
+ VERSION = '0.0.8'.freeze
3
3
  end
data/lib/feature_gate.rb CHANGED
@@ -9,30 +9,6 @@ module FeatureGate
9
9
  def self.setup
10
10
  yield self
11
11
  end
12
-
13
- def self.gate_page(name)
14
- gated_feature = GatedFeature.where(name: name).first_or_create
15
- if gated_feature.gated?
16
- raise ActiveRecord::RecordNotFound
17
- end
18
- end
19
-
20
- def self.gate(name)
21
- gated_feature = GatedFeature.where(name: name).first_or_create
22
- if !gated_feature.gated?
23
- yield
24
- end
25
- end
26
-
27
- def self.open!(name)
28
- gated_feature = GatedFeature.find_by_name!(name)
29
- gated_feature.deploy_feature!
30
- end
31
-
32
- def self.close!(name)
33
- gated_feature = GatedFeature.find_by_name!(name)
34
- gated_feature.gate_feature!
35
- end
36
12
  end
37
13
 
38
14
  require 'feature_gate/engine'
data/spec/factories.rb ADDED
@@ -0,0 +1,10 @@
1
+ FactoryGirl.define do
2
+ factory :gated_feature, class: 'FeatureGate::GatedFeature' do
3
+ sequence(:name){ |n| "name_#{n}" }
4
+ gated true
5
+
6
+ trait :open do
7
+ gated false
8
+ end
9
+ end
10
+ end
data/spec/fake_app.rb ADDED
@@ -0,0 +1,17 @@
1
+ # Classes required for the tests
2
+ # class User; end
3
+ # module ApplicationHelper; def current_user; raise; end; end
4
+
5
+ # Create a rails app
6
+ module FeatureGate
7
+ class Application < Rails::Application
8
+ config.secret_key_base = 'test'
9
+ config.paths['config/database'] = ['spec/support/database.yml']
10
+ config.eager_load = false
11
+ end
12
+ end
13
+ FeatureGate::Application.initialize!
14
+
15
+ # Run migrations
16
+ require_relative '../lib/generators/feature_gate/templates/migration'
17
+ CreateGatedFeatures.suppress_messages { CreateGatedFeatures.new.change }
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe FeatureGate::Manager do
4
+ describe '.gate' do
5
+ it 'if the gate for the given name does not exist, create the gate and return nil' do
6
+ expect do
7
+ result = FeatureGate::Manager.gate('new_gate') do
8
+ 'foobar'
9
+ end
10
+ expect(result).to eq nil
11
+ end.to change{ FeatureGate::GatedFeature.count }.by(1)
12
+ end
13
+
14
+ it 'if the gate does exist and it is closed, return nil' do
15
+ create(:gated_feature, name: 'new_gate')
16
+
17
+ expect do
18
+ result = FeatureGate::Manager.gate('new_gate') do
19
+ 'foobar'
20
+ end
21
+ expect(result).to eq nil
22
+ end.not_to change{ FeatureGate::GatedFeature.count }
23
+ end
24
+
25
+ it 'if the gate does exist and it is opened, yield' do
26
+ create(:gated_feature, :open, name: 'new_gate')
27
+
28
+ expect do
29
+ result = FeatureGate::Manager.gate('new_gate') do
30
+ 'foobar'
31
+ end
32
+ expect(result).to eq 'foobar'
33
+ end.not_to change{ FeatureGate::GatedFeature.count }
34
+ end
35
+ end
36
+
37
+ describe '.gate_page' do
38
+ it 'if the gate for the given name does not exist, create the gate and raise not found' do
39
+ expect do
40
+ FeatureGate::Manager.gate_page('new_gate')
41
+ end.to raise_error(ActionController::RoutingError)
42
+ end
43
+
44
+ it 'if the gate does exist and it is closed, raise not found' do
45
+ create(:gated_feature, name: 'new_gate')
46
+
47
+ expect do
48
+ FeatureGate::Manager.gate_page('new_gate')
49
+ end.to raise_error(ActionController::RoutingError)
50
+ end
51
+
52
+ it 'if the gate does exist and it is opened do not raise' do
53
+ create(:gated_feature, :open, name: 'new_gate')
54
+
55
+ expect do
56
+ FeatureGate::Manager.gate_page('new_gate')
57
+ end.not_to raise_error(ActionController::RoutingError)
58
+ end
59
+ end
60
+
61
+ describe '.opened_gates' do
62
+ it 'returns names of all opened gates' do
63
+ opened_gates = create_list(:gated_feature, 2, :open)
64
+ create_list(:gated_feature, 2)
65
+
66
+ expect(FeatureGate::Manager.opened_gates).to match_array(opened_gates.map(&:name))
67
+ end
68
+ end
69
+
70
+ describe '.closed_gates' do
71
+ it 'returns names of all closed gates' do
72
+ create_list(:gated_feature, 2, :open)
73
+ closed_gates = create_list(:gated_feature, 2)
74
+
75
+ expect(FeatureGate::Manager.closed_gates).to match_array(closed_gates.map(&:name))
76
+ end
77
+ end
78
+
79
+ describe '.open!' do
80
+ it 'marks a given gate as open' do
81
+ gate = create(:gated_feature)
82
+ FeatureGate::Manager.open!(gate.name)
83
+ expect(gate.reload).not_to be_gated
84
+ end
85
+ end
86
+
87
+ describe '.close!' do
88
+ it 'marks a given gate as closed' do
89
+ gate = create(:gated_feature, :open)
90
+ FeatureGate::Manager.close!(gate.name)
91
+ expect(gate.reload).to be_gated
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,20 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+
3
+ require 'rails/all'
4
+ require 'rspec/rails'
5
+ require 'fake_app'
6
+
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
8
+
9
+ require 'factory_girl'
10
+ require 'factories'
11
+
12
+ RSpec.configure do |config|
13
+ config.include FactoryGirl::Syntax::Methods
14
+ config.include Rails.application.routes.url_helpers
15
+ config.infer_spec_type_from_file_location!
16
+ config.default_formatter = 'doc'
17
+ config.before(:each) do
18
+ FeatureGate::GatedFeature.delete_all
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ':memory:'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feature_gate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiffany Huang
@@ -38,8 +38,36 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: factory_girl_rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '4.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '4.5'
41
69
  description: A gem to toggle feature gates on and off
42
- email: little.huang@gmail.
70
+ email: little.huang@gmail.com
43
71
  executables: []
44
72
  extensions: []
45
73
  extra_rdoc_files: []
@@ -49,13 +77,19 @@ files:
49
77
  - Gemfile.lock
50
78
  - LICENSE
51
79
  - README.md
52
- - app/models/gated_feature.rb
80
+ - app/models/feature_gate/gated_feature.rb
81
+ - app/models/feature_gate/manager.rb
53
82
  - feature_gate.gemspec
54
83
  - lib/feature_gate.rb
55
84
  - lib/feature_gate/engine.rb
56
85
  - lib/feature_gate/version.rb
57
86
  - lib/generators/feature_gate/feature_gate_generator.rb
58
87
  - lib/generators/feature_gate/templates/migration.rb
88
+ - spec/factories.rb
89
+ - spec/fake_app.rb
90
+ - spec/models/feature_gate/manager_spec.rb
91
+ - spec/spec_helper.rb
92
+ - spec/support/database.yml
59
93
  homepage: https://github.com/tiffling/feature_gate
60
94
  licenses:
61
95
  - MIT
@@ -1,14 +0,0 @@
1
- class GatedFeature < ActiveRecord::Base
2
- validates :name, presence: true
3
- validates :gated, inclusion: { in: [true, false] }
4
-
5
- def deploy_feature!
6
- self.gated = false
7
- save!
8
- end
9
-
10
- def gate_feature!
11
- self.gated = true
12
- save!
13
- end
14
- end