can-do 1.0.0 → 1.1.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/can_do.gemspec +1 -1
  4. data/lib/can_do.rb +56 -54
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0ea512e8449c21e74af8d3d8f0d025b549c43e5
4
- data.tar.gz: ba1daeabb76c50d8337a36a1833b7bf3394f8ed3
3
+ metadata.gz: bff3d57eaf45561bc031a0fc69b6204ee12fc95f
4
+ data.tar.gz: ae8b80fee8aff5b8faab98e34b7d91724fe1c3ce
5
5
  SHA512:
6
- metadata.gz: 66bf959f3b5f28b13f11589c2b485066b28d3d493bd2d2ddf675de2290640bc6c49579083c3b5fdc738216fe71adb1bf2d6c5bc51874b2f26830f2dbbeb36631
7
- data.tar.gz: d1a7991590354dd293c68608163437fdad126bc9ebd5138363279c26ddeeb9fdda6830244fb946ce170a310d9ef0642d332b9240ee455bc418b50a0e900d9df6
6
+ metadata.gz: 24b18790e7043f62fc2171b689f285e5a9953af0b2127c8d20618621e96c6a813650229b4a452715e975911983521abf914d8243b06710b312546036c6c78633
7
+ data.tar.gz: 9d05c3df6ba44e2e5c2b790bc071f3e443c7152f45b87a3d6c6e50b4d9f7ec4ad2ef414450103bf090a5f238fa9fc3f2632f8c9cd6d7d9647091086cd0035552
data/.travis.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  language: ruby
2
+ services:
3
+ - redis-server
2
4
  before_script:
3
5
  - bundle install
4
6
  script:
data/can_do.gemspec CHANGED
@@ -3,7 +3,7 @@ $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 = "1.0.0"
6
+ spec.version = "1.1.0"
7
7
  spec.authors = ["Blacklane"]
8
8
 
9
9
  spec.summary = %q{Simple feature flags.}
data/lib/can_do.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "connection_pool"
2
2
  require "redis"
3
- require "singleton"
4
3
  require "yaml"
5
4
 
6
5
  # Flips your features based on either a redis key, a config/features.yml file or environment variables.
@@ -27,8 +26,6 @@ require "yaml"
27
26
  # end
28
27
  #
29
28
  class CanDo
30
- include Singleton
31
- FEATURE_KEY_PREFIX = "features:"
32
29
  CONNECTION_POOL_SIZE = ENV.fetch("CANDO_CONNECTION_POOL_SIZE", 5)
33
30
  CONNECTION_POOL = ConnectionPool.new(size: CONNECTION_POOL_SIZE, timeout: 5) do
34
31
  Redis.new(url: ENV["CANDO_REDIS_URL"])
@@ -37,66 +34,71 @@ class CanDo
37
34
  THE_TRUTH = /^(true|t|yes|y|1)$/i
38
35
  DEFAULT_NAMESPACE = "defaults".freeze
39
36
 
40
- attr_reader :features
37
+ class << self
38
+ def feature?(feature)
39
+ is_enabled = read(feature)
40
+ # If no block is passed, return true or false
41
+ return is_enabled unless block_given?
42
+ # If a block is passed, return block or nil
43
+ yield if is_enabled
44
+ end
41
45
 
42
- def self.features
43
- instance.features
44
- end
46
+ def read(feature)
47
+ name = feature.to_s
48
+ shared_feature = pool.with { |redis| redis.get(redis_key(name)) }
49
+
50
+ fallback_value = fallback.fetch(name, false)
45
51
 
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
52
+ return !!(shared_feature =~ THE_TRUTH) unless shared_feature.nil?
53
+ write(name, fallback_value)
54
+ fallback_value
55
+ rescue Redis::CannotConnectError
56
+ fallback_value
53
57
  end
54
- end
55
58
 
56
- def self.feature?(name)
57
- name = name.to_s
58
- env_name = name.upcase
59
- shared_feature = shared_features(name)
60
-
61
- is_enabled =
62
- if !shared_feature.nil?
63
- !!(shared_feature =~ THE_TRUTH)
64
- elsif ENV.key?(env_name)
65
- !!(ENV[env_name] =~ THE_TRUTH)
66
- else
67
- features[name] == true
68
- end
69
-
70
- # If no block is passed, return true or false
71
- return is_enabled unless block_given?
72
-
73
- # If a block is passed, return block or nil
74
- yield if is_enabled
75
- end
59
+ def write(name, val)
60
+ pool.with { |redis| redis.set(redis_key(name), val) } == "OK"
61
+ rescue Redis::CannotConnectError
62
+ false
63
+ end
76
64
 
77
- private
65
+ def features
66
+ keys = pool.with { |redis| redis.keys(redis_key("*")) }
67
+ keys.map { |key| key.sub(redis_key(nil), "") }
68
+ rescue Redis::CannotConnectError
69
+ []
70
+ end
78
71
 
79
- def initialize
80
- yaml_file = File.expand_path("config/features.yml", Dir.pwd)
72
+ private
81
73
 
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
89
- end
74
+ def redis_key(name)
75
+ "#{redis_namespace}:#{name}"
76
+ end
90
77
 
91
- def env
92
- rails_env || rack_env
93
- end
78
+ def pool
79
+ CONNECTION_POOL
80
+ end
94
81
 
95
- def rails_env
96
- defined?(Rails) ? Rails.env : ENV["RAILS_ENV"]
97
- end
82
+ def fallback
83
+ @fallback ||= load_yaml_features
84
+ end
85
+
86
+ def yaml_file_path
87
+ File.expand_path("config/features.yml", Dir.pwd)
88
+ end
98
89
 
99
- def rack_env
100
- ENV["RACK_ENV"]
90
+ def load_yaml_features
91
+ return {} unless File.exist?(yaml_file_path)
92
+ data = YAML.safe_load(File.read(yaml_file_path))
93
+ data.fetch(DEFAULT_NAMESPACE, {}).merge(data.fetch(env, {}))
94
+ end
95
+
96
+ def env
97
+ ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
98
+ end
99
+
100
+ def redis_namespace
101
+ "features"
102
+ end
101
103
  end
102
104
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: can-do
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blacklane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2017-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis