can-do 0.1.1 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +1 -1
- data/README.md +32 -2
- data/bin/console +7 -0
- data/can_do.gemspec +10 -4
- data/lib/can_do.rb +36 -15
- metadata +95 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0ea512e8449c21e74af8d3d8f0d025b549c43e5
|
4
|
+
data.tar.gz: ba1daeabb76c50d8337a36a1833b7bf3394f8ed3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66bf959f3b5f28b13f11589c2b485066b28d3d493bd2d2ddf675de2290640bc6c49579083c3b5fdc738216fe71adb1bf2d6c5bc51874b2f26830f2dbbeb36631
|
7
|
+
data.tar.gz: d1a7991590354dd293c68608163437fdad126bc9ebd5138363279c26ddeeb9fdda6830244fb946ce170a310d9ef0642d332b9240ee455bc418b50a0e900d9df6
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/can-do)
|
4
4
|
|
5
|
-
Flips your features based on a `config/features.yml` file or environment variables.
|
5
|
+
Flips your features based on a redis key, a `config/features.yml` file or environment variables.
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
@@ -14,6 +14,36 @@ Add `can-do` to your Gemfile:
|
|
14
14
|
gem "can-do", require: "can_do"
|
15
15
|
```
|
16
16
|
|
17
|
+
## Redis values
|
18
|
+
|
19
|
+
To use redis as a storage set the environment variable `CANDO_REDIS_URL` with your redis instance.
|
20
|
+
|
21
|
+
The keys have to be prefixed with 'features:'.
|
22
|
+
|
23
|
+
So to set and use the feature `experiment-1` set the key like
|
24
|
+
|
25
|
+
```sh
|
26
|
+
$ redis-cli SET features:experiment_1 true
|
27
|
+
```
|
28
|
+
|
29
|
+
and use it like
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require "can_do"
|
33
|
+
|
34
|
+
CanDo.feature?(:experiment_1)
|
35
|
+
```
|
36
|
+
|
37
|
+
Any unset key will fall back to either the environment variable or the yaml variable and `false` if none is set.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
require "can_do"
|
41
|
+
|
42
|
+
CanDo.feature?(:experiment_1)
|
43
|
+
```
|
44
|
+
|
45
|
+
## Yaml File
|
46
|
+
|
17
47
|
Inside the `config` folder relative to your working directory create a file called `features.yml`. Within this file,
|
18
48
|
place your *default feature flags* within the `defaults` key. All available features should be listed here, together with
|
19
49
|
their default values. Add *environment-specific* feature flags under the environment name.
|
@@ -48,7 +78,7 @@ CanDo.feature?(:some_feature) do
|
|
48
78
|
end
|
49
79
|
```
|
50
80
|
|
51
|
-
If a feature is not found, `
|
81
|
+
If a feature is not found, `false` is returned.
|
52
82
|
|
53
83
|
## Environment variables
|
54
84
|
|
data/bin/console
ADDED
data/can_do.gemspec
CHANGED
@@ -3,12 +3,11 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "can-do"
|
6
|
-
spec.version = "0.
|
7
|
-
spec.authors = ["
|
8
|
-
spec.email = ["florin.lipan@blacklane.com", "yuri.veremeyenko@blacklane.com"]
|
6
|
+
spec.version = "1.0.0"
|
7
|
+
spec.authors = ["Blacklane"]
|
9
8
|
|
10
9
|
spec.summary = %q{Simple feature flags.}
|
11
|
-
spec.description = %q{Simple feature flags based on a YAML config file and/or environment variables.}
|
10
|
+
spec.description = %q{Simple feature flags based on a redis instance, a YAML config file and/or environment variables.}
|
12
11
|
spec.homepage = "https://github.com/blacklane/can-do"
|
13
12
|
spec.license = "MIT"
|
14
13
|
|
@@ -17,5 +16,12 @@ Gem::Specification.new do |spec|
|
|
17
16
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
17
|
spec.require_paths = ["lib"]
|
19
18
|
|
19
|
+
spec.add_dependency "redis"
|
20
|
+
spec.add_dependency "connection_pool"
|
21
|
+
|
20
22
|
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "rubocop"
|
26
|
+
spec.add_development_dependency "rspec-mocks"
|
21
27
|
end
|
data/lib/can_do.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
require "connection_pool"
|
2
|
+
require "redis"
|
1
3
|
require "singleton"
|
2
4
|
require "yaml"
|
3
5
|
|
4
|
-
# Flips your features based on a config/features.yml file or environment variables.
|
5
|
-
#
|
6
|
+
# Flips your features based on either a redis key, a config/features.yml file or environment variables.
|
7
|
+
# Redis keys always take precedence over Environment variables and the settings in your YAML file.
|
6
8
|
#
|
7
9
|
# @example config/features.yml
|
8
10
|
# defaults:
|
@@ -26,8 +28,11 @@ require "yaml"
|
|
26
28
|
#
|
27
29
|
class CanDo
|
28
30
|
include Singleton
|
29
|
-
|
30
|
-
|
31
|
+
FEATURE_KEY_PREFIX = "features:"
|
32
|
+
CONNECTION_POOL_SIZE = ENV.fetch("CANDO_CONNECTION_POOL_SIZE", 5)
|
33
|
+
CONNECTION_POOL = ConnectionPool.new(size: CONNECTION_POOL_SIZE, timeout: 5) do
|
34
|
+
Redis.new(url: ENV["CANDO_REDIS_URL"])
|
35
|
+
end
|
31
36
|
|
32
37
|
THE_TRUTH = /^(true|t|yes|y|1)$/i
|
33
38
|
DEFAULT_NAMESPACE = "defaults".freeze
|
@@ -38,18 +43,29 @@ class CanDo
|
|
38
43
|
instance.features
|
39
44
|
end
|
40
45
|
|
41
|
-
def self.
|
46
|
+
def self.shared_features(name)
|
47
|
+
CONNECTION_POOL.with do |redis|
|
48
|
+
begin
|
49
|
+
redis.get(FEATURE_KEY_PREFIX + name.to_s)
|
50
|
+
rescue Redis::BaseError
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.feature?(name)
|
42
57
|
name = name.to_s
|
43
58
|
env_name = name.upcase
|
44
|
-
|
45
|
-
fail NotAFeature.new(name) unless features.key?(name)
|
59
|
+
shared_feature = shared_features(name)
|
46
60
|
|
47
61
|
is_enabled =
|
48
|
-
if
|
62
|
+
if !shared_feature.nil?
|
63
|
+
!!(shared_feature =~ THE_TRUTH)
|
64
|
+
elsif ENV.key?(env_name)
|
49
65
|
!!(ENV[env_name] =~ THE_TRUTH)
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
else
|
67
|
+
features[name] == true
|
68
|
+
end
|
53
69
|
|
54
70
|
# If no block is passed, return true or false
|
55
71
|
return is_enabled unless block_given?
|
@@ -61,10 +77,15 @@ class CanDo
|
|
61
77
|
private
|
62
78
|
|
63
79
|
def initialize
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
80
|
+
yaml_file = File.expand_path("config/features.yml", Dir.pwd)
|
81
|
+
|
82
|
+
@features =
|
83
|
+
if File.exist?(yaml_file)
|
84
|
+
data = YAML.safe_load(File.read(yaml_file))
|
85
|
+
data.fetch(DEFAULT_NAMESPACE, {}).merge(data.fetch(env, {}))
|
86
|
+
else
|
87
|
+
{}
|
88
|
+
end
|
68
89
|
end
|
69
90
|
|
70
91
|
def env
|
metadata
CHANGED
@@ -1,16 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: can-do
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
- Yuri Veremeyenko
|
7
|
+
- Blacklane
|
9
8
|
autorequire:
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2017-11-06 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
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: connection_pool
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
14
41
|
- !ruby/object:Gem::Dependency
|
15
42
|
name: bundler
|
16
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,18 +52,76 @@ dependencies:
|
|
25
52
|
- - ">="
|
26
53
|
- !ruby/object:Gem::Version
|
27
54
|
version: '0'
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
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
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-mocks
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Simple feature flags based on a redis instance, a YAML config file and/or
|
112
|
+
environment variables.
|
113
|
+
email:
|
32
114
|
executables: []
|
33
115
|
extensions: []
|
34
116
|
extra_rdoc_files: []
|
35
117
|
files:
|
36
118
|
- ".gitignore"
|
119
|
+
- ".rubocop.yml"
|
120
|
+
- ".travis.yml"
|
37
121
|
- Gemfile
|
38
122
|
- LICENSE.txt
|
39
123
|
- README.md
|
124
|
+
- bin/console
|
40
125
|
- can_do.gemspec
|
41
126
|
- lib/can_do.rb
|
42
127
|
homepage: https://github.com/blacklane/can-do
|
@@ -59,8 +144,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
144
|
version: '0'
|
60
145
|
requirements: []
|
61
146
|
rubyforge_project:
|
62
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.5.1
|
63
148
|
signing_key:
|
64
149
|
specification_version: 4
|
65
150
|
summary: Simple feature flags.
|
66
151
|
test_files: []
|
152
|
+
has_rdoc:
|