flag 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d92ca5beee75e55334375129bf62b0836adf5f7
4
- data.tar.gz: 868a270b5142903ef440f22fd6385a380fcc4bf3
3
+ metadata.gz: aaf08d31ce04248717ab95bcb04f05e040c9dad9
4
+ data.tar.gz: 7bcf051376520b23c40e8d2b80d2539cdad47567
5
5
  SHA512:
6
- metadata.gz: c8f3b6480ce579aa163eea68559385b6790bd02072fc08089a8bc26d6aca6e18b6e45a53920c7a6ad3cd45353b5a6cd5b353d1a0cb8a0508d730faa8b0a49020
7
- data.tar.gz: 7b064e5d80901a1b77d80b50f74cea3c91a681b089d570f596d9d958bc7016be866d6e7bba33d22587b1616d1746546d33aa2cd5adaad3208cc679ea9f993a41
6
+ metadata.gz: 1a67ef9024c6f14362ff7ac9b71b4931ccc7408c32aa92f81d70aa48ae6cd3fff5811a610842fe7566da770ac3e1e5d55df892159ca71e4c92601c380226ffea
7
+ data.tar.gz: 7f549faf4fcb3309e8529157ae9a073f6dfa09810ff1af36774bd3f4c5abc0e724af6658042d1c07b53499e32e21150a6f46e078a8ab1565a828a7757e7b6d54
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.0
4
+ services:
5
+ - "redis-server"
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ flag (1.0.0)
5
+ redic (~> 1.5.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ clap (1.0.0)
11
+ cutest (1.2.3)
12
+ clap
13
+ hiredis (0.6.1)
14
+ rake (12.0.0)
15
+ redic (1.5.0)
16
+ hiredis
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ cutest (~> 1.2.3)
23
+ flag!
24
+ rake
25
+
26
+ BUNDLED WITH
27
+ 1.14.4
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Flag
2
+ [![Build Status](https://travis-ci.org/elcuervo/flag.svg?branch=master)](https://travis-ci.org/elcuervo/flag)
2
3
 
3
4
  Simple feature flags for any app
4
5
 
@@ -37,6 +38,18 @@ Flag(:something).on!("uuid")
37
38
  Flag(:something).on!(:group)
38
39
  ```
39
40
 
41
+ ## Quiet mode
42
+
43
+ Sometimes you don't want to have your server down when doing flag checks:
44
+
45
+ ```ruby
46
+ Flag.quiet!
47
+ # Now everything fails silently
48
+
49
+ Flag.store = Redic.new("redis://localhost:5433/123")
50
+ Flag(:quack).on!
51
+ ```
52
+
40
53
  ## Enable/Check feature flags
41
54
 
42
55
  ### Ids
data/Rakefile CHANGED
@@ -1,11 +1,7 @@
1
1
  require "rake/testtask"
2
2
 
3
- Rake::TestTask.new("spec") do |t|
4
- t.libs << "lib"
5
- t.libs << "test"
6
- t.pattern = "test/**/*_test.rb"
3
+ task :test do
4
+ exec "cutest test/*.rb"
7
5
  end
8
6
 
9
- task :default => [:test]
10
- task :all => [:test, :bench]
11
- task :test => [:spec]
7
+ task :default => :test
@@ -1,17 +1,15 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "flag"
3
- s.version = "0.0.2"
3
+ s.version = "1.0.0"
4
4
  s.summary = "Simple feature flags"
5
5
  s.description = "Feature flags for the humans and the coders"
6
6
  s.authors = ["elcuervo"]
7
7
  s.licenses = ["MIT", "HUGWARE"]
8
- s.email = ["yo@brunoaguirre.com"]
8
+ s.email = ["elcuervo@elcuervo.net"]
9
9
  s.homepage = "http://github.com/elcuervo/flag"
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.test_files = `git ls-files test`.split("\n")
12
12
 
13
- s.add_dependency("redic", "~> 1.4.1")
14
-
15
- s.add_development_dependency("minitest", "~> 5.3.0")
16
- s.add_development_dependency("minitest-given", "~> 3.0.0")
13
+ s.add_dependency("redic", "~> 1.5.0")
14
+ s.add_development_dependency("cutest", "~> 1.2.3")
17
15
  end
@@ -4,15 +4,19 @@ require "redic"
4
4
  module Flag
5
5
  FEATURES = "_flag:features".freeze
6
6
 
7
+ RedisGoneError = StandardError
8
+
7
9
  Members = Struct.new(:name) do
8
10
  USERS = "users".freeze
9
11
  GROUPS = "groups".freeze
10
12
 
11
13
  def <<(item)
12
- if item.to_s.end_with?("%")
13
- Flag.store.call("HSET", Flag::FEATURES, name, item[0...-1])
14
- else
15
- Flag.store.call("SADD", subkey(item), item)
14
+ Flag.execute do |store|
15
+ if item.to_s.end_with?("%")
16
+ store.call("HSET", Flag::FEATURES, name, item[0...-1])
17
+ else
18
+ store.call("SADD", subkey(item), item)
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -24,28 +28,39 @@ module Flag
24
28
  { percentage: percentage, users: users, groups: groups }
25
29
  end
26
30
 
27
- def groups; members_for(GROUPS).map(&:to_sym) end
28
- def users; members_for(USERS) end
31
+ def groups
32
+ members_for(GROUPS).map(&:to_sym)
33
+ end
34
+
35
+ def users
36
+ members_for(USERS)
37
+ end
29
38
 
30
39
  def include?(item)
31
40
  return percentage == item.to_i if item.to_s.end_with?("%")
32
41
  return true if Zlib.crc32(item.to_s) % 100 < percentage
33
42
 
34
- Flag.store.call("SISMEMBER", subkey(item), item).to_i == 1
43
+ Flag.execute do |store|
44
+ store.call("SISMEMBER", subkey(item), item).to_i == 1
45
+ end
35
46
  end
36
47
 
37
48
  def reset
38
- [USERS, GROUPS].each { |k| Flag.store.call("DEL", "#{key}:#{k}") }
49
+ [USERS, GROUPS].each do |k|
50
+ Flag.execute { |store| store.call("DEL", "#{key}:#{k}") }
51
+ end
39
52
  end
40
53
 
41
54
  def percentage
42
- Flag.store.call("HGET", Flag::FEATURES, name).to_i
55
+ Flag.execute { |store| store.call("HGET", Flag::FEATURES, name).to_i }
43
56
  end
44
57
 
45
58
  private
46
59
 
47
60
  def members_for(type)
48
- Flag.store.call("SMEMBERS", "#{key}:#{type}") || []
61
+ Flag.execute do |store|
62
+ store.call("SMEMBERS", "#{key}:#{type}") || []
63
+ end
49
64
  end
50
65
 
51
66
  def subkey(item)
@@ -55,7 +70,7 @@ module Flag
55
70
  def subgroup(item)
56
71
  case item
57
72
  when Integer, Fixnum, String then USERS
58
- when Symbol then GROUPS
73
+ when Symbol then GROUPS
59
74
  end
60
75
  end
61
76
  end
@@ -69,11 +84,21 @@ module Flag
69
84
  @members = Members.new(name)
70
85
  end
71
86
 
72
- def reset; @members.reset end
73
- def key; @members.key end
74
- def activated; @members.activated end
87
+ def reset
88
+ @members.reset
89
+ end
90
+
91
+ def key
92
+ @members.key
93
+ end
94
+
95
+ def activated
96
+ @members.activated
97
+ end
75
98
 
76
- def off?; !active? end
99
+ def off?
100
+ !active?
101
+ end
77
102
 
78
103
  def on?(what = false)
79
104
  return active? if !what
@@ -103,31 +128,58 @@ module Flag
103
128
  end
104
129
 
105
130
  class << self
106
- attr_accessor :store
131
+ attr_accessor :store, :quiet
107
132
 
108
133
  def flush
109
134
  @_group = nil
110
135
  features.each { |_, f| f.reset }
111
- self.store.call("DEL", FEATURES)
136
+ self.execute { |store| store.call("DEL", FEATURES) }
112
137
  end
113
138
 
114
139
  def enabled
115
140
  features.select { |k, v| v.on? }.keys
116
141
  end
117
142
 
118
- def store; @store ||= Redic.new end
119
- def group; @_group ||= Hash.new { |h, k| h[k] = lambda { |id| } } end
143
+ def quiet!
144
+ @quiet = true
145
+ end
146
+
147
+ def quiet?
148
+ @quiet == true
149
+ end
150
+
151
+ def execute
152
+ yield(store)
153
+ rescue Errno::ECONNREFUSED, Errno::EINVAL => e
154
+ raise RedisGoneError unless quiet?
155
+ end
120
156
 
121
- def groups; group.keys end
157
+ def store
158
+ @store ||= Redic.new
159
+ end
160
+
161
+ def group
162
+ @_group ||= Hash.new do |h, k|
163
+ h[k] = lambda { |id| }
164
+ end
165
+ end
166
+
167
+ def groups
168
+ group.keys
169
+ end
122
170
 
123
171
  def features
124
172
  @_features ||= Hash.new { |h, k| h[k] = Feature.new(k) }
125
173
 
126
- self.store.call("HKEYS", FEATURES).each { |k| @_features[k.to_sym] }
174
+ self.execute do |store|
175
+ store.call("HKEYS", FEATURES).each { |k| @_features[k.to_sym] }
176
+ end
127
177
 
128
178
  @_features
129
179
  end
130
180
  end
131
181
  end
132
182
 
133
- def Flag(feature); Flag.features[feature] end
183
+ def Flag(feature)
184
+ Flag.features[feature]
185
+ end
@@ -0,0 +1,32 @@
1
+ require_relative "./spec_helper"
2
+
3
+ scope "fallback" do
4
+ setup do
5
+ Flag.store = Redic.new("redis://localhost:6380/23")
6
+ end
7
+
8
+ scope "normal mode" do
9
+ test "fail when Redis is gone" do
10
+ Flag.quiet = false
11
+
12
+ assert Flag.quiet? == false
13
+ assert_raise(Flag::RedisGoneError) do
14
+ Flag(:fallback).on!
15
+ end
16
+ end
17
+ end
18
+
19
+ scope "quiet mode" do
20
+ setup do
21
+ Flag.quiet!
22
+ end
23
+
24
+ test "do not fail when Redis is gone" do
25
+ assert Flag.quiet? == true
26
+
27
+ Flag(:fallback).on!
28
+
29
+ assert Flag(:fallback).on? == false
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ require_relative "./spec_helper"
2
+
3
+ prepare do
4
+ Flag.flush
5
+ end
6
+
7
+ scope "features" do
8
+ test "empty" do
9
+ assert_equal [], Flag.enabled
10
+ end
11
+
12
+ test "having one" do
13
+ Flag(:test).on!
14
+ assert_equal [:test], Flag.enabled
15
+ end
16
+
17
+ test "turning them off" do
18
+ Flag(:test).on!
19
+ Flag(:test).off!
20
+ Flag(:test2).on!
21
+
22
+ assert_equal [:test2], Flag.enabled
23
+ assert_equal [:test, :test2], Flag.features.keys
24
+ end
25
+
26
+ test "get feature info" do
27
+ Flag(:test).on!("50%")
28
+ Flag(:test).on!("25")
29
+ Flag(:test).on!("UUID")
30
+ Flag(:test).on!(:staff)
31
+
32
+ assert Flag(:test).activated.is_a?(Hash)
33
+ assert Flag(:test).activated[:percentage] == 50
34
+ assert Flag(:test).activated[:users].size == 2
35
+ assert Flag(:test).activated[:users].include?("25")
36
+ assert Flag(:test).activated[:users].include?("UUID")
37
+ assert Flag(:test).activated[:groups] == [:staff]
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ require_relative "./spec_helper"
2
+
3
+ prepare do
4
+ Flag.flush
5
+ end
6
+
7
+ scope "groups" do
8
+ setup do
9
+ Flag.group[:staff] = lambda { |id| id > 1 }
10
+ end
11
+
12
+ test "adding groups" do
13
+ assert_equal [:staff], Flag.groups
14
+ end
15
+
16
+ test "testing if feature is activated for a group" do
17
+ Flag(:test).on!(:staff)
18
+
19
+ assert Flag(:test).on?(:staff)
20
+ end
21
+
22
+ test "trying to check for an empty group" do
23
+ Flag(:test).on!(:bogus)
24
+
25
+ assert_equal false, Flag(:test).on?(1)
26
+ end
27
+
28
+ test "testing if a user beloging to a group get stuff activated" do
29
+ Flag(:test).on!(:staff)
30
+
31
+ assert Flag(:test).on?(1) == false
32
+ assert Flag(:test).on?(2) == true
33
+ assert Flag(:test).on?(3) == true
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "./spec_helper"
2
+
3
+ prepare do
4
+ Flag.flush
5
+ end
6
+
7
+ scope "keys" do
8
+ test "uses the correct namespace" do
9
+ assert_equal "_flag:features:test_the_key", Flag(:test_the_key).key
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ require_relative "./spec_helper"
2
+
3
+ prepare do
4
+ Flag.flush
5
+ end
6
+
7
+ scope "percentage" do
8
+ test "only half" do
9
+ Flag(:test).on!("50%")
10
+
11
+ assert Flag(:test).on?(1) == false
12
+ assert Flag(:test).on?(2) == true
13
+ assert Flag(:test).on?("49%") == false
14
+ assert Flag(:test).on?("50%") == true
15
+ end
16
+ end
@@ -1,7 +1,4 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../lib'
2
2
 
3
- require "minitest/autorun"
4
- require "minitest/spec"
5
- require "minitest/pride"
6
- require "minitest/given"
3
+ require "cutest"
7
4
  require "flag"
@@ -0,0 +1,20 @@
1
+ require_relative "./spec_helper"
2
+
3
+ prepare do
4
+ Flag.flush
5
+ end
6
+
7
+ scope "users" do
8
+ test "enabled only for a user" do
9
+ Flag(:test).on!(1)
10
+
11
+ assert Flag(:test).on?(1) == true
12
+ assert Flag(:test).on?(2) == false
13
+ end
14
+
15
+ test "using any kind of id" do
16
+ Flag(:test).on!("ImARandomUUID")
17
+
18
+ assert Flag(:test).on?("ImARandomUUID")
19
+ end
20
+ end
metadata CHANGED
@@ -1,71 +1,65 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - elcuervo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2017-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redic
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.4.1
19
+ version: 1.5.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.4.1
26
+ version: 1.5.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: minitest
28
+ name: cutest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 5.3.0
33
+ version: 1.2.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 5.3.0
41
- - !ruby/object:Gem::Dependency
42
- name: minitest-given
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ~>
46
- - !ruby/object:Gem::Version
47
- version: 3.0.0
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ~>
53
- - !ruby/object:Gem::Version
54
- version: 3.0.0
40
+ version: 1.2.3
55
41
  description: Feature flags for the humans and the coders
56
42
  email:
57
- - yo@brunoaguirre.com
43
+ - elcuervo@elcuervo.net
58
44
  executables: []
59
45
  extensions: []
60
46
  extra_rdoc_files: []
61
47
  files:
48
+ - ".travis.yml"
49
+ - Gemfile
50
+ - Gemfile.lock
62
51
  - README.md
63
52
  - Rakefile
64
53
  - SPEC.md
65
54
  - flag.gemspec
66
55
  - lib/flag.rb
67
- - test/flag_test.rb
56
+ - test/fallback_test.rb
57
+ - test/features_test.rb
58
+ - test/groups_test.rb
59
+ - test/keys_test.rb
60
+ - test/percentage_test.rb
68
61
  - test/spec_helper.rb
62
+ - test/users_test.rb
69
63
  homepage: http://github.com/elcuervo/flag
70
64
  licenses:
71
65
  - MIT
@@ -77,20 +71,25 @@ require_paths:
77
71
  - lib
78
72
  required_ruby_version: !ruby/object:Gem::Requirement
79
73
  requirements:
80
- - - '>='
74
+ - - ">="
81
75
  - !ruby/object:Gem::Version
82
76
  version: '0'
83
77
  required_rubygems_version: !ruby/object:Gem::Requirement
84
78
  requirements:
85
- - - '>='
79
+ - - ">="
86
80
  - !ruby/object:Gem::Version
87
81
  version: '0'
88
82
  requirements: []
89
83
  rubyforge_project:
90
- rubygems_version: 2.0.14
84
+ rubygems_version: 2.5.1
91
85
  signing_key:
92
86
  specification_version: 4
93
87
  summary: Simple feature flags
94
88
  test_files:
95
- - test/flag_test.rb
89
+ - test/fallback_test.rb
90
+ - test/features_test.rb
91
+ - test/groups_test.rb
92
+ - test/keys_test.rb
93
+ - test/percentage_test.rb
96
94
  - test/spec_helper.rb
95
+ - test/users_test.rb
@@ -1,101 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Flag do
4
- after { Flag.flush }
5
-
6
- context "features" do
7
-
8
- context "empty" do
9
- Given(:features) { Flag.enabled }
10
- Then { features == [] }
11
- end
12
-
13
- context "having one" do
14
- Given { Flag(:test).on! }
15
- Then { Flag.enabled == [:test] }
16
- end
17
-
18
- context "turning them off" do
19
- Given { Flag(:test).on! }
20
- When { Flag(:test).off! }
21
- When { Flag(:test2).on! }
22
-
23
- Then { Flag.enabled == [:test2] }
24
- And { Flag.features.keys == [:test, :test2] }
25
- end
26
-
27
- end
28
-
29
- context "groups" do
30
- Given do
31
- Flag.group[:staff] = lambda { |id| id > 1 }
32
- end
33
-
34
- context "adding groups" do
35
- When(:groups) { Flag.groups }
36
- Then { groups == [:staff] }
37
- end
38
-
39
- context "testing if feature is activated for a group" do
40
- Given { Flag(:test).on!(:staff) }
41
- When(:feature) { Flag(:test).on?(:staff) }
42
- Then { feature == true }
43
- end
44
-
45
- context "trying to check for an empty group" do
46
- Given { Flag(:test).on!(:bogus) }
47
- When(:feature) { Flag(:test).on?(1) }
48
- Then { feature == false }
49
- end
50
-
51
- context "testing if a user beloging to a group get stuff activated" do
52
- Given { Flag(:test).on!(:staff) }
53
-
54
- Then { Flag(:test).on?(1) == false }
55
- And { Flag(:test).on?(2) == true }
56
- And { Flag(:test).on?(3) == true }
57
- end
58
- end
59
-
60
- context "users" do
61
- context "enabled only for a user" do
62
- When { Flag(:test).on!(1) }
63
-
64
- Then { Flag(:test).on?(1) == true }
65
- And { Flag(:test).on?(2) == false }
66
- end
67
-
68
- context "with non numeric users" do
69
- When { Flag(:test).on!("ImARandomUUID") }
70
- Then { Flag(:test).on?("ImARandomUUID") == true }
71
- end
72
- end
73
-
74
- context "keys" do
75
- Given(:feature) { Flag(:test_the_key) }
76
- Then { feature.key == "_flag:features:test_the_key" }
77
- end
78
-
79
- context "percentage" do
80
- Given { Flag(:test).on!("50%") }
81
-
82
- Then { Flag(:test).on?(1) == false }
83
- And { Flag(:test).on?(2) == true }
84
- And { Flag(:test).on?("49%") == false }
85
- And { Flag(:test).on?("50%") == true }
86
- end
87
-
88
- context "get feature info" do
89
- Given { Flag(:test).on!("50%") }
90
- Given { Flag(:test).on!("25") }
91
- Given { Flag(:test).on!("UUID") }
92
- Given { Flag(:test).on!(:staff) }
93
-
94
- Then { Flag(:test).activated.is_a?(Hash) }
95
- And { Flag(:test).activated[:percentage] == 50 }
96
- And { Flag(:test).activated[:users].size == 2 }
97
- And { Flag(:test).activated[:users].include?("25") }
98
- And { Flag(:test).activated[:users].include?("UUID") }
99
- And { Flag(:test).activated[:groups] == [:staff] }
100
- end
101
- end