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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8eb5a19ab6f14a1d63e0d490b212ce57da941430
4
- data.tar.gz: 2a53db2847e808306c426853d767a8f2319a62de
3
+ metadata.gz: a0ea512e8449c21e74af8d3d8f0d025b549c43e5
4
+ data.tar.gz: ba1daeabb76c50d8337a36a1833b7bf3394f8ed3
5
5
  SHA512:
6
- metadata.gz: 335a1d55bbc0ada21058946bf487a46915ed944e93c8d3bc007f0600277f30b656a8b1a324d37bb482a5263c39deff677b9b02e410693baa5b4b8b671e7132f2
7
- data.tar.gz: 356dfff84096d84920547a38c5787d6d3a58027189cf0d8d3c1b7471a1e7d5b4b71a4ea47491fae93790563e3e68af5e187f8944f15c1dcbda0f49a468ff56cc
6
+ metadata.gz: 66bf959f3b5f28b13f11589c2b485066b28d3d493bd2d2ddf675de2290640bc6c49579083c3b5fdc738216fe71adb1bf2d6c5bc51874b2f26830f2dbbeb36631
7
+ data.tar.gz: d1a7991590354dd293c68608163437fdad126bc9ebd5138363279c26ddeeb9fdda6830244fb946ce170a310d9ef0642d332b9240ee455bc418b50a0e900d9df6
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
  /tmp/
10
10
 
11
11
  .ruby-version
12
+ .DS_Store
13
+ .rubocop-http*
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ inherit_from:
2
+ - https://raw.githubusercontent.com/blacklane/rubocop/master/rubocop.yml
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ before_script:
3
+ - bundle install
4
+ script:
5
+ - bundle exec rspec
6
+ - bundle exec rubocop
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/can-do.svg)](http://badge.fury.io/rb/can-do)
4
4
 
5
- Flips your features based on a `config/features.yml` file or environment variables. No data store required.
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, `CanDo::NotAFeature` is raised.
81
+ If a feature is not found, `false` is returned.
52
82
 
53
83
  ## Environment variables
54
84
 
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "can_do"
5
+
6
+ require "pry"
7
+ Pry.start
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.1.1"
7
- spec.authors = ["Florin Lipan", "Yuri Veremeyenko"]
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
- # Environment variables always take precedence over the settings in your YAML file.
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
- NotAFeature = Class.new(StandardError)
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.feature?(name, &block)
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 ENV.key?(env_name)
62
+ if !shared_feature.nil?
63
+ !!(shared_feature =~ THE_TRUTH)
64
+ elsif ENV.key?(env_name)
49
65
  !!(ENV[env_name] =~ THE_TRUTH)
50
- else
51
- features[name] == true
52
- end
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
- yaml = File.read(File.expand_path("config/features.yml", Dir.pwd))
65
- data = YAML.load(yaml)
66
-
67
- @features = (data.fetch(DEFAULT_NAMESPACE, {})).merge(data.fetch(env, {}))
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.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Florin Lipan
8
- - Yuri Veremeyenko
7
+ - Blacklane
9
8
  autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2016-04-18 00:00:00.000000000 Z
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
- description: Simple feature flags based on a YAML config file and/or environment variables.
29
- email:
30
- - florin.lipan@blacklane.com
31
- - yuri.veremeyenko@blacklane.com
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.4.6
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: