feature_gate 0.0.7 → 0.0.8

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.
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