flip-flop 0.0.2 → 0.0.3
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 +4 -4
- data/Gemfile +6 -1
- data/Gemfile.lock +26 -2
- data/README.md +23 -6
- data/lib/flip-flop/adapters/active_record.rb +61 -0
- data/lib/flip-flop/gates.rb +6 -2
- data/lib/flip-flop/version.rb +1 -1
- data/lib/flip-flop.rb +2 -1
- data/lib/generators/flip-flop/migrations_generator.rb +20 -0
- data/lib/generators/templates/migration.rb +15 -0
- data/spec/lib/adapters/active_record_spec.rb +51 -0
- data/spec/lib/view_helpers_spec.rb +42 -4
- data/spec/spec_helper.rb +4 -4
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 402aff4b7c0a288f0f8f6bf862faa253a991cdeb
|
|
4
|
+
data.tar.gz: 6344ef9e5da7ed8cfd854feaf488285f01f3bdef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb0ee52c53566d20e347126e2978c10606a0d04f460c426456fbe08d0bf115eeb9c261826148a3fd3668f66e23471a642dc68428da0a6e1b2207d6829adbd13e
|
|
7
|
+
data.tar.gz: ecaf65cefa2a7d68e85093e1ea3d1593ce2d09ba301dcf3ccdec4eaff90f93adbb865d7d90ceed942d633085e915ac8aba6276c3de3e4a53d2a148bd1e0b66cb
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
flip-flop (0.0.
|
|
4
|
+
flip-flop (0.0.3)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
+
activemodel (4.2.6)
|
|
10
|
+
activesupport (= 4.2.6)
|
|
11
|
+
builder (~> 3.1)
|
|
12
|
+
activerecord (4.2.6)
|
|
13
|
+
activemodel (= 4.2.6)
|
|
14
|
+
activesupport (= 4.2.6)
|
|
15
|
+
arel (~> 6.0)
|
|
16
|
+
activesupport (4.2.6)
|
|
17
|
+
i18n (~> 0.7)
|
|
18
|
+
json (~> 1.7, >= 1.7.7)
|
|
19
|
+
minitest (~> 5.1)
|
|
20
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
|
21
|
+
tzinfo (~> 1.1)
|
|
22
|
+
arel (6.0.3)
|
|
23
|
+
builder (3.2.2)
|
|
9
24
|
diff-lcs (1.2.5)
|
|
25
|
+
i18n (0.7.0)
|
|
26
|
+
json (1.8.3)
|
|
27
|
+
minitest (5.8.4)
|
|
10
28
|
rake (10.4.2)
|
|
11
29
|
rspec (3.4.0)
|
|
12
30
|
rspec-core (~> 3.4.0)
|
|
@@ -21,14 +39,20 @@ GEM
|
|
|
21
39
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
22
40
|
rspec-support (~> 3.4.0)
|
|
23
41
|
rspec-support (3.4.1)
|
|
42
|
+
sqlite3 (1.3.11)
|
|
43
|
+
thread_safe (0.3.5)
|
|
44
|
+
tzinfo (1.2.2)
|
|
45
|
+
thread_safe (~> 0.1)
|
|
24
46
|
|
|
25
47
|
PLATFORMS
|
|
26
48
|
ruby
|
|
27
49
|
|
|
28
50
|
DEPENDENCIES
|
|
51
|
+
activerecord
|
|
29
52
|
flip-flop!
|
|
30
53
|
rake (~> 10.4.2)
|
|
31
54
|
rspec (~> 3.0)
|
|
55
|
+
sqlite3
|
|
32
56
|
|
|
33
57
|
BUNDLED WITH
|
|
34
|
-
1.
|
|
58
|
+
1.12.4
|
data/README.md
CHANGED
|
@@ -36,7 +36,7 @@ FlipFlop.configure do |config|
|
|
|
36
36
|
end
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
and add a YAML file: `config/
|
|
39
|
+
and add a YAML file: `config/flip_flop.yml`
|
|
40
40
|
|
|
41
41
|
for example:
|
|
42
42
|
|
|
@@ -57,12 +57,23 @@ for example:
|
|
|
57
57
|
begin: 2016-01-01
|
|
58
58
|
end: 2016-02-01
|
|
59
59
|
excl: false
|
|
60
|
+
:rails_env_example:
|
|
61
|
+
:type: :rails_env
|
|
62
|
+
:value: :production
|
|
63
|
+
:another_rails_env_example:
|
|
64
|
+
:type: :rails_env
|
|
65
|
+
:env:
|
|
66
|
+
- :production
|
|
67
|
+
- :test
|
|
60
68
|
```
|
|
61
69
|
|
|
62
70
|
Example Usage
|
|
63
71
|
-------------
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
Once FlipFlop has been configured, (see above section) you can start checking if features
|
|
74
|
+
are enabled or not.
|
|
75
|
+
|
|
76
|
+
### In a Rails View:
|
|
66
77
|
|
|
67
78
|
```ruby
|
|
68
79
|
if feature_enabled? :my_cool_feature
|
|
@@ -73,7 +84,7 @@ end
|
|
|
73
84
|
|
|
74
85
|
```
|
|
75
86
|
|
|
76
|
-
In a
|
|
87
|
+
### In a Rails Controller:
|
|
77
88
|
|
|
78
89
|
```ruby
|
|
79
90
|
class SomeController < ApplicationController
|
|
@@ -85,10 +96,10 @@ class SomeController < ApplicationController
|
|
|
85
96
|
end
|
|
86
97
|
```
|
|
87
98
|
|
|
88
|
-
Without Rails:
|
|
99
|
+
### Without Rails:
|
|
89
100
|
|
|
90
101
|
```ruby
|
|
91
|
-
if FlipFlop
|
|
102
|
+
if FlipFlop.feature_enabled? :some_feature
|
|
92
103
|
puts 'something'
|
|
93
104
|
else
|
|
94
105
|
puts 'something else'
|
|
@@ -106,6 +117,7 @@ Gates
|
|
|
106
117
|
* `until_time` — enable a feature until a time has passed
|
|
107
118
|
* `time_range` — enable a feature for the duration of a time range
|
|
108
119
|
* `percentage_of_time` — enable a feature for a given percentage of checks
|
|
120
|
+
* `rails_env` — enable a feature for a specified Rails environment
|
|
109
121
|
|
|
110
122
|
Adapters
|
|
111
123
|
--------
|
|
@@ -122,6 +134,11 @@ about enabled and disabled features. The YAML file is parsed once when the appli
|
|
|
122
134
|
loaded. It's quick and easy to use, but it requres a deployment if a feature needs
|
|
123
135
|
to be quickly flipped.
|
|
124
136
|
|
|
137
|
+
### ActiveRecord
|
|
138
|
+
|
|
139
|
+
Allows feature settings to be stored in a database table. Because of typecasting and
|
|
140
|
+
additional garbage collection this will not be as fast as the YAML adapter. Futher
|
|
141
|
+
efforts will be made to makeing The ActiveRecord adapter more performant.
|
|
125
142
|
|
|
126
143
|
Extending FlipFlop
|
|
127
144
|
------------------
|
|
@@ -151,4 +168,4 @@ Contributing to FlipFlop
|
|
|
151
168
|
* branch
|
|
152
169
|
* commit
|
|
153
170
|
* push
|
|
154
|
-
* pull request
|
|
171
|
+
* pull request
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module FlipFlop
|
|
4
|
+
module Adapters
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
|
|
7
|
+
# override this method to prevent the feature being loaded from the
|
|
8
|
+
# database twice.
|
|
9
|
+
def feature_enabled?(feature_name)
|
|
10
|
+
f = get_feature(feature_name)
|
|
11
|
+
public_send f.gate_type, f.value
|
|
12
|
+
rescue
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_feature(name)
|
|
17
|
+
Feature::find_by_name(name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Load the record from the DB if it's already there, and store
|
|
21
|
+
# the gate type and value
|
|
22
|
+
def set_feature(name, gate_type, value)
|
|
23
|
+
f = Feature::find_or_initialize_by(name: name)
|
|
24
|
+
f.gate_type = gate_type
|
|
25
|
+
f.value = value
|
|
26
|
+
f.save
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Diable the feature by deleting the record from the DB
|
|
30
|
+
def disable_feature(name)
|
|
31
|
+
get_feature(name).delete
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# here for compatability, should not really be used
|
|
35
|
+
def feature_type(name)
|
|
36
|
+
get_feature(name).gate_type.to_sym
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# here for compatabilty, should not really be used
|
|
40
|
+
def feature_value(name)
|
|
41
|
+
get_feature(name).value
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Feature < ::ActiveRecord::Base
|
|
45
|
+
self.table_name = 'flip_flop_features'.freeze
|
|
46
|
+
serialize :value
|
|
47
|
+
|
|
48
|
+
# getter to type case to symbol
|
|
49
|
+
def name
|
|
50
|
+
super.to_sym
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# getter to type case to symbol
|
|
54
|
+
def gate_type
|
|
55
|
+
super.to_sym
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/flip-flop/gates.rb
CHANGED
|
@@ -23,15 +23,19 @@ module FlipFlop
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def until_time(value)
|
|
26
|
-
Time.now < value
|
|
26
|
+
Time.now.utc < value
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def after_time(value)
|
|
30
|
-
Time.now > value
|
|
30
|
+
Time.now.utc > value
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def percentage_of_time(value)
|
|
34
34
|
rand < (value / 100.0)
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
def rails_env(value)
|
|
38
|
+
value == Rails.env.to_sym || value.include?(Rails.env.to_sym)
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
end
|
data/lib/flip-flop/version.rb
CHANGED
data/lib/flip-flop.rb
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'rails/generators/active_record'
|
|
2
|
+
|
|
3
|
+
module FlipFlop
|
|
4
|
+
module Generators
|
|
5
|
+
class MigrationsGenerator < ::Rails::Generators::Base
|
|
6
|
+
include ::Rails::Generators::Migration
|
|
7
|
+
desc 'Generates migration for FlipFlop tables'
|
|
8
|
+
|
|
9
|
+
source_paths << File.join(File.dirname(__FILE__), 'templates')
|
|
10
|
+
|
|
11
|
+
def create_migration_file
|
|
12
|
+
migration_template 'migration.rb', 'db/migrate/create_flip_flop_tables.rb'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.next_migration_number(dirname)
|
|
16
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class CreateFlipFlopFeatureTable < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :flip_flop_features do |t|
|
|
4
|
+
t.string :name
|
|
5
|
+
t.string :gate_type
|
|
6
|
+
t.text :value
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
add_index :flip_flop_features, :name, unique: true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.down
|
|
13
|
+
drop_table :flip_flop_features
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'flip-flop/adapters/active_record'
|
|
3
|
+
require 'generators/templates/migration'
|
|
4
|
+
|
|
5
|
+
ActiveRecord::Migration.verbose = false
|
|
6
|
+
|
|
7
|
+
describe FlipFlop::Adapters::ActiveRecord do
|
|
8
|
+
context 'ActiveRecord' do
|
|
9
|
+
|
|
10
|
+
before :all do
|
|
11
|
+
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
|
|
12
|
+
FlipFlop.configure { |config| config[:adapter] = FlipFlop::Adapters::ActiveRecord }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before :each do
|
|
16
|
+
CreateFlipFlopFeatureTable.up
|
|
17
|
+
FlipFlop.get_instance.set_feature :db, :boolean, true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
after :each do
|
|
21
|
+
CreateFlipFlopFeatureTable.down
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should save a feature to the database' do
|
|
25
|
+
r = FlipFlop::Adapters::ActiveRecord::Feature.all
|
|
26
|
+
expect(r.size).to eql 1
|
|
27
|
+
expect(r.first.name).to eql :db
|
|
28
|
+
expect(r.first.value).to be_truthy
|
|
29
|
+
expect(r.first.gate_type).to eql :boolean
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'should return true for a bool' do
|
|
33
|
+
expect(FlipFlop.feature_enabled?(:db)).to be_truthy
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should be changeable' do
|
|
37
|
+
FlipFlop.get_instance.set_feature :db, :boolean, false
|
|
38
|
+
r = FlipFlop::Adapters::ActiveRecord::Feature.all
|
|
39
|
+
expect(r.size).to eql 1
|
|
40
|
+
expect(r.first.name).to eql :db
|
|
41
|
+
expect(r.first.value).to be_falsey
|
|
42
|
+
expect(r.first.gate_type).to eql :boolean
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'should still work with other datatypes' do
|
|
46
|
+
FlipFlop.get_instance.set_feature :dates, :date_range, (Date.today - 2)..(Date.today + 2)
|
|
47
|
+
expect(FlipFlop.feature_enabled?(:dates)).to be_truthy
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -7,7 +7,18 @@ class DummyController
|
|
|
7
7
|
include FlipFlop::ViewHelpers
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
if !defined? Rails
|
|
11
|
+
module Rails
|
|
12
|
+
def self.env
|
|
13
|
+
:test
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe DummyController do
|
|
19
|
+
before :each do
|
|
20
|
+
FlipFlop.configure {}
|
|
21
|
+
end
|
|
11
22
|
|
|
12
23
|
describe '#feature_enabled?' do
|
|
13
24
|
it 'should return false if nothing has been set' do
|
|
@@ -101,15 +112,42 @@ describe DummyController do
|
|
|
101
112
|
end
|
|
102
113
|
|
|
103
114
|
it 'feature should be disabled if range not started yet' do
|
|
104
|
-
::FlipFlop::get_instance.set_feature(:ranged, :
|
|
115
|
+
::FlipFlop::get_instance.set_feature(:ranged, :time_range, (Time.now.utc + 60)..(Time.now.utc + ONE_DAY))
|
|
105
116
|
expect(subject.feature_enabled? :ranged).to be_falsey
|
|
106
117
|
end
|
|
107
118
|
|
|
108
119
|
it 'feature should be disabled if range is past' do
|
|
109
|
-
::FlipFlop::get_instance.set_feature(:ranged, :
|
|
120
|
+
::FlipFlop::get_instance.set_feature(:ranged, :time_range, (Time.now.utc - ONE_DAY)..(Time.now.utc - 60))
|
|
110
121
|
expect(subject.feature_enabled? :ranged).to be_falsey
|
|
111
122
|
end
|
|
112
123
|
end
|
|
124
|
+
|
|
125
|
+
context 'rails_env gate' do
|
|
126
|
+
it 'should work if value is equal to rails env' do
|
|
127
|
+
::FlipFlop::get_instance.set_feature(:qwerty, :rails_env, :test)
|
|
128
|
+
expect(subject.feature_enabled? :qwerty).to be_truthy
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'should fail if value is not equal to rails env' do
|
|
132
|
+
::FlipFlop::get_instance.set_feature(:qwerty, :rails_env, :production)
|
|
133
|
+
expect(subject.feature_enabled? :qwerty).to be_falsey
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'should pass in value is an array containing the env' do
|
|
137
|
+
::FlipFlop::get_instance.set_feature(:qwerty, :rails_env, [:production, :test])
|
|
138
|
+
expect(subject.feature_enabled? :qwerty).to be_truthy
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'should fail in value is an array not containing the env' do
|
|
142
|
+
::FlipFlop::get_instance.set_feature(:qwerty, :rails_env, [:production, :dev])
|
|
143
|
+
expect(subject.feature_enabled? :qwerty).to be_falsey
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'should fail if the env contains part of the value' do
|
|
147
|
+
::FlipFlop::get_instance.set_feature(:qwerty, :rails_env, [:production, :testing])
|
|
148
|
+
expect(subject.feature_enabled? :test).to be_falsey
|
|
149
|
+
end
|
|
150
|
+
end
|
|
113
151
|
end
|
|
114
152
|
|
|
115
|
-
end
|
|
153
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
|
2
2
|
|
|
3
3
|
require 'pathname'
|
|
4
4
|
FlopFlopRoot = Pathname(__FILE__).dirname.join('..').expand_path
|
|
@@ -6,10 +6,10 @@ FlopFlopRoot = Pathname(__FILE__).dirname.join('..').expand_path
|
|
|
6
6
|
require 'rubygems'
|
|
7
7
|
require 'bundler'
|
|
8
8
|
|
|
9
|
-
Bundler.setup(:default)
|
|
9
|
+
Bundler.setup(:default, :test)
|
|
10
10
|
|
|
11
11
|
require 'flip-flop'
|
|
12
12
|
|
|
13
|
-
RSpec.configure do
|
|
13
|
+
RSpec.configure do
|
|
14
14
|
FlipFlop.configure {}
|
|
15
|
-
end
|
|
15
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flip-flop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Kulyk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-05-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Enable or disable features easily
|
|
14
14
|
email:
|
|
@@ -23,12 +23,16 @@ files:
|
|
|
23
23
|
- Rakefile
|
|
24
24
|
- flip-flop.gemspec
|
|
25
25
|
- lib/flip-flop.rb
|
|
26
|
+
- lib/flip-flop/adapters/active_record.rb
|
|
26
27
|
- lib/flip-flop/adapters/memory.rb
|
|
27
28
|
- lib/flip-flop/adapters/yaml.rb
|
|
28
29
|
- lib/flip-flop/gates.rb
|
|
29
30
|
- lib/flip-flop/railtie.rb
|
|
30
31
|
- lib/flip-flop/version.rb
|
|
31
32
|
- lib/flip-flop/view_helpers.rb
|
|
33
|
+
- lib/generators/flip-flop/migrations_generator.rb
|
|
34
|
+
- lib/generators/templates/migration.rb
|
|
35
|
+
- spec/lib/adapters/active_record_spec.rb
|
|
32
36
|
- spec/lib/adapters/yaml_spec.rb
|
|
33
37
|
- spec/lib/view_helpers_spec.rb
|
|
34
38
|
- spec/spec_helper.rb
|
|
@@ -53,11 +57,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
53
57
|
version: '0'
|
|
54
58
|
requirements: []
|
|
55
59
|
rubyforge_project:
|
|
56
|
-
rubygems_version: 2.
|
|
60
|
+
rubygems_version: 2.5.1
|
|
57
61
|
signing_key:
|
|
58
62
|
specification_version: 4
|
|
59
63
|
summary: Feature flipper
|
|
60
64
|
test_files:
|
|
65
|
+
- spec/lib/adapters/active_record_spec.rb
|
|
61
66
|
- spec/lib/adapters/yaml_spec.rb
|
|
62
67
|
- spec/lib/view_helpers_spec.rb
|
|
63
68
|
- spec/spec_helper.rb
|