rollout 2.4.3 → 2.4.6

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
- SHA1:
3
- metadata.gz: c11b1c464e66f315ad7ee924ea7408a5c4bf2a6f
4
- data.tar.gz: 16da6d26818429e62e4783533df17d9022380a46
2
+ SHA256:
3
+ metadata.gz: f3e6e9521ed03059b5b673616e985f89231d77d1ca42d8fa7ff00797ef906768
4
+ data.tar.gz: ac66f6f5f0da7e03bbf506d09f62d34e6afd7f1ea09b248b5193d74f3b6a720e
5
5
  SHA512:
6
- metadata.gz: 4b7b1416e6ba291b67dbce4b5d67db30bbe494fbb31791f6435efe3280607abf17d64cf96210bbe113c6c9948ca8d50c25c0547b9870d0f652033b69cf412b00
7
- data.tar.gz: 19e0b2bd04907cfe2f1b400ccb047b8320b35dddf85f1b76d607b5491340f0b3a63a20fdb2f30af138579a8e016accc4aa88549d32c4136c8a003fe2997ea318
6
+ metadata.gz: ccebf1c2024c332cd921a49b400a7ee8e9a5c0ce95cdf59f5e89fb302bef08684cc04ffae30c952e14ffd5acc97d583871ee590aebe6aa2c519cc416afc17b9f
7
+ data.tar.gz: fe0a400d1f694a6aefb5b1e7d89afb64a8cb28c07a1f510d01655d724bfb97d5b38e7c60e40669aec5fded5581e760549b53564078018cad92c968b6900753ee
@@ -0,0 +1,95 @@
1
+ version: 2.1
2
+
3
+ workflows:
4
+ main:
5
+ jobs:
6
+ - ruby27
7
+ - ruby26
8
+ - ruby25
9
+ - ruby24
10
+ - ruby23
11
+
12
+ executors:
13
+ ruby27:
14
+ docker:
15
+ - image: circleci/ruby:2.7
16
+ - image: circleci/redis:alpine
17
+ ruby26:
18
+ docker:
19
+ - image: circleci/ruby:2.6
20
+ - image: circleci/redis:alpine
21
+ ruby25:
22
+ docker:
23
+ - image: circleci/ruby:2.5
24
+ - image: circleci/redis:alpine
25
+ ruby24:
26
+ docker:
27
+ - image: circleci/ruby:2.4
28
+ - image: circleci/redis:alpine
29
+ ruby23:
30
+ docker:
31
+ - image: circleci/ruby:2.3
32
+ - image: circleci/redis:alpine
33
+
34
+ commands:
35
+ test:
36
+ steps:
37
+ - restore_cache:
38
+ keys:
39
+ - bundler-{{ checksum "Gemfile.lock" }}
40
+
41
+ - run:
42
+ name: Bundle Install
43
+ command: bundle check --path vendor/bundle || bundle install
44
+
45
+ - save_cache:
46
+ key: bundler-{{ checksum "Gemfile.lock" }}
47
+ paths:
48
+ - vendor/bundle
49
+
50
+ - run:
51
+ name: Run rspec
52
+ command: |
53
+ bundle exec rspec --format documentation --format RspecJunitFormatter --out test_results/rspec.xml
54
+
55
+ jobs:
56
+ ruby27:
57
+ executor: ruby27
58
+ steps:
59
+ - checkout
60
+ - test
61
+
62
+ - run:
63
+ name: Report Test Coverage
64
+ command: |
65
+ wget https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 -O cc-test-reporter
66
+ chmod +x cc-test-reporter
67
+ ./cc-test-reporter format-coverage -t simplecov -o coverage/codeclimate.json coverage/.resultset.json
68
+ ./cc-test-reporter upload-coverage -i coverage/codeclimate.json
69
+
70
+ - store_test_results:
71
+ path: test_results
72
+
73
+ ruby26:
74
+ executor: ruby26
75
+ steps:
76
+ - checkout
77
+ - test
78
+
79
+ ruby25:
80
+ executor: ruby25
81
+ steps:
82
+ - checkout
83
+ - test
84
+
85
+ ruby24:
86
+ executor: ruby24
87
+ steps:
88
+ - checkout
89
+ - test
90
+
91
+ ruby23:
92
+ executor: ruby23
93
+ steps:
94
+ - checkout
95
+ - test
data/.gitignore CHANGED
@@ -19,5 +19,6 @@ rdoc
19
19
  pkg
20
20
  *.gem
21
21
  gemfiles/*.lock
22
+ .rspec_status
22
23
 
23
24
  ## PROJECT::SPECIFIC
data/.rubocop.yml ADDED
@@ -0,0 +1,11 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'spec/**/*'
4
+
5
+ Metrics/LineLength:
6
+ Max: 120
7
+ Metrics/MethodLength:
8
+ Max: 20
9
+
10
+ Style/TrailingCommaInArguments:
11
+ EnforcedStyleForMultiline: comma
data/.travis.yml CHANGED
@@ -4,13 +4,13 @@ sudo: false
4
4
  services:
5
5
  - redis-server
6
6
  rvm:
7
- - 2.4.1
8
- - 2.3.1
7
+ - 2.6
8
+ - 2.5
9
+ - 2.4
10
+ - 2.3
9
11
  - 2.2
10
12
  - 2.1
11
- - 2.0.0
12
- - 1.9.3
13
- - jruby-19mode
13
+ - 2.0
14
14
  env:
15
15
  - USE_REAL_REDIS=true
16
16
  gemfile:
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  gemspec
data/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  Fast feature flags based on Redis.
4
4
 
5
- [![Build Status](https://travis-ci.org/fetlife/rollout.svg?branch=master)](https://travis-ci.org/fetlife/rollout)
6
- [![Code Climate](https://codeclimate.com/github/FetLife/rollout/badges/gpa.svg)](https://codeclimate.com/github/fetlife/rollout)
7
- [![Test Coverage](https://codeclimate.com/github/FetLife/rollout/badges/coverage.svg)](https://codeclimate.com/github/fetlife/rollout/coverage)
8
- [![Dependency Status](https://gemnasium.com/FetLife/rollout.svg)](https://gemnasium.com/fetlife/rollout)
5
+ [![Gem Version](https://badge.fury.io/rb/rollout.svg)](https://badge.fury.io/rb/rollout)
6
+ [![CircleCI](https://circleci.com/gh/fetlife/rollout.svg?style=svg)](https://circleci.com/gh/fetlife/rollout)
7
+ [![Code Climate](https://codeclimate.com/github/FetLife/rollout/badges/gpa.svg)](https://codeclimate.com/github/FetLife/rollout)
8
+ [![Test Coverage](https://codeclimate.com/github/FetLife/rollout/badges/coverage.svg)](https://codeclimate.com/github/FetLife/rollout/coverage)
9
9
 
10
10
  ## Install it
11
11
 
@@ -20,10 +20,18 @@ Initialize a rollout object. I assign it to a global var.
20
20
  ```ruby
21
21
  require 'redis'
22
22
 
23
- $redis = Redis.new
23
+ $redis = Redis.new
24
24
  $rollout = Rollout.new($redis)
25
25
  ```
26
26
 
27
+ or even simpler
28
+
29
+ ```ruby
30
+ require 'redis'
31
+ $rollout = Rollout.new(Redis.current) # Will use REDIS_URL env var or default redis url
32
+ ```
33
+
34
+
27
35
  Update data specific to a feature:
28
36
 
29
37
  ```ruby
@@ -71,6 +79,9 @@ Deactivate groups like this:
71
79
  $rollout.deactivate_group(:chat, :all)
72
80
  ```
73
81
 
82
+ Groups need to be defined every time your app starts. The logic is not persisted
83
+ anywhere.
84
+
74
85
  ## Specific Users
75
86
 
76
87
  You might want to let a specific user into a beta test or something. If that
@@ -98,7 +109,7 @@ $rollout.activate_percentage(:chat, 20)
98
109
  The algorithm for determining which users get let in is this:
99
110
 
100
111
  ```ruby
101
- CRC32(user.id) % 100_000 < percentage * 1_000
112
+ CRC32(user.id) < (2**32 - 1) / 100.0 * percentage
102
113
  ```
103
114
 
104
115
  So, for 20%, users 0, 1, 10, 11, 20, 21, etc would be allowed in. Those users
@@ -176,6 +187,7 @@ This example would use the "development:feature:chat:groups" key.
176
187
  * Python: https://github.com/asenchi/proclaim
177
188
  * PHP: https://github.com/opensoft/rollout
178
189
  * Clojure: https://github.com/yeller/shoutout
190
+ * Perl: https://metacpan.org/pod/Toggle
179
191
 
180
192
 
181
193
  ## Contributors
data/Rakefile CHANGED
@@ -1,9 +1,7 @@
1
- begin
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
3
2
 
4
- RSpec::Core::RakeTask.new(:spec)
3
+ require 'rspec/core/rake_task'
5
4
 
6
- task default: :spec
7
- rescue LoadError
8
- # no rspec available
9
- end
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
data/lib/rollout.rb CHANGED
@@ -1,141 +1,18 @@
1
- require "rollout/version"
2
- require "zlib"
3
- require "set"
4
- require "json"
1
+ # frozen_string_literal: true
2
+
3
+ require 'rollout/feature'
4
+ require 'rollout/version'
5
+ require 'zlib'
6
+ require 'set'
7
+ require 'json'
5
8
 
6
9
  class Rollout
7
10
  RAND_BASE = (2**32 - 1) / 100.0
8
-
9
- class Feature
10
- attr_accessor :groups, :users, :percentage, :data
11
- attr_reader :name, :options
12
-
13
- def initialize(name, string = nil, opts = {})
14
- @options = opts
15
- @name = name
16
-
17
- if string
18
- raw_percentage,raw_users,raw_groups,raw_data = string.split('|', 4)
19
- @percentage = raw_percentage.to_f
20
- @users = users_from_string(raw_users)
21
- @groups = groups_from_string(raw_groups)
22
- @data = raw_data.nil? || raw_data.strip.empty? ? {} : JSON.parse(raw_data)
23
- else
24
- clear
25
- end
26
- end
27
-
28
- def serialize
29
- "#{@percentage}|#{@users.to_a.join(",")}|#{@groups.to_a.join(",")}|#{serialize_data}"
30
- end
31
-
32
- def add_user(user)
33
- id = user_id(user)
34
- @users << id unless @users.include?(id)
35
- end
36
-
37
- def remove_user(user)
38
- @users.delete(user_id(user))
39
- end
40
-
41
- def add_group(group)
42
- @groups << group.to_sym unless @groups.include?(group.to_sym)
43
- end
44
-
45
- def remove_group(group)
46
- @groups.delete(group.to_sym)
47
- end
48
-
49
- def clear
50
- @groups = groups_from_string("")
51
- @users = users_from_string("")
52
- @percentage = 0
53
- @data = {}
54
- end
55
-
56
- def active?(rollout, user)
57
- if user
58
- id = user_id(user)
59
- user_in_percentage?(id) ||
60
- user_in_active_users?(id) ||
61
- user_in_active_group?(user, rollout)
62
- else
63
- @percentage == 100
64
- end
65
- end
66
-
67
- def user_in_active_users?(user)
68
- @users.include?(user_id(user))
69
- end
70
-
71
- def to_hash
72
- {
73
- percentage: @percentage,
74
- groups: @groups,
75
- users: @users
76
- }
77
- end
78
-
79
- private
80
- def user_id(user)
81
- if user.is_a?(Integer) || user.is_a?(String)
82
- user.to_s
83
- else
84
- user.send(id_user_by).to_s
85
- end
86
- end
87
-
88
- def id_user_by
89
- @options[:id_user_by] || :id
90
- end
91
-
92
- def user_in_percentage?(user)
93
- Zlib.crc32(user_id_for_percentage(user)) < RAND_BASE * @percentage
94
- end
95
-
96
- def user_id_for_percentage(user)
97
- if @options[:randomize_percentage]
98
- user_id(user).to_s + @name.to_s
99
- else
100
- user_id(user)
101
- end
102
- end
103
-
104
- def user_in_active_group?(user, rollout)
105
- @groups.any? do |g|
106
- rollout.active_in_group?(g, user)
107
- end
108
- end
109
-
110
- def serialize_data
111
- return "" unless @data.is_a? Hash
112
-
113
- @data.to_json
114
- end
115
-
116
- def users_from_string(raw_users)
117
- users = (raw_users || "").split(",").map(&:to_s)
118
- if @options[:use_sets]
119
- users.to_set
120
- else
121
- users
122
- end
123
- end
124
-
125
- def groups_from_string(raw_groups)
126
- groups = (raw_groups || "").split(",").map(&:to_sym)
127
- if @options[:use_sets]
128
- groups.to_set
129
- else
130
- groups
131
- end
132
- end
133
- end
134
11
 
135
12
  def initialize(storage, opts = {})
136
13
  @storage = storage
137
14
  @options = opts
138
- @groups = { all: lambda { |user| true } }
15
+ @groups = { all: ->(_user) { true } }
139
16
  end
140
17
 
141
18
  def activate(feature)
@@ -145,15 +22,13 @@ class Rollout
145
22
  end
146
23
 
147
24
  def deactivate(feature)
148
- with_feature(feature) do |f|
149
- f.clear
150
- end
25
+ with_feature(feature, &:clear)
151
26
  end
152
27
 
153
28
  def delete(feature)
154
- features = (@storage.get(features_key) || "").split(",")
29
+ features = (@storage.get(features_key) || '').split(',')
155
30
  features.delete(feature.to_s)
156
- @storage.set(features_key, features.join(","))
31
+ @storage.set(features_key, features.join(','))
157
32
  @storage.del(key(feature))
158
33
  end
159
34
 
@@ -193,20 +68,20 @@ class Rollout
193
68
 
194
69
  def activate_users(feature, users)
195
70
  with_feature(feature) do |f|
196
- users.each{|user| f.add_user(user)}
71
+ users.each { |user| f.add_user(user) }
197
72
  end
198
73
  end
199
74
 
200
75
  def deactivate_users(feature, users)
201
76
  with_feature(feature) do |f|
202
- users.each{|user| f.remove_user(user)}
77
+ users.each { |user| f.remove_user(user) }
203
78
  end
204
79
  end
205
80
 
206
81
  def set_users(feature, users)
207
82
  with_feature(feature) do |f|
208
83
  f.users = []
209
- users.each{|user| f.add_user(user)}
84
+ users.each { |user| f.add_user(user) }
210
85
  end
211
86
  end
212
87
 
@@ -242,7 +117,7 @@ class Rollout
242
117
 
243
118
  def active_in_group?(group, user)
244
119
  f = @groups[group.to_sym]
245
- f && f.call(user)
120
+ f&.call(user)
246
121
  end
247
122
 
248
123
  def get(feature)
@@ -263,29 +138,31 @@ class Rollout
263
138
  end
264
139
 
265
140
  def multi_get(*features)
266
- feature_keys = features.map{ |feature| key(feature) }
141
+ return [] if features.empty?
142
+
143
+ feature_keys = features.map { |feature| key(feature) }
267
144
  @storage.mget(*feature_keys).map.with_index { |string, index| Feature.new(features[index], string, @options) }
268
145
  end
269
146
 
270
147
  def features
271
- (@storage.get(features_key) || "").split(",").map(&:to_sym)
148
+ (@storage.get(features_key) || '').split(',').map(&:to_sym)
272
149
  end
273
150
 
274
151
  def feature_states(user = nil)
275
- features.each_with_object({}) do |f, hash|
276
- hash[f] = active?(f, user)
152
+ multi_get(*features).each_with_object({}) do |f, hash|
153
+ hash[f.name] = f.active?(self, user)
277
154
  end
278
155
  end
279
156
 
280
157
  def active_features(user = nil)
281
- features.select do |f|
282
- active?(f, user)
283
- end
158
+ multi_get(*features).select do |f|
159
+ f.active?(self, user)
160
+ end.map(&:name)
284
161
  end
285
162
 
286
163
  def clear!
287
164
  features.each do |feature|
288
- with_feature(feature) { |f| f.clear }
165
+ with_feature(feature, &:clear)
289
166
  @storage.del(key(feature))
290
167
  end
291
168
 
@@ -293,7 +170,13 @@ class Rollout
293
170
  end
294
171
 
295
172
  def exists?(feature)
296
- @storage.exists(key(feature))
173
+ # since redis-rb v4.2, `#exists?` replaces `#exists` which now returns integer value instead of boolean
174
+ # https://github.com/redis/redis-rb/pull/918
175
+ if @storage.respond_to?(:exists?)
176
+ @storage.exists?(key(feature))
177
+ else
178
+ @storage.exists(key(feature))
179
+ end
297
180
  end
298
181
 
299
182
  private
@@ -303,7 +186,7 @@ class Rollout
303
186
  end
304
187
 
305
188
  def features_key
306
- "feature:__features__"
189
+ 'feature:__features__'
307
190
  end
308
191
 
309
192
  def with_feature(feature)
@@ -314,6 +197,6 @@ class Rollout
314
197
 
315
198
  def save(feature)
316
199
  @storage.set(key(feature.name), feature.serialize)
317
- @storage.set(features_key, (features | [feature.name.to_sym]).join(","))
200
+ @storage.set(features_key, (features | [feature.name.to_sym]).join(','))
318
201
  end
319
202
  end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Rollout
4
+ class Feature
5
+ attr_accessor :groups, :users, :percentage, :data
6
+ attr_reader :name, :options
7
+
8
+ def initialize(name, string = nil, opts = {})
9
+ @options = opts
10
+ @name = name
11
+
12
+ if string
13
+ raw_percentage, raw_users, raw_groups, raw_data = string.split('|', 4)
14
+ @percentage = raw_percentage.to_f
15
+ @users = users_from_string(raw_users)
16
+ @groups = groups_from_string(raw_groups)
17
+ @data = raw_data.nil? || raw_data.strip.empty? ? {} : JSON.parse(raw_data)
18
+ else
19
+ clear
20
+ end
21
+ end
22
+
23
+ def serialize
24
+ "#{@percentage}|#{@users.to_a.join(',')}|#{@groups.to_a.join(',')}|#{serialize_data}"
25
+ end
26
+
27
+ def add_user(user)
28
+ id = user_id(user)
29
+ @users << id unless @users.include?(id)
30
+ end
31
+
32
+ def remove_user(user)
33
+ @users.delete(user_id(user))
34
+ end
35
+
36
+ def add_group(group)
37
+ @groups << group.to_sym unless @groups.include?(group.to_sym)
38
+ end
39
+
40
+ def remove_group(group)
41
+ @groups.delete(group.to_sym)
42
+ end
43
+
44
+ def clear
45
+ @groups = groups_from_string('')
46
+ @users = users_from_string('')
47
+ @percentage = 0
48
+ @data = {}
49
+ end
50
+
51
+ def active?(rollout, user)
52
+ if user
53
+ id = user_id(user)
54
+ user_in_percentage?(id) ||
55
+ user_in_active_users?(id) ||
56
+ user_in_active_group?(user, rollout)
57
+ else
58
+ @percentage == 100
59
+ end
60
+ end
61
+
62
+ def user_in_active_users?(user)
63
+ @users.include?(user_id(user))
64
+ end
65
+
66
+ def to_hash
67
+ {
68
+ percentage: @percentage,
69
+ groups: @groups,
70
+ users: @users
71
+ }
72
+ end
73
+
74
+ private
75
+
76
+ def user_id(user)
77
+ if user.is_a?(Integer) || user.is_a?(String)
78
+ user.to_s
79
+ else
80
+ user.send(id_user_by).to_s
81
+ end
82
+ end
83
+
84
+ def id_user_by
85
+ @options[:id_user_by] || :id
86
+ end
87
+
88
+ def user_in_percentage?(user)
89
+ Zlib.crc32(user_id_for_percentage(user)) < RAND_BASE * @percentage
90
+ end
91
+
92
+ def user_id_for_percentage(user)
93
+ if @options[:randomize_percentage]
94
+ user_id(user).to_s + @name.to_s
95
+ else
96
+ user_id(user)
97
+ end
98
+ end
99
+
100
+ def user_in_active_group?(user, rollout)
101
+ @groups.any? do |g|
102
+ rollout.active_in_group?(g, user)
103
+ end
104
+ end
105
+
106
+ def serialize_data
107
+ return '' unless @data.is_a? Hash
108
+
109
+ @data.to_json
110
+ end
111
+
112
+ def users_from_string(raw_users)
113
+ users = (raw_users || '').split(',').map(&:to_s)
114
+ if @options[:use_sets]
115
+ users.to_set
116
+ else
117
+ users
118
+ end
119
+ end
120
+
121
+ def groups_from_string(raw_groups)
122
+ groups = (raw_groups || '').split(',').map(&:to_sym)
123
+ if @options[:use_sets]
124
+ groups.to_set
125
+ else
126
+ groups
127
+ end
128
+ end
129
+ end
130
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rollout
2
- VERSION = "2.4.3"
4
+ VERSION = '2.4.6'
3
5
  end
data/rollout.gemspec CHANGED
@@ -1,27 +1,31 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "rollout/version"
1
+ # frozen_string_literal: true
4
2
 
5
- Gem::Specification.new do |s|
6
- s.name = "rollout"
7
- s.version = Rollout::VERSION
8
- s.authors = ["James Golick"]
9
- s.email = ["jamesgolick@gmail.com"]
10
- s.description = "Feature flippers with redis."
11
- s.summary = "Feature flippers with redis."
12
- s.homepage = "https://github.com/FetLife/rollout"
13
- s.license = "MIT"
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
+ require 'rollout/version'
14
5
 
15
- s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- s.require_paths = ["lib"]
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rollout'
8
+ spec.version = Rollout::VERSION
9
+ spec.authors = ['James Golick']
10
+ spec.email = ['jamesgolick@gmail.com']
11
+ spec.description = 'Feature flippers with redis.'
12
+ spec.summary = 'Feature flippers with redis.'
13
+ spec.homepage = 'https://github.com/FetLife/rollout'
14
+ spec.license = 'MIT'
19
15
 
20
- s.add_development_dependency "rspec"
21
- s.add_development_dependency "appraisal"
22
- s.add_development_dependency "bundler", ">= 1.0.0"
23
- s.add_development_dependency "redis"
24
- s.add_development_dependency "fakeredis"
25
- s.add_development_dependency "simplecov"
26
- s.add_development_dependency "codeclimate-test-reporter"
16
+ spec.files = `git ls-files`.split("\n")
17
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.required_ruby_version = '>= 2.3'
22
+
23
+ spec.add_dependency 'redis', '~> 4.0'
24
+
25
+ spec.add_development_dependency 'bundler', '>= 1.17'
26
+ spec.add_development_dependency 'pry'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
29
+ spec.add_development_dependency 'rubocop', '~> 0.71'
30
+ spec.add_development_dependency 'simplecov', '0.17'
27
31
  end
data/spec/rollout_spec.rb CHANGED
@@ -2,8 +2,7 @@ require "spec_helper"
2
2
 
3
3
  RSpec.describe "Rollout" do
4
4
  before do
5
- @redis = Redis.new
6
- @rollout = Rollout.new(@redis)
5
+ @rollout = Rollout.new(Redis.current)
7
6
  end
8
7
 
9
8
  describe "when a group is activated" do
@@ -605,6 +604,12 @@ RSpec.describe "Rollout" do
605
604
  expect(features[2].percentage).to eq 100
606
605
  expect(features.size).to eq 3
607
606
  end
607
+
608
+ describe 'when given feature keys is empty' do
609
+ it 'returns empty array' do
610
+ expect(@rollout.multi_get(*[])).to match_array([])
611
+ end
612
+ end
608
613
  end
609
614
 
610
615
  describe "#set_feature_data" do
data/spec/spec_helper.rb CHANGED
@@ -1,18 +1,27 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
1
+ # frozen_string_literal: true
3
2
 
4
- require "simplecov"
5
- require "rspec"
6
- require ENV["USE_REAL_REDIS"] == "true" ? "redis" : "fakeredis"
3
+ require 'simplecov'
7
4
 
8
- SimpleCov.start do
9
- formatter SimpleCov::Formatter::MultiFormatter.new([
10
- SimpleCov::Formatter::HTMLFormatter,
11
- ])
12
- end
5
+ SimpleCov.start
6
+
7
+ require 'bundler/setup'
8
+ require 'redis'
9
+ require 'rollout'
13
10
 
14
- require "rollout"
11
+ Redis.current = Redis.new(
12
+ host: ENV.fetch('REDIS_HOST', '127.0.0.1'),
13
+ port: ENV.fetch('REDIS_PORT', '6379'),
14
+ db: ENV.fetch('REDIS_DB', '7'),
15
+ )
15
16
 
16
17
  RSpec.configure do |config|
17
- config.before { Redis.new.flushdb }
18
+ config.example_status_persistence_file_path = '.rspec_status'
19
+
20
+ # config.disable_monkey_patching!
21
+
22
+ config.expect_with :rspec do |c|
23
+ c.syntax = :expect
24
+ end
25
+
26
+ config.before { Redis.current.flushdb }
18
27
  end
metadata CHANGED
@@ -1,113 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rollout
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.3
4
+ version: 2.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Golick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-30 00:00:00.000000000 Z
11
+ date: 2020-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
19
+ version: '4.0'
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: '0'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: appraisal
28
+ name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.17'
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: '0'
40
+ version: '1.17'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.0
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.0
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: redis
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '3.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: fakeredis
70
+ name: rspec_junit_formatter
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '0.4'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '0.4'
83
83
  - !ruby/object:Gem::Dependency
84
- name: simplecov
84
+ name: rubocop
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '0.71'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '0.71'
97
97
  - !ruby/object:Gem::Dependency
98
- name: codeclimate-test-reporter
98
+ name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '0.17'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '0.17'
111
111
  description: Feature flippers with redis.
112
112
  email:
113
113
  - jamesgolick@gmail.com
@@ -115,19 +115,17 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
- - ".document"
118
+ - ".circleci/config.yml"
119
119
  - ".gitignore"
120
120
  - ".rspec"
121
+ - ".rubocop.yml"
121
122
  - ".travis.yml"
122
- - Appraisals
123
123
  - Gemfile
124
- - Gemfile.lock
125
124
  - LICENSE
126
125
  - README.md
127
126
  - Rakefile
128
- - gemfiles/redis_3.gemfile
129
- - gemfiles/redis_4.gemfile
130
127
  - lib/rollout.rb
128
+ - lib/rollout/feature.rb
131
129
  - lib/rollout/version.rb
132
130
  - rollout.gemspec
133
131
  - spec/rollout_spec.rb
@@ -144,15 +142,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
142
  requirements:
145
143
  - - ">="
146
144
  - !ruby/object:Gem::Version
147
- version: '0'
145
+ version: '2.3'
148
146
  required_rubygems_version: !ruby/object:Gem::Requirement
149
147
  requirements:
150
148
  - - ">="
151
149
  - !ruby/object:Gem::Version
152
150
  version: '0'
153
151
  requirements: []
154
- rubyforge_project:
155
- rubygems_version: 2.6.12
152
+ rubygems_version: 3.0.3
156
153
  signing_key:
157
154
  specification_version: 4
158
155
  summary: Feature flippers with redis.
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/Appraisals DELETED
@@ -1,7 +0,0 @@
1
- appraise "redis-3" do
2
- gem "redis", "~> 3.3.2"
3
- end
4
-
5
- appraise "redis-4" do
6
- gem "redis", "4.0.0.rc1"
7
- end
data/Gemfile.lock DELETED
@@ -1,56 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- rollout (2.4.3)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- appraisal (2.2.0)
10
- bundler
11
- rake
12
- thor (>= 0.14.0)
13
- codeclimate-test-reporter (1.0.8)
14
- simplecov (<= 0.13)
15
- diff-lcs (1.3)
16
- docile (1.1.5)
17
- fakeredis (0.6.0)
18
- redis (~> 3.2)
19
- json (2.1.0)
20
- rake (12.0.0)
21
- redis (3.3.3)
22
- rspec (3.6.0)
23
- rspec-core (~> 3.6.0)
24
- rspec-expectations (~> 3.6.0)
25
- rspec-mocks (~> 3.6.0)
26
- rspec-core (3.6.0)
27
- rspec-support (~> 3.6.0)
28
- rspec-expectations (3.6.0)
29
- diff-lcs (>= 1.2.0, < 2.0)
30
- rspec-support (~> 3.6.0)
31
- rspec-mocks (3.6.0)
32
- diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.6.0)
34
- rspec-support (3.6.0)
35
- simplecov (0.13.0)
36
- docile (~> 1.1.0)
37
- json (>= 1.8, < 3)
38
- simplecov-html (~> 0.10.0)
39
- simplecov-html (0.10.1)
40
- thor (0.19.4)
41
-
42
- PLATFORMS
43
- ruby
44
-
45
- DEPENDENCIES
46
- appraisal
47
- bundler (>= 1.0.0)
48
- codeclimate-test-reporter
49
- fakeredis
50
- redis
51
- rollout!
52
- rspec
53
- simplecov
54
-
55
- BUNDLED WITH
56
- 1.15.1
@@ -1,13 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- if RUBY_VERSION >= '2.0'
6
- gem "json"
7
- else
8
- gem "json", "~> 1.8.3"
9
- end
10
-
11
- gem "redis", "~> 3.3.2"
12
-
13
- gemspec :path => "../"
@@ -1,13 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- if RUBY_VERSION >= '2.0'
6
- gem "json"
7
- else
8
- gem "json", "~> 1.8.3"
9
- end
10
-
11
- gem "redis", "4.0.0.rc1"
12
-
13
- gemspec :path => "../"