featureflags 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +80 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +83 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/featureflags.gemspec +68 -0
- data/lib/featureflags.rb +0 -0
- data/lib/featureflags/features.rb +55 -0
- data/spec/featureflags_spec.rb +164 -0
- data/spec/spec_helper.rb +30 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 762724b4bba1d8809b3b4e7dbcbbd5b309831259
|
4
|
+
data.tar.gz: f6aa09c1cf29e26ace2609fa1818b369579245f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bf00765f2ccb091f3e2d6f41e1eee9dee6c26ccde01a63cfa2171f233d0a00c4220f92171157ab574ccb83a5b19c33f3462faf6cb153de85027acedba08ac856
|
7
|
+
data.tar.gz: 8564a2cbf4ca5ed41318a26c8b10d985f039e83b9cb42d914f2dbc2120e410052e16e1b1b395bad780fbf672c6bea3d3d3a41094e5b7c7edfe0984ffa4ae583c
|
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development, :test do
|
9
|
+
gem 'byebug'
|
10
|
+
gem "rspec", "~> 3.3.0"
|
11
|
+
gem "rdoc", "~> 3.12"
|
12
|
+
gem "bundler", "~> 1.0"
|
13
|
+
gem "jeweler", "~> 2.0.1"
|
14
|
+
gem "simplecov", ">= 0"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.8)
|
5
|
+
builder (3.2.2)
|
6
|
+
byebug (6.0.2)
|
7
|
+
descendants_tracker (0.0.4)
|
8
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
docile (1.1.5)
|
11
|
+
faraday (0.9.1)
|
12
|
+
multipart-post (>= 1.2, < 3)
|
13
|
+
git (1.2.9.1)
|
14
|
+
github_api (0.12.4)
|
15
|
+
addressable (~> 2.3)
|
16
|
+
descendants_tracker (~> 0.0.4)
|
17
|
+
faraday (~> 0.8, < 0.10)
|
18
|
+
hashie (>= 3.4)
|
19
|
+
multi_json (>= 1.7.5, < 2.0)
|
20
|
+
nokogiri (~> 1.6.6)
|
21
|
+
oauth2
|
22
|
+
hashie (3.4.2)
|
23
|
+
highline (1.7.3)
|
24
|
+
jeweler (2.0.1)
|
25
|
+
builder
|
26
|
+
bundler (>= 1.0)
|
27
|
+
git (>= 1.2.5)
|
28
|
+
github_api
|
29
|
+
highline (>= 1.6.15)
|
30
|
+
nokogiri (>= 1.5.10)
|
31
|
+
rake
|
32
|
+
rdoc
|
33
|
+
json (1.8.3)
|
34
|
+
jwt (1.5.1)
|
35
|
+
mini_portile (0.6.2)
|
36
|
+
multi_json (1.11.2)
|
37
|
+
multi_xml (0.5.5)
|
38
|
+
multipart-post (2.0.0)
|
39
|
+
nokogiri (1.6.6.2)
|
40
|
+
mini_portile (~> 0.6.0)
|
41
|
+
oauth2 (1.0.0)
|
42
|
+
faraday (>= 0.8, < 0.10)
|
43
|
+
jwt (~> 1.0)
|
44
|
+
multi_json (~> 1.3)
|
45
|
+
multi_xml (~> 0.5)
|
46
|
+
rack (~> 1.2)
|
47
|
+
rack (1.6.4)
|
48
|
+
rake (10.4.2)
|
49
|
+
rdoc (3.12.2)
|
50
|
+
json (~> 1.4)
|
51
|
+
rspec (3.3.0)
|
52
|
+
rspec-core (~> 3.3.0)
|
53
|
+
rspec-expectations (~> 3.3.0)
|
54
|
+
rspec-mocks (~> 3.3.0)
|
55
|
+
rspec-core (3.3.2)
|
56
|
+
rspec-support (~> 3.3.0)
|
57
|
+
rspec-expectations (3.3.1)
|
58
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
59
|
+
rspec-support (~> 3.3.0)
|
60
|
+
rspec-mocks (3.3.2)
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
62
|
+
rspec-support (~> 3.3.0)
|
63
|
+
rspec-support (3.3.0)
|
64
|
+
simplecov (0.10.0)
|
65
|
+
docile (~> 1.1.0)
|
66
|
+
json (~> 1.8)
|
67
|
+
simplecov-html (~> 0.10.0)
|
68
|
+
simplecov-html (0.10.0)
|
69
|
+
thread_safe (0.3.5)
|
70
|
+
|
71
|
+
PLATFORMS
|
72
|
+
ruby
|
73
|
+
|
74
|
+
DEPENDENCIES
|
75
|
+
bundler (~> 1.0)
|
76
|
+
byebug
|
77
|
+
jeweler (~> 2.0.1)
|
78
|
+
rdoc (~> 3.12)
|
79
|
+
rspec (~> 3.3.0)
|
80
|
+
simplecov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Al Davidson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
= featureflags
|
2
|
+
|
3
|
+
Simple implementation of the 'Feature Flags' pattern as a Ruby gem.
|
4
|
+
Allows you to set defaults in a Hash of the form:
|
5
|
+
|
6
|
+
```{ feature_name_1: true, feature_name_2: false, feature_with_variations: 'A' }```
|
7
|
+
|
8
|
+
and override them with correspondingly-named environment variables.
|
9
|
+
In the example above, you could enable the feature 'feature_name_2' with the environment variable 'FEATURE_NAME_2'.
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
In your gemfile:
|
14
|
+
|
15
|
+
```gem "ministryofjustice-featureflags"```
|
16
|
+
|
17
|
+
=== If you're using Rails:
|
18
|
+
|
19
|
+
You can set defaults during Rails initialization, usually with a dedicated file in config/initializers:
|
20
|
+
|
21
|
+
defaults = {
|
22
|
+
some_feature: true,
|
23
|
+
some_other_feature: false,
|
24
|
+
another_feature: 'variant-1' # <- any non-falsey value will be treated as enabled
|
25
|
+
}
|
26
|
+
Features::FeatureFlags.init!(defaults)
|
27
|
+
|
28
|
+
=== Setting Flags With Environment Variables
|
29
|
+
|
30
|
+
You can *also* override these values by starting Rails with the correspondingly-named environment variable. For instance, some_other_feature would be mapped to ENV['SOME_OTHER_FEATURE']. The environment variables are checked _at runtime_ (i.e. whenever enabled? is called).
|
31
|
+
|
32
|
+
=== Checking The Flags
|
33
|
+
|
34
|
+
In your application code:
|
35
|
+
|
36
|
+
```
|
37
|
+
if FeatureFlags::Features.enabled?(:some_feature)
|
38
|
+
# do something
|
39
|
+
else
|
40
|
+
# do something different
|
41
|
+
```
|
42
|
+
|
43
|
+
Groups of features:
|
44
|
+
|
45
|
+
```
|
46
|
+
# ALL
|
47
|
+
if FeatureFlags::Features.all_enabled?(:some_feature, :some_other_feature)
|
48
|
+
|
49
|
+
# ANY
|
50
|
+
if FeatureFlags::Features.any_enabled?(:some_feature, :some_other_feature)
|
51
|
+
|
52
|
+
```
|
53
|
+
== Non-boolean Flags
|
54
|
+
|
55
|
+
When checking enabled?, any non-false-y value will return true.
|
56
|
+
This allows you to transparently store non-boolean values in flags, for instance in A/B testing:
|
57
|
+
|
58
|
+
```
|
59
|
+
Features::FeatureFlags.init!(my_feature_variant: 'variant-A')
|
60
|
+
|
61
|
+
case Features::FeatureFlags.flag(:my_feature)
|
62
|
+
when 'variant-A'
|
63
|
+
# do something...
|
64
|
+
when 'variant-B'
|
65
|
+
# do something else...
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
== Contributing to featureflags
|
70
|
+
|
71
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
72
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
73
|
+
* Fork the project.
|
74
|
+
* Start a feature/bugfix branch.
|
75
|
+
* Commit and push until you are happy with your contribution.
|
76
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
77
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
78
|
+
|
79
|
+
== Copyright
|
80
|
+
|
81
|
+
Copyright (c) 2015 Al Davidson. See LICENSE.txt for
|
82
|
+
further details.
|
83
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "featureflags"
|
18
|
+
gem.homepage = "http://github.com/aldavidson/featureflags"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Simple ENV-based implementation of Feature Flags}
|
21
|
+
gem.description = <<-END
|
22
|
+
Simple implementation of the 'Feature Flags' pattern as a Ruby gem.
|
23
|
+
Allows you to set defaults in a Hash of the form:
|
24
|
+
|
25
|
+
```{ feature_name_1: true, feature_name_2: false, feature_with_variations: 'A' }```
|
26
|
+
|
27
|
+
and override them with correspondingly-named environment variables.
|
28
|
+
In the example above, you could enable the feature 'feature_name_2' with the environment variable 'FEATURE_NAME_2'.
|
29
|
+
|
30
|
+
END
|
31
|
+
gem.email = "apdavidson@gmail.com"
|
32
|
+
gem.authors = ["Al Davidson"]
|
33
|
+
# dependencies defined in Gemfile
|
34
|
+
end
|
35
|
+
Jeweler::RubygemsDotOrgTasks.new
|
36
|
+
|
37
|
+
require 'rspec/core'
|
38
|
+
require 'rspec/core/rake_task'
|
39
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
40
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Code coverage detail"
|
44
|
+
task :simplecov do
|
45
|
+
ENV['COVERAGE'] = "true"
|
46
|
+
Rake::Task['spec'].execute
|
47
|
+
end
|
48
|
+
|
49
|
+
task :default => :spec
|
50
|
+
|
51
|
+
require 'rdoc/task'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
54
|
+
|
55
|
+
rdoc.rdoc_dir = 'rdoc'
|
56
|
+
rdoc.title = "featureflags #{version}"
|
57
|
+
rdoc.rdoc_files.include('README*')
|
58
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: featureflags 0.1.0 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "featureflags"
|
9
|
+
s.version = "0.1.0"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Al Davidson"]
|
14
|
+
s.date = "2015-08-26"
|
15
|
+
s.description = "Simple implementation of the 'Feature Flags' pattern as a Ruby gem.\nAllows you to set defaults in a Hash of the form:\n\n ```{ feature_name_1: true, feature_name_2: false, feature_with_variations: 'A' }```\n\nand override them with correspondingly-named environment variables. \nIn the example above, you could enable the feature 'feature_name_2' with the environment variable 'FEATURE_NAME_2'.\n\n"
|
16
|
+
s.email = "apdavidson@gmail.com"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rspec",
|
24
|
+
"Gemfile",
|
25
|
+
"Gemfile.lock",
|
26
|
+
"LICENSE.txt",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"featureflags.gemspec",
|
31
|
+
"lib/featureflags.rb",
|
32
|
+
"lib/featureflags/features.rb",
|
33
|
+
"spec/featureflags_spec.rb",
|
34
|
+
"spec/spec_helper.rb"
|
35
|
+
]
|
36
|
+
s.homepage = "http://github.com/aldavidson/featureflags"
|
37
|
+
s.licenses = ["MIT"]
|
38
|
+
s.rubygems_version = "2.4.6"
|
39
|
+
s.summary = "Simple ENV-based implementation of Feature Flags"
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
s.specification_version = 4
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_development_dependency(%q<byebug>, [">= 0"])
|
46
|
+
s.add_development_dependency(%q<rspec>, ["~> 3.3.0"])
|
47
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
48
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
49
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
50
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<byebug>, [">= 0"])
|
53
|
+
s.add_dependency(%q<rspec>, ["~> 3.3.0"])
|
54
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
55
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
56
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
57
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<byebug>, [">= 0"])
|
61
|
+
s.add_dependency(%q<rspec>, ["~> 3.3.0"])
|
62
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
65
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/featureflags.rb
ADDED
File without changes
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module FeatureFlags
|
2
|
+
module Features
|
3
|
+
attr_accessor :flags
|
4
|
+
|
5
|
+
def self.init!(flags=nil)
|
6
|
+
@flags = load_flags!(flags)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.enabled?(name)
|
10
|
+
!!flag(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Could be useful to use this directly for variants /
|
14
|
+
# AB testing, etc
|
15
|
+
# e.g. FeatureFlags::Features.flag('homepage.splash_form')
|
16
|
+
def self.flag(name)
|
17
|
+
ENV[env_ize(name)] || @flags[name.to_sym]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.all_defaults
|
21
|
+
@flags || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# return all features which are enabled by default
|
25
|
+
# i.e. not-false, regardless of environment variables
|
26
|
+
def self.enabled_by_default
|
27
|
+
@flags.select{|k,v| v}.map{|k,v| k}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.any_enabled?(*names)
|
31
|
+
names.flatten.any?{ |name| enabled?(name) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.all_enabled?(*names)
|
35
|
+
names.flatten.all?{ |name| enabled?(name) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.env_ize(name)
|
39
|
+
name.to_s.upcase.gsub(/[^A-Z0-9_]+/, '_')
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
# NOTE: thread-safety??
|
45
|
+
def self.load_flags!(defaults={})
|
46
|
+
@flags = {}
|
47
|
+
if defaults
|
48
|
+
defaults.each do |key, value|
|
49
|
+
@flags[key] = value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'featureflags/features'
|
3
|
+
|
4
|
+
describe "Featureflags" do
|
5
|
+
let(:args){
|
6
|
+
{
|
7
|
+
cheese: 'gruyere',
|
8
|
+
facebook_login: true,
|
9
|
+
facebook_autopost: false
|
10
|
+
}
|
11
|
+
}
|
12
|
+
before do
|
13
|
+
FeatureFlags::Features.init!( args )
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'init!' do
|
17
|
+
context 'given no args' do
|
18
|
+
let(:args){ nil }
|
19
|
+
|
20
|
+
it 'creates an empty set of flags' do
|
21
|
+
expect(FeatureFlags::Features.all_defaults).to eq({})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'given args' do
|
26
|
+
let(:args){ {'facebook.authentication' => true, 'facebook.autopost' => false} }
|
27
|
+
|
28
|
+
it "stores the given args as flags" do
|
29
|
+
expect(FeatureFlags::Features.all_defaults).to eq(args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'enabled?' do
|
35
|
+
describe 'the given name' do
|
36
|
+
context 'is a sym' do
|
37
|
+
let(:name){ :facebook_login }
|
38
|
+
|
39
|
+
it 'resolves correctly' do
|
40
|
+
expect(FeatureFlags::Features.enabled?(name)).to eq(true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'is a string' do
|
45
|
+
let(:name){ 'facebook_login' }
|
46
|
+
|
47
|
+
it 'resolves correctly' do
|
48
|
+
expect(FeatureFlags::Features.enabled?(name)).to eq(true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'has a non-boolean value' do
|
53
|
+
let(:name){ 'cheese' }
|
54
|
+
|
55
|
+
it 'returns true' do
|
56
|
+
expect(FeatureFlags::Features.enabled?(name)).to eq(true)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'does not exist' do
|
61
|
+
let(:name){ 'foo' }
|
62
|
+
|
63
|
+
it 'returns false' do
|
64
|
+
expect(FeatureFlags::Features.enabled?(name)).to eq(false)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'flag' do
|
71
|
+
context 'when an ENV var exists with the corresponding name' do
|
72
|
+
before do
|
73
|
+
allow(ENV).to receive(:[]).with('FACEBOOK_AUTOPOST').and_return('oh-yes-indeed')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns the ENV var value' do
|
77
|
+
expect(FeatureFlags::Features.flag('facebook_autopost')).to eq('oh-yes-indeed')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
context 'when an ENV var with the corresponding name does not exist' do
|
81
|
+
before do
|
82
|
+
allow(ENV).to receive(:[]).with('FACEBOOK_AUTOPOST').and_return(nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns the inital value' do
|
86
|
+
expect(FeatureFlags::Features.flag('facebook_autopost')).to eq(false)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'all_defaults' do
|
92
|
+
it 'returns all the stored flags' do
|
93
|
+
expect(FeatureFlags::Features.all_defaults).to eq(args)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'enabled_by_default' do
|
98
|
+
it 'returns all stored flag keys with a not-false stored value' do
|
99
|
+
expect(FeatureFlags::Features.enabled_by_default).to eq([:cheese, :facebook_login])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'any_enabled?' do
|
104
|
+
context 'when at least one of the given keys is currently enabled' do
|
105
|
+
let(:keys){ [:cheese, :facebook_autopost] }
|
106
|
+
|
107
|
+
it 'returns true' do
|
108
|
+
expect(FeatureFlags::Features.any_enabled?(keys)).to eq(true)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when none of the given keys are currently enabled' do
|
113
|
+
let(:keys){ [:donkeys, :facebook_autopost] }
|
114
|
+
|
115
|
+
it 'returns false' do
|
116
|
+
expect(FeatureFlags::Features.any_enabled?(keys)).to eq(false)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'all_enabled?' do
|
122
|
+
context 'when all of the given keys are currently enabled' do
|
123
|
+
let(:keys){ [:cheese, :facebook_login] }
|
124
|
+
|
125
|
+
it 'returns true' do
|
126
|
+
expect(FeatureFlags::Features.all_enabled?(keys)).to eq(true)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when any of the given keys are not currently enabled' do
|
131
|
+
let(:keys){ [:donkeys, :facebook_autopost] }
|
132
|
+
|
133
|
+
it 'returns false' do
|
134
|
+
expect(FeatureFlags::Features.all_enabled?(keys)).to eq(false)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'env_ize' do
|
140
|
+
describe 'a sequence of punctation characters other than _' do
|
141
|
+
it 'gets replaced with _' do
|
142
|
+
expect(FeatureFlags::Features.env_ize('SOME_THING-THAT.IS...ENABLED!')).to eq('SOME_THING_THAT_IS_ENABLED_')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'a sequence of ascii characters other than A-Z or 0-9' do
|
147
|
+
it 'gets replaced with _' do
|
148
|
+
expect(FeatureFlags::Features.env_ize('is it red???')).to eq('IS_IT_RED_')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe 'a sequence of non-ascii characters' do
|
153
|
+
it 'gets replaced with _' do
|
154
|
+
expect(FeatureFlags::Features.env_ize('ಠ益ಠRAGEಠ益ಠ')).to eq('_RAGE_')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe 'a sequence of lower-case ASCII characters' do
|
159
|
+
it 'gets upper-cased' do
|
160
|
+
expect(FeatureFlags::Features.env_ize('ascii')).to eq('ASCII')
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'byebug'
|
3
|
+
|
4
|
+
module SimpleCov::Configuration
|
5
|
+
def clean_filters
|
6
|
+
@filters = []
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
SimpleCov.configure do
|
11
|
+
clean_filters
|
12
|
+
load_adapter 'test_frameworks'
|
13
|
+
end
|
14
|
+
|
15
|
+
ENV["COVERAGE"] && SimpleCov.start do
|
16
|
+
add_filter "/.rvm/"
|
17
|
+
end
|
18
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
19
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
20
|
+
|
21
|
+
require 'rspec'
|
22
|
+
require 'featureflags'
|
23
|
+
|
24
|
+
# Requires supporting files with custom matchers and macros, etc,
|
25
|
+
# in ./support/ and its subdirectories.
|
26
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: featureflags
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Al Davidson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: byebug
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.3.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.3.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: "Simple implementation of the 'Feature Flags' pattern as a Ruby gem.\nAllows
|
98
|
+
you to set defaults in a Hash of the form:\n\n ```{ feature_name_1: true, feature_name_2:
|
99
|
+
false, feature_with_variations: 'A' }```\n\nand override them with correspondingly-named
|
100
|
+
environment variables. \nIn the example above, you could enable the feature 'feature_name_2'
|
101
|
+
with the environment variable 'FEATURE_NAME_2'.\n\n"
|
102
|
+
email: apdavidson@gmail.com
|
103
|
+
executables: []
|
104
|
+
extensions: []
|
105
|
+
extra_rdoc_files:
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.rdoc
|
108
|
+
files:
|
109
|
+
- ".document"
|
110
|
+
- ".rspec"
|
111
|
+
- Gemfile
|
112
|
+
- Gemfile.lock
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.rdoc
|
115
|
+
- Rakefile
|
116
|
+
- VERSION
|
117
|
+
- featureflags.gemspec
|
118
|
+
- lib/featureflags.rb
|
119
|
+
- lib/featureflags/features.rb
|
120
|
+
- spec/featureflags_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
homepage: http://github.com/aldavidson/featureflags
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.4.6
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Simple ENV-based implementation of Feature Flags
|
146
|
+
test_files: []
|