split 4.0.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +8 -3
  3. data/.rubocop.yml +2 -5
  4. data/CHANGELOG.md +38 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +1 -1
  7. data/README.md +11 -3
  8. data/Rakefile +4 -5
  9. data/gemfiles/5.2.gemfile +1 -3
  10. data/gemfiles/6.0.gemfile +1 -3
  11. data/gemfiles/6.1.gemfile +1 -3
  12. data/gemfiles/7.0.gemfile +1 -3
  13. data/lib/split/algorithms/block_randomization.rb +5 -6
  14. data/lib/split/algorithms/whiplash.rb +16 -18
  15. data/lib/split/algorithms.rb +14 -0
  16. data/lib/split/alternative.rb +21 -22
  17. data/lib/split/cache.rb +0 -1
  18. data/lib/split/combined_experiments_helper.rb +4 -4
  19. data/lib/split/configuration.rb +83 -84
  20. data/lib/split/dashboard/helpers.rb +6 -7
  21. data/lib/split/dashboard/pagination_helpers.rb +53 -54
  22. data/lib/split/dashboard/public/style.css +5 -2
  23. data/lib/split/dashboard/views/_experiment.erb +2 -1
  24. data/lib/split/dashboard/views/index.erb +19 -4
  25. data/lib/split/dashboard.rb +29 -23
  26. data/lib/split/encapsulated_helper.rb +4 -6
  27. data/lib/split/experiment.rb +93 -88
  28. data/lib/split/experiment_catalog.rb +6 -5
  29. data/lib/split/extensions/string.rb +1 -1
  30. data/lib/split/goals_collection.rb +8 -10
  31. data/lib/split/helper.rb +20 -20
  32. data/lib/split/metric.rb +4 -5
  33. data/lib/split/persistence/cookie_adapter.rb +44 -47
  34. data/lib/split/persistence/dual_adapter.rb +7 -8
  35. data/lib/split/persistence/redis_adapter.rb +3 -4
  36. data/lib/split/persistence/session_adapter.rb +0 -2
  37. data/lib/split/persistence.rb +4 -4
  38. data/lib/split/redis_interface.rb +7 -1
  39. data/lib/split/trial.rb +23 -24
  40. data/lib/split/user.rb +12 -13
  41. data/lib/split/version.rb +1 -1
  42. data/lib/split/zscore.rb +1 -3
  43. data/lib/split.rb +26 -25
  44. data/spec/algorithms/block_randomization_spec.rb +6 -5
  45. data/spec/algorithms/weighted_sample_spec.rb +6 -5
  46. data/spec/algorithms/whiplash_spec.rb +4 -5
  47. data/spec/alternative_spec.rb +35 -36
  48. data/spec/cache_spec.rb +15 -19
  49. data/spec/combined_experiments_helper_spec.rb +18 -17
  50. data/spec/configuration_spec.rb +32 -38
  51. data/spec/dashboard/pagination_helpers_spec.rb +69 -67
  52. data/spec/dashboard/paginator_spec.rb +10 -9
  53. data/spec/dashboard_helpers_spec.rb +19 -18
  54. data/spec/dashboard_spec.rb +79 -35
  55. data/spec/encapsulated_helper_spec.rb +12 -14
  56. data/spec/experiment_catalog_spec.rb +14 -13
  57. data/spec/experiment_spec.rb +132 -123
  58. data/spec/goals_collection_spec.rb +17 -15
  59. data/spec/helper_spec.rb +415 -382
  60. data/spec/metric_spec.rb +14 -14
  61. data/spec/persistence/cookie_adapter_spec.rb +23 -8
  62. data/spec/persistence/dual_adapter_spec.rb +71 -71
  63. data/spec/persistence/redis_adapter_spec.rb +28 -29
  64. data/spec/persistence/session_adapter_spec.rb +2 -3
  65. data/spec/persistence_spec.rb +1 -2
  66. data/spec/redis_interface_spec.rb +26 -14
  67. data/spec/spec_helper.rb +16 -13
  68. data/spec/split_spec.rb +11 -11
  69. data/spec/support/cookies_mock.rb +1 -2
  70. data/spec/trial_spec.rb +61 -60
  71. data/spec/user_spec.rb +36 -36
  72. data/split.gemspec +21 -20
  73. metadata +25 -14
  74. data/.rubocop_todo.yml +0 -226
  75. data/Appraisals +0 -19
  76. data/gemfiles/5.0.gemfile +0 -9
  77. data/gemfiles/5.1.gemfile +0 -9
data/spec/split_spec.rb CHANGED
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
- require 'spec_helper'
3
2
 
4
- RSpec.describe Split do
3
+ require "spec_helper"
5
4
 
5
+ RSpec.describe Split do
6
6
  around(:each) do |ex|
7
- old_env, old_redis = [ENV.delete('REDIS_URL'), Split.redis]
7
+ old_env, old_redis = [ENV.delete("REDIS_URL"), Split.redis]
8
8
  ex.run
9
- ENV['REDIS_URL'] = old_env
9
+ ENV["REDIS_URL"] = old_env
10
10
  Split.redis = old_redis
11
11
  end
12
12
 
13
- describe '#redis=' do
14
- it 'accepts a url string' do
15
- Split.redis = 'redis://localhost:6379'
13
+ describe "#redis=" do
14
+ it "accepts a url string" do
15
+ Split.redis = "redis://localhost:6379"
16
16
  expect(Split.redis).to be_a(Redis)
17
17
 
18
18
  client = Split.redis.connection
@@ -20,8 +20,8 @@ RSpec.describe Split do
20
20
  expect(client[:port]).to eq(6379)
21
21
  end
22
22
 
23
- it 'accepts an options hash' do
24
- Split.redis = {host: 'localhost', port: 6379, db: 12}
23
+ it "accepts an options hash" do
24
+ Split.redis = { host: "localhost", port: 6379, db: 12 }
25
25
  expect(Split.redis).to be_a(Redis)
26
26
 
27
27
  client = Split.redis.connection
@@ -30,13 +30,13 @@ RSpec.describe Split do
30
30
  expect(client[:db]).to eq(12)
31
31
  end
32
32
 
33
- it 'accepts a valid Redis instance' do
33
+ it "accepts a valid Redis instance" do
34
34
  other_redis = Redis.new(url: "redis://localhost:6379")
35
35
  Split.redis = other_redis
36
36
  expect(Split.redis).to eq(other_redis)
37
37
  end
38
38
 
39
- it 'raises an ArgumentError when server cannot be determined' do
39
+ it "raises an ArgumentError when server cannot be determined" do
40
40
  expect { Split.redis = Object.new }.to raise_error(ArgumentError)
41
41
  end
42
42
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- class CookiesMock
3
2
 
3
+ class CookiesMock
4
4
  def initialize
5
5
  @cookies = {}
6
6
  end
@@ -16,5 +16,4 @@ class CookiesMock
16
16
  def delete(key)
17
17
  @cookies.delete(key)
18
18
  end
19
-
20
19
  end
data/spec/trial_spec.rb CHANGED
@@ -1,54 +1,55 @@
1
1
  # frozen_string_literal: true
2
- require 'spec_helper'
3
- require 'split/trial'
2
+
3
+ require "spec_helper"
4
+ require "split/trial"
4
5
 
5
6
  describe Split::Trial do
6
7
  let(:user) { mock_user }
7
- let(:alternatives) { ['basket', 'cart'] }
8
+ let(:alternatives) { ["basket", "cart"] }
8
9
  let(:experiment) do
9
- Split::Experiment.new('basket_text', :alternatives => alternatives).save
10
+ Split::Experiment.new("basket_text", alternatives: alternatives).save
10
11
  end
11
12
 
12
13
  it "should be initializeable" do
13
- experiment = double('experiment')
14
- alternative = double('alternative', :kind_of? => Split::Alternative)
15
- trial = Split::Trial.new(:experiment => experiment, :alternative => alternative)
14
+ experiment = double("experiment")
15
+ alternative = double("alternative", kind_of?: Split::Alternative)
16
+ trial = Split::Trial.new(experiment: experiment, alternative: alternative)
16
17
  expect(trial.experiment).to eq(experiment)
17
18
  expect(trial.alternative).to eq(alternative)
18
19
  end
19
20
 
20
21
  describe "alternative" do
21
22
  it "should use the alternative if specified" do
22
- alternative = double('alternative', :kind_of? => Split::Alternative)
23
- trial = Split::Trial.new(:experiment => double('experiment'),
24
- :alternative => alternative, :user => user)
23
+ alternative = double("alternative", kind_of?: Split::Alternative)
24
+ trial = Split::Trial.new(experiment: double("experiment"),
25
+ alternative: alternative, user: user)
25
26
  expect(trial).not_to receive(:choose)
26
27
  expect(trial.alternative).to eq(alternative)
27
28
  end
28
29
 
29
30
  it "should load the alternative when the alternative name is set" do
30
- experiment = Split::Experiment.new('basket_text', :alternatives => ['basket', 'cart'])
31
+ experiment = Split::Experiment.new("basket_text", alternatives: ["basket", "cart"])
31
32
  experiment.save
32
33
 
33
- trial = Split::Trial.new(:experiment => experiment, :alternative => 'basket')
34
- expect(trial.alternative.name).to eq('basket')
34
+ trial = Split::Trial.new(experiment: experiment, alternative: "basket")
35
+ expect(trial.alternative.name).to eq("basket")
35
36
  end
36
37
  end
37
38
 
38
39
  describe "metadata" do
39
40
  let(:metadata) { Hash[alternatives.map { |k| [k, "Metadata for #{k}"] }] }
40
41
  let(:experiment) do
41
- Split::Experiment.new('basket_text', :alternatives => alternatives, :metadata => metadata).save
42
+ Split::Experiment.new("basket_text", alternatives: alternatives, metadata: metadata).save
42
43
  end
43
44
 
44
- it 'has metadata on each trial' do
45
- trial = Split::Trial.new(:experiment => experiment, :user => user, :metadata => metadata['cart'],
46
- :override => 'cart')
47
- expect(trial.metadata).to eq(metadata['cart'])
45
+ it "has metadata on each trial" do
46
+ trial = Split::Trial.new(experiment: experiment, user: user, metadata: metadata["cart"],
47
+ override: "cart")
48
+ expect(trial.metadata).to eq(metadata["cart"])
48
49
  end
49
50
 
50
- it 'has metadata on each trial from the experiment' do
51
- trial = Split::Trial.new(:experiment => experiment, :user => user)
51
+ it "has metadata on each trial from the experiment" do
52
+ trial = Split::Trial.new(experiment: experiment, user: user)
52
53
  trial.choose!
53
54
  expect(trial.metadata).to eq(metadata[trial.alternative.name])
54
55
  expect(trial.metadata).to match(/#{trial.alternative.name}/)
@@ -56,24 +57,24 @@ describe Split::Trial do
56
57
  end
57
58
 
58
59
  describe "#choose!" do
59
- let(:context) { double(on_trial_callback: 'test callback') }
60
+ let(:context) { double(on_trial_callback: "test callback") }
60
61
  let(:trial) do
61
- Split::Trial.new(:user => user, :experiment => experiment)
62
+ Split::Trial.new(user: user, experiment: experiment)
62
63
  end
63
64
 
64
- shared_examples_for 'a trial with callbacks' do
65
- it 'does not run if on_trial callback is not respondable' do
65
+ shared_examples_for "a trial with callbacks" do
66
+ it "does not run if on_trial callback is not respondable" do
66
67
  Split.configuration.on_trial = :foo
67
68
  allow(context).to receive(:respond_to?).with(:foo, true).and_return false
68
69
  expect(context).to_not receive(:foo)
69
70
  trial.choose! context
70
71
  end
71
- it 'runs on_trial callback' do
72
+ it "runs on_trial callback" do
72
73
  Split.configuration.on_trial = :on_trial_callback
73
74
  expect(context).to receive(:on_trial_callback)
74
75
  trial.choose! context
75
76
  end
76
- it 'does not run nil on_trial callback' do
77
+ it "does not run nil on_trial callback" do
77
78
  Split.configuration.on_trial = nil
78
79
  expect(context).not_to receive(:on_trial_callback)
79
80
  trial.choose! context
@@ -88,12 +89,12 @@ describe Split::Trial do
88
89
  end
89
90
 
90
91
  context "when override is present" do
91
- let(:override) { 'cart' }
92
+ let(:override) { "cart" }
92
93
  let(:trial) do
93
- Split::Trial.new(:user => user, :experiment => experiment, :override => override)
94
+ Split::Trial.new(user: user, experiment: experiment, override: override)
94
95
  end
95
96
 
96
- it_behaves_like 'a trial with callbacks'
97
+ it_behaves_like "a trial with callbacks"
97
98
 
98
99
  it "picks the override" do
99
100
  expect(experiment).to_not receive(:next_alternative)
@@ -102,7 +103,7 @@ describe Split::Trial do
102
103
 
103
104
  context "when alternative doesn't exist" do
104
105
  let(:override) { nil }
105
- it 'falls back on next_alternative' do
106
+ it "falls back on next_alternative" do
106
107
  expect(experiment).to receive(:next_alternative).and_call_original
107
108
  expect_alternative(trial, alternatives)
108
109
  end
@@ -111,7 +112,7 @@ describe Split::Trial do
111
112
 
112
113
  context "when disabled option is true" do
113
114
  let(:trial) do
114
- Split::Trial.new(:user => user, :experiment => experiment, :disabled => true)
115
+ Split::Trial.new(user: user, experiment: experiment, disabled: true)
115
116
  end
116
117
 
117
118
  it "picks the control", :aggregate_failures do
@@ -120,7 +121,7 @@ describe Split::Trial do
120
121
 
121
122
  expect(context).not_to receive(:on_trial_callback)
122
123
 
123
- expect_alternative(trial, 'basket')
124
+ expect_alternative(trial, "basket")
124
125
  Split.configuration.on_trial = nil
125
126
  end
126
127
  end
@@ -132,7 +133,7 @@ describe Split::Trial do
132
133
 
133
134
  expect(experiment).to_not receive(:next_alternative)
134
135
  expect(context).not_to receive(:on_trial_callback)
135
- expect_alternative(trial, 'basket')
136
+ expect_alternative(trial, "basket")
136
137
 
137
138
  Split.configuration.enabled = true
138
139
  Split.configuration.on_trial = nil
@@ -141,45 +142,45 @@ describe Split::Trial do
141
142
 
142
143
  context "when experiment has winner" do
143
144
  let(:trial) do
144
- Split::Trial.new(:user => user, :experiment => experiment)
145
+ Split::Trial.new(user: user, experiment: experiment)
145
146
  end
146
147
 
147
- it_behaves_like 'a trial with callbacks'
148
+ it_behaves_like "a trial with callbacks"
148
149
 
149
150
  it "picks the winner" do
150
- experiment.winner = 'cart'
151
+ experiment.winner = "cart"
151
152
  expect(experiment).to_not receive(:next_alternative)
152
153
 
153
- expect_alternative(trial, 'cart')
154
+ expect_alternative(trial, "cart")
154
155
  end
155
156
  end
156
157
 
157
158
  context "when exclude is true" do
158
159
  let(:trial) do
159
- Split::Trial.new(:user => user, :experiment => experiment, :exclude => true)
160
+ Split::Trial.new(user: user, experiment: experiment, exclude: true)
160
161
  end
161
162
 
162
- it_behaves_like 'a trial with callbacks'
163
+ it_behaves_like "a trial with callbacks"
163
164
 
164
165
  it "picks the control" do
165
166
  expect(experiment).to_not receive(:next_alternative)
166
- expect_alternative(trial, 'basket')
167
+ expect_alternative(trial, "basket")
167
168
  end
168
169
  end
169
170
 
170
171
  context "when user is already participating" do
171
- it_behaves_like 'a trial with callbacks'
172
+ it_behaves_like "a trial with callbacks"
172
173
 
173
174
  it "picks the same alternative" do
174
- user[experiment.key] = 'basket'
175
+ user[experiment.key] = "basket"
175
176
  expect(experiment).to_not receive(:next_alternative)
176
177
 
177
- expect_alternative(trial, 'basket')
178
+ expect_alternative(trial, "basket")
178
179
  end
179
180
 
180
181
  context "when alternative is not found" do
181
182
  it "falls back on next_alternative" do
182
- user[experiment.key] = 'notfound'
183
+ user[experiment.key] = "notfound"
183
184
  expect(experiment).to receive(:next_alternative).and_call_original
184
185
  expect_alternative(trial, alternatives)
185
186
  end
@@ -213,7 +214,7 @@ describe Split::Trial do
213
214
 
214
215
  expect(experiment).to_not receive(:next_alternative)
215
216
  expect(context).not_to receive(:on_trial_callback)
216
- expect_alternative(trial, 'basket')
217
+ expect_alternative(trial, "basket")
217
218
 
218
219
  Split.configuration.enabled = true
219
220
  Split.configuration.on_trial = nil
@@ -229,9 +230,9 @@ describe Split::Trial do
229
230
  end
230
231
 
231
232
  describe "#complete!" do
232
- context 'when there are no goals' do
233
- let(:trial) { Split::Trial.new(:user => user, :experiment => experiment) }
234
- it 'should complete the trial' do
233
+ context "when there are no goals" do
234
+ let(:trial) { Split::Trial.new(user: user, experiment: experiment) }
235
+ it "should complete the trial" do
235
236
  trial.choose!
236
237
  old_completed_count = trial.alternative.completed_count
237
238
  trial.complete!
@@ -241,11 +242,11 @@ describe Split::Trial do
241
242
 
242
243
  context "when there are many goals" do
243
244
  let(:goals) { [ "goal1", "goal2" ] }
244
- let(:trial) { Split::Trial.new(:user => user, :experiment => experiment, :goals => goals) }
245
+ let(:trial) { Split::Trial.new(user: user, experiment: experiment, goals: goals) }
245
246
 
246
247
  it "increments the completed count corresponding to the goals" do
247
248
  trial.choose!
248
- old_completed_counts = goals.map{ |goal| [goal, trial.alternative.completed_count(goal)] }.to_h
249
+ old_completed_counts = goals.map { |goal| [goal, trial.alternative.completed_count(goal)] }.to_h
249
250
  trial.complete!
250
251
  goals.each { | goal | expect(trial.alternative.completed_count(goal)).to eq(old_completed_counts[goal] + 1) }
251
252
  end
@@ -253,7 +254,7 @@ describe Split::Trial do
253
254
 
254
255
  context "when there is 1 goal of type string" do
255
256
  let(:goal) { "goal" }
256
- let(:trial) { Split::Trial.new(:user => user, :experiment => experiment, :goals => goal) }
257
+ let(:trial) { Split::Trial.new(user: user, experiment: experiment, goals: goal) }
257
258
  it "increments the completed count corresponding to the goal" do
258
259
  trial.choose!
259
260
  old_completed_count = trial.alternative.completed_count(goal)
@@ -268,7 +269,7 @@ describe Split::Trial do
268
269
 
269
270
  context "when override is present" do
270
271
  it "stores when store_override is true" do
271
- trial = Split::Trial.new(:user => user, :experiment => experiment, :override => 'basket')
272
+ trial = Split::Trial.new(user: user, experiment: experiment, override: "basket")
272
273
 
273
274
  Split.configuration.store_override = true
274
275
  expect(user).to receive("[]=")
@@ -277,7 +278,7 @@ describe Split::Trial do
277
278
  end
278
279
 
279
280
  it "does not store when store_override is false" do
280
- trial = Split::Trial.new(:user => user, :experiment => experiment, :override => 'basket')
281
+ trial = Split::Trial.new(user: user, experiment: experiment, override: "basket")
281
282
 
282
283
  expect(user).to_not receive("[]=")
283
284
  trial.choose!
@@ -286,7 +287,7 @@ describe Split::Trial do
286
287
 
287
288
  context "when disabled is present" do
288
289
  it "stores when store_override is true" do
289
- trial = Split::Trial.new(:user => user, :experiment => experiment, :disabled => true)
290
+ trial = Split::Trial.new(user: user, experiment: experiment, disabled: true)
290
291
 
291
292
  Split.configuration.store_override = true
292
293
  expect(user).to receive("[]=")
@@ -294,7 +295,7 @@ describe Split::Trial do
294
295
  end
295
296
 
296
297
  it "does not store when store_override is false" do
297
- trial = Split::Trial.new(:user => user, :experiment => experiment, :disabled => true)
298
+ trial = Split::Trial.new(user: user, experiment: experiment, disabled: true)
298
299
 
299
300
  expect(user).to_not receive("[]=")
300
301
  trial.choose!
@@ -303,20 +304,20 @@ describe Split::Trial do
303
304
 
304
305
  context "when exclude is present" do
305
306
  it "does not store" do
306
- trial = Split::Trial.new(:user => user, :experiment => experiment, :exclude => true)
307
+ trial = Split::Trial.new(user: user, experiment: experiment, exclude: true)
307
308
 
308
309
  expect(user).to_not receive("[]=")
309
310
  trial.choose!
310
311
  end
311
312
  end
312
313
 
313
- context 'when experiment has winner' do
314
+ context "when experiment has winner" do
314
315
  let(:trial) do
315
- experiment.winner = 'cart'
316
- Split::Trial.new(:user => user, :experiment => experiment)
316
+ experiment.winner = "cart"
317
+ Split::Trial.new(user: user, experiment: experiment)
317
318
  end
318
319
 
319
- it 'does not store' do
320
+ it "does not store" do
320
321
  expect(user).to_not receive("[]=")
321
322
  trial.choose!
322
323
  end
data/spec/user_spec.rb CHANGED
@@ -1,71 +1,73 @@
1
- require 'spec_helper'
2
- require 'split/experiment_catalog'
3
- require 'split/experiment'
4
- require 'split/user'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "split/experiment_catalog"
5
+ require "split/experiment"
6
+ require "split/user"
5
7
 
6
8
  describe Split::User do
7
- let(:user_keys) { { 'link_color' => 'blue' } }
8
- let(:context) { double(:session => { split: user_keys }) }
9
- let(:experiment) { Split::Experiment.new('link_color') }
9
+ let(:user_keys) { { "link_color" => "blue" } }
10
+ let(:context) { double(session: { split: user_keys }) }
11
+ let(:experiment) { Split::Experiment.new("link_color") }
10
12
 
11
13
  before(:each) do
12
14
  @subject = described_class.new(context)
13
15
  end
14
16
 
15
- it 'delegates methods correctly' do
16
- expect(@subject['link_color']).to eq(@subject.user['link_color'])
17
+ it "delegates methods correctly" do
18
+ expect(@subject["link_color"]).to eq(@subject.user["link_color"])
17
19
  end
18
20
 
19
- context '#cleanup_old_versions!' do
21
+ context "#cleanup_old_versions!" do
20
22
  let(:experiment_version) { "#{experiment.name}:1" }
21
23
  let(:second_experiment_version) { "#{experiment.name}_another:1" }
22
24
  let(:third_experiment_version) { "variation_of_#{experiment.name}:1" }
23
25
  let(:user_keys) do
24
26
  {
25
- experiment_version => 'blue',
26
- second_experiment_version => 'red',
27
- third_experiment_version => 'yellow'
27
+ experiment_version => "blue",
28
+ second_experiment_version => "red",
29
+ third_experiment_version => "yellow"
28
30
  }
29
31
  end
30
32
 
31
33
  before(:each) { @subject.cleanup_old_versions!(experiment) }
32
34
 
33
- it 'removes key if old experiment is found' do
35
+ it "removes key if old experiment is found" do
34
36
  expect(@subject.keys).not_to include(experiment_version)
35
37
  end
36
38
 
37
- it 'does not remove other keys' do
39
+ it "does not remove other keys" do
38
40
  expect(@subject.keys).to include(second_experiment_version, third_experiment_version)
39
41
  end
40
- end
42
+ end
41
43
 
42
- context '#cleanup_old_experiments!' do
43
- it 'removes key if experiment is not found' do
44
+ context "#cleanup_old_experiments!" do
45
+ it "removes key if experiment is not found" do
44
46
  @subject.cleanup_old_experiments!
45
47
  expect(@subject.keys).to be_empty
46
48
  end
47
49
 
48
- it 'removes key if experiment has a winner' do
49
- allow(Split::ExperimentCatalog).to receive(:find).with('link_color').and_return(experiment)
50
+ it "removes key if experiment has a winner" do
51
+ allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
50
52
  allow(experiment).to receive(:start_time).and_return(Date.today)
51
53
  allow(experiment).to receive(:has_winner?).and_return(true)
52
54
  @subject.cleanup_old_experiments!
53
55
  expect(@subject.keys).to be_empty
54
56
  end
55
57
 
56
- it 'removes key if experiment has not started yet' do
57
- allow(Split::ExperimentCatalog).to receive(:find).with('link_color').and_return(experiment)
58
+ it "removes key if experiment has not started yet" do
59
+ allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
58
60
  allow(experiment).to receive(:has_winner?).and_return(false)
59
61
  @subject.cleanup_old_experiments!
60
62
  expect(@subject.keys).to be_empty
61
63
  end
62
64
 
63
- context 'with finished key' do
64
- let(:user_keys) { { 'link_color' => 'blue', 'link_color:finished' => true } }
65
+ context "with finished key" do
66
+ let(:user_keys) { { "link_color" => "blue", "link_color:finished" => true } }
65
67
 
66
- it 'does not remove finished key for experiment without a winner' do
67
- allow(Split::ExperimentCatalog).to receive(:find).with('link_color').and_return(experiment)
68
- allow(Split::ExperimentCatalog).to receive(:find).with('link_color:finished').and_return(nil)
68
+ it "does not remove finished key for experiment without a winner" do
69
+ allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
70
+ allow(Split::ExperimentCatalog).to receive(:find).with("link_color:finished").and_return(nil)
69
71
  allow(experiment).to receive(:start_time).and_return(Date.today)
70
72
  allow(experiment).to receive(:has_winner?).and_return(false)
71
73
  @subject.cleanup_old_experiments!
@@ -74,33 +76,32 @@ describe Split::User do
74
76
  end
75
77
  end
76
78
 
77
- context 'when already cleaned up' do
79
+ context "when already cleaned up" do
78
80
  before do
79
81
  @subject.cleanup_old_experiments!
80
82
  end
81
83
 
82
- it 'does not clean up again' do
84
+ it "does not clean up again" do
83
85
  expect(@subject).to_not receive(:keys_without_finished)
84
86
  @subject.cleanup_old_experiments!
85
87
  end
86
88
  end
87
89
  end
88
90
 
89
- context 'allows user to be loaded from adapter' do
90
- it 'loads user from adapter (RedisAdapter)' do
91
+ context "allows user to be loaded from adapter" do
92
+ it "loads user from adapter (RedisAdapter)" do
91
93
  user = Split::Persistence::RedisAdapter.new(nil, 112233)
92
- user['foo'] = 'bar'
94
+ user["foo"] = "bar"
93
95
 
94
96
  ab_user = Split::User.find(112233, :redis)
95
97
 
96
- expect(ab_user['foo']).to eql('bar')
98
+ expect(ab_user["foo"]).to eql("bar")
97
99
  end
98
100
 
99
- it 'returns nil if adapter does not implement a finder method' do
101
+ it "returns nil if adapter does not implement a finder method" do
100
102
  ab_user = Split::User.find(112233, :dual_adapter)
101
103
  expect(ab_user).to be_nil
102
104
  end
103
-
104
105
  end
105
106
 
106
107
  context "instantiated with custom adapter" do
@@ -114,5 +115,4 @@ describe Split::User do
114
115
  expect(@subject.user).to eq(custom_adapter)
115
116
  end
116
117
  end
117
-
118
118
  end
data/split.gemspec CHANGED
@@ -9,36 +9,37 @@ Gem::Specification.new do |s|
9
9
  s.version = Split::VERSION
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = ["Andrew Nesbitt"]
12
- s.licenses = ['MIT']
12
+ s.licenses = ["MIT"]
13
13
  s.email = ["andrewnez@gmail.com"]
14
14
  s.homepage = "https://github.com/splitrb/split"
15
15
  s.summary = "Rack based split testing framework"
16
16
 
17
17
  s.metadata = {
18
- "homepage_uri" => "https://github.com/splitrb/split",
19
- "changelog_uri" => "https://github.com/splitrb/split/blob/master/CHANGELOG.md",
20
- "source_code_uri" => "https://github.com/splitrb/split",
21
- "bug_tracker_uri" => "https://github.com/splitrb/split/issues",
22
- "wiki_uri" => "https://github.com/splitrb/split/wiki",
23
- "mailing_list_uri" => "https://groups.google.com/d/forum/split-ruby"
24
- }
18
+ "homepage_uri" => "https://github.com/splitrb/split",
19
+ "changelog_uri" => "https://github.com/splitrb/split/blob/main/CHANGELOG.md",
20
+ "source_code_uri" => "https://github.com/splitrb/split",
21
+ "bug_tracker_uri" => "https://github.com/splitrb/split/issues",
22
+ "wiki_uri" => "https://github.com/splitrb/split/wiki",
23
+ "mailing_list_uri" => "https://groups.google.com/d/forum/split-ruby"
24
+ }
25
25
 
26
- s.required_ruby_version = '>= 2.5.0'
27
- s.required_rubygems_version = '>= 2.0.0'
26
+ s.required_ruby_version = ">= 2.5.0"
27
+ s.required_rubygems_version = ">= 2.0.0"
28
28
 
29
29
  s.files = `git ls-files`.split("\n")
30
30
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
31
31
  s.require_paths = ["lib"]
32
32
 
33
- s.add_dependency 'redis', '>= 4.2'
34
- s.add_dependency 'sinatra', '>= 1.2.6'
35
- s.add_dependency 'rubystats', '>= 0.3.0'
33
+ s.add_dependency "redis", ">= 4.2"
34
+ s.add_dependency "sinatra", ">= 1.2.6"
35
+ s.add_dependency "rubystats", ">= 0.3.0"
36
+ s.add_dependency "matrix"
36
37
 
37
- s.add_development_dependency 'bundler', '>= 1.17'
38
- s.add_development_dependency 'simplecov', '~> 0.15'
39
- s.add_development_dependency 'rack-test', '~> 1.1'
40
- s.add_development_dependency 'rake', '~> 13'
41
- s.add_development_dependency 'rspec', '~> 3.7'
42
- s.add_development_dependency 'pry', '~> 0.10'
43
- s.add_development_dependency 'rails', '>= 5.0'
38
+ s.add_development_dependency "bundler", ">= 1.17"
39
+ s.add_development_dependency "simplecov", "~> 0.15"
40
+ s.add_development_dependency "rack-test", "~> 2.0"
41
+ s.add_development_dependency "rake", "~> 13"
42
+ s.add_development_dependency "rspec", "~> 3.7"
43
+ s.add_development_dependency "pry", "~> 0.10"
44
+ s.add_development_dependency "rails", ">= 5.0"
44
45
  end