split 1.4.1 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -0
- data/lib/split.rb +1 -0
- data/lib/split/encapsulated_helper.rb +5 -4
- data/lib/split/helper.rb +2 -2
- data/lib/split/trial.rb +1 -0
- data/lib/split/user.rb +24 -0
- data/lib/split/version.rb +1 -1
- data/spec/encapsulated_helper_spec.rb +1 -1
- data/spec/helper_spec.rb +25 -21
- data/spec/spec_helper.rb +5 -1
- data/spec/trial_spec.rb +1 -1
- data/spec/user_spec.rb +42 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eaed323e2d2459412259d82d76e4000c299c1db6
|
4
|
+
data.tar.gz: 54e05592a68ed6285e0ba613dadac52ed79bf23e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a981adeb6a103db7766be39180bd353a31f642c659e4044071fbe8a094f4e36558705b477dd8a4b6eff893b11823209a241c24d5acc8d339201108abb33bf4b0
|
7
|
+
data.tar.gz: 7ca7d69fa815e194f9273974df0da3c556cb186f01720e8b342edd9482814725e4478006581b1878b1fb36f9fa53ed6f900176d3809101785d03bbac80e52f43
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -165,6 +165,8 @@ finished(:experiment_name, reset: false)
|
|
165
165
|
|
166
166
|
The user will then always see the alternative they started with.
|
167
167
|
|
168
|
+
Any old unfinished experiment key will be deleted from the user's data storage if the experiment had been removed or is over and a winner had been chosen. This allows a user to enroll into any new experiment in cases when the `allow_multiple_experiments` config option is set to `false`.
|
169
|
+
|
168
170
|
### Multiple experiments at once
|
169
171
|
|
170
172
|
By default Split will avoid users participating in multiple experiments at once. This means you are less likely to skew results by adding in more variation to your tests.
|
data/lib/split.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
# Split's helper exposes all kinds of methods we don't want to
|
3
3
|
# mix into our model classes.
|
4
4
|
#
|
5
|
-
# This module exposes only two methods
|
6
|
-
# - ab_test
|
7
|
-
# -
|
5
|
+
# This module exposes only two methods:
|
6
|
+
# - ab_test()
|
7
|
+
# - finished()
|
8
8
|
# that can safely be mixed into any class.
|
9
9
|
#
|
10
10
|
# Passes the instance of the class that it's mixed into to the
|
@@ -22,7 +22,7 @@ module Split
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def ab_user
|
25
|
-
@ab_user ||= Split::
|
25
|
+
@ab_user ||= Split::User.new(@context)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -44,6 +44,7 @@ module Split
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def ab_test_finished(*arguments)
|
47
|
+
warn 'DEPRECATION WARNING: ab_test_finished is deprecated and will be removed from Split 1.5.0'
|
47
48
|
split_context_shim.finished *arguments
|
48
49
|
end
|
49
50
|
|
data/lib/split/helper.rb
CHANGED
@@ -6,7 +6,6 @@ module Split
|
|
6
6
|
def ab_test(metric_descriptor, control = nil, *alternatives)
|
7
7
|
begin
|
8
8
|
experiment = ExperimentCatalog.find_or_initialize(metric_descriptor, control, *alternatives)
|
9
|
-
|
10
9
|
alternative = if Split.configuration.enabled
|
11
10
|
experiment.save
|
12
11
|
trial = Trial.new(:user => ab_user, :experiment => experiment,
|
@@ -88,13 +87,14 @@ module Split
|
|
88
87
|
end
|
89
88
|
|
90
89
|
def begin_experiment(experiment, alternative_name = nil)
|
90
|
+
warn 'DEPRECATION WARNING: begin_experiment is deprecated and will be removed from Split 1.5.0'
|
91
91
|
alternative_name ||= experiment.control.name
|
92
92
|
ab_user[experiment.key] = alternative_name
|
93
93
|
alternative_name
|
94
94
|
end
|
95
95
|
|
96
96
|
def ab_user
|
97
|
-
@ab_user ||=
|
97
|
+
@ab_user ||= User.new(self)
|
98
98
|
end
|
99
99
|
|
100
100
|
def exclude_visitor?
|
data/lib/split/trial.rb
CHANGED
@@ -50,6 +50,7 @@ module Split
|
|
50
50
|
# method is guaranteed to only run once, and will skip the alternative choosing process if run
|
51
51
|
# a second time.
|
52
52
|
def choose!(context = nil)
|
53
|
+
@user.cleanup_old_experiments
|
53
54
|
# Only run the process once
|
54
55
|
return alternative if @alternative_choosen
|
55
56
|
|
data/lib/split/user.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Split
|
2
|
+
class User
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators :@user, :keys, :[], :[]=, :delete
|
5
|
+
attr_reader :user
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@user = Split::Persistence.adapter.new(context)
|
9
|
+
end
|
10
|
+
|
11
|
+
def cleanup_old_experiments
|
12
|
+
user.keys.each do |key|
|
13
|
+
experiment = ExperimentCatalog.find key_without_version(key)
|
14
|
+
if experiment.nil? || experiment.has_winner? || experiment.start_time.nil?
|
15
|
+
user.delete key
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def key_without_version(key)
|
21
|
+
key.split(/\:\d(?!\:)/)[0]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/split/version.rb
CHANGED
data/spec/helper_spec.rb
CHANGED
@@ -172,7 +172,7 @@ describe Split::Helper do
|
|
172
172
|
it "should only let a user participate in one experiment at a time" do
|
173
173
|
link_color = ab_test('link_color', 'blue', 'red')
|
174
174
|
ab_test('button_size', 'small', 'big')
|
175
|
-
expect(ab_user).to eq(
|
175
|
+
expect(ab_user['link_color']).to eq(link_color)
|
176
176
|
big = Split::Alternative.new('big', 'button_size')
|
177
177
|
expect(big.participant_count).to eq(0)
|
178
178
|
small = Split::Alternative.new('small', 'button_size')
|
@@ -185,7 +185,8 @@ describe Split::Helper do
|
|
185
185
|
end
|
186
186
|
link_color = ab_test('link_color', 'blue', 'red')
|
187
187
|
button_size = ab_test('button_size', 'small', 'big')
|
188
|
-
expect(ab_user).to eq(
|
188
|
+
expect(ab_user['link_color']).to eq(link_color)
|
189
|
+
expect(ab_user['button_size']).to eq(button_size)
|
189
190
|
button_size_alt = Split::Alternative.new(button_size, 'button_size')
|
190
191
|
expect(button_size_alt.participant_count).to eq(1)
|
191
192
|
end
|
@@ -193,9 +194,9 @@ describe Split::Helper do
|
|
193
194
|
it "should not over-write a finished key when an experiment is on a later version" do
|
194
195
|
experiment.increment_version
|
195
196
|
ab_user = { experiment.key => 'blue', experiment.finished_key => true }
|
196
|
-
|
197
|
+
finished_session = ab_user.dup
|
197
198
|
ab_test('link_color', 'blue', 'red')
|
198
|
-
expect(ab_user).to eq(
|
199
|
+
expect(ab_user).to eq(finished_session)
|
199
200
|
end
|
200
201
|
end
|
201
202
|
|
@@ -247,7 +248,8 @@ describe Split::Helper do
|
|
247
248
|
|
248
249
|
it "should set experiment's finished key if reset is false" do
|
249
250
|
finished(@experiment_name, {:reset => false})
|
250
|
-
expect(ab_user).to eq(@
|
251
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
252
|
+
expect(ab_user[@experiment.finished_key]).to eq(true)
|
251
253
|
end
|
252
254
|
|
253
255
|
it 'should not increment the counter if reset is false and the experiment has been already finished' do
|
@@ -279,30 +281,31 @@ describe Split::Helper do
|
|
279
281
|
end
|
280
282
|
|
281
283
|
it "should clear out the user's participation from their session" do
|
282
|
-
expect(ab_user).to eq(@
|
284
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
283
285
|
finished(@experiment_name)
|
284
|
-
expect(ab_user).to
|
286
|
+
expect(ab_user.keys).to be_empty
|
285
287
|
end
|
286
288
|
|
287
289
|
it "should not clear out the users session if reset is false" do
|
288
|
-
expect(ab_user).to eq(@
|
290
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
289
291
|
finished(@experiment_name, {:reset => false})
|
290
|
-
expect(ab_user).to eq(@
|
292
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
293
|
+
expect(ab_user[@experiment.finished_key]).to eq(true)
|
291
294
|
end
|
292
295
|
|
293
296
|
it "should reset the users session when experiment is not versioned" do
|
294
|
-
expect(ab_user).to eq(@
|
297
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
295
298
|
finished(@experiment_name)
|
296
|
-
expect(ab_user).to
|
299
|
+
expect(ab_user.keys).to be_empty
|
297
300
|
end
|
298
301
|
|
299
302
|
it "should reset the users session when experiment is versioned" do
|
300
303
|
@experiment.increment_version
|
301
304
|
@alternative_name = ab_test(@experiment_name, *@alternatives)
|
302
305
|
|
303
|
-
expect(ab_user).to eq(@
|
306
|
+
expect(ab_user[@experiment.key]).to eq(@alternative_name)
|
304
307
|
finished(@experiment_name)
|
305
|
-
expect(ab_user).to
|
308
|
+
expect(ab_user.keys).to be_empty
|
306
309
|
end
|
307
310
|
|
308
311
|
it "should do nothing where the experiment was not started by this user" do
|
@@ -337,7 +340,8 @@ describe Split::Helper do
|
|
337
340
|
experiment = Split::ExperimentCatalog.find :my_experiment
|
338
341
|
|
339
342
|
finished :my_experiment
|
340
|
-
expect(ab_user).to eq(
|
343
|
+
expect(ab_user[experiment.key]).to eq(alternative)
|
344
|
+
expect(ab_user[experiment.finished_key]).to eq(true)
|
341
345
|
end
|
342
346
|
end
|
343
347
|
|
@@ -618,28 +622,28 @@ describe Split::Helper do
|
|
618
622
|
it "should use version zero if no version is present" do
|
619
623
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
620
624
|
expect(experiment.version).to eq(0)
|
621
|
-
expect(ab_user).to eq(
|
625
|
+
expect(ab_user['link_color']).to eq(alternative_name)
|
622
626
|
end
|
623
627
|
|
624
628
|
it "should save the version of the experiment to the session" do
|
625
629
|
experiment.reset
|
626
630
|
expect(experiment.version).to eq(1)
|
627
631
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
628
|
-
expect(ab_user).to eq(
|
632
|
+
expect(ab_user['link_color:1']).to eq(alternative_name)
|
629
633
|
end
|
630
634
|
|
631
635
|
it "should load the experiment even if the version is not 0" do
|
632
636
|
experiment.reset
|
633
637
|
expect(experiment.version).to eq(1)
|
634
638
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
635
|
-
expect(ab_user).to eq(
|
639
|
+
expect(ab_user['link_color:1']).to eq(alternative_name)
|
636
640
|
return_alternative_name = ab_test('link_color', 'blue', 'red')
|
637
641
|
expect(return_alternative_name).to eq(alternative_name)
|
638
642
|
end
|
639
643
|
|
640
644
|
it "should reset the session of a user on an older version of the experiment" do
|
641
645
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
642
|
-
expect(ab_user).to eq(
|
646
|
+
expect(ab_user['link_color']).to eq(alternative_name)
|
643
647
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
644
648
|
expect(alternative.participant_count).to eq(1)
|
645
649
|
|
@@ -656,7 +660,7 @@ describe Split::Helper do
|
|
656
660
|
|
657
661
|
it "should cleanup old versions of experiments from the session" do
|
658
662
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
659
|
-
expect(ab_user).to eq(
|
663
|
+
expect(ab_user['link_color']).to eq(alternative_name)
|
660
664
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
661
665
|
expect(alternative.participant_count).to eq(1)
|
662
666
|
|
@@ -666,12 +670,12 @@ describe Split::Helper do
|
|
666
670
|
expect(alternative.participant_count).to eq(0)
|
667
671
|
|
668
672
|
new_alternative_name = ab_test('link_color', 'blue', 'red')
|
669
|
-
expect(ab_user).to eq(
|
673
|
+
expect(ab_user['link_color:1']).to eq(new_alternative_name)
|
670
674
|
end
|
671
675
|
|
672
676
|
it "should only count completion of users on the current version" do
|
673
677
|
alternative_name = ab_test('link_color', 'blue', 'red')
|
674
|
-
expect(ab_user).to eq(
|
678
|
+
expect(ab_user['link_color']).to eq(alternative_name)
|
675
679
|
alternative = Split::Alternative.new(alternative_name, 'link_color')
|
676
680
|
|
677
681
|
experiment.reset
|
data/spec/spec_helper.rb
CHANGED
@@ -19,11 +19,15 @@ RSpec.configure do |config|
|
|
19
19
|
config.before(:each) do
|
20
20
|
Split.configuration = Split::Configuration.new
|
21
21
|
Split.redis.flushall
|
22
|
-
@ab_user =
|
22
|
+
@ab_user = mock_user
|
23
23
|
params = nil
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def mock_user
|
28
|
+
Split::User.new(double(session: {}))
|
29
|
+
end
|
30
|
+
|
27
31
|
def session
|
28
32
|
@session ||= {}
|
29
33
|
end
|
data/spec/trial_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
require 'split/trial'
|
4
4
|
|
5
5
|
describe Split::Trial do
|
6
|
-
let(:user) {
|
6
|
+
let(:user) { mock_user }
|
7
7
|
let(:experiment) do
|
8
8
|
Split::Experiment.new('basket_text', :alternatives => ['basket', 'cart']).save
|
9
9
|
end
|
data/spec/user_spec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'split/experiment_catalog'
|
3
|
+
require 'split/experiment'
|
4
|
+
require 'split/user'
|
5
|
+
|
6
|
+
describe Split::User do
|
7
|
+
let(:context) do
|
8
|
+
double(:session => { split: { 'link_color' => 'blue' } })
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@subject = described_class.new(context)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'delegates methods correctly' do
|
16
|
+
expect(@subject['link_color']).to eq(@subject.user['link_color'])
|
17
|
+
end
|
18
|
+
|
19
|
+
context '#cleanup_old_experiments' do
|
20
|
+
let(:experiment) { Split::Experiment.new('link_color') }
|
21
|
+
|
22
|
+
it 'removes key if experiment is not found' do
|
23
|
+
@subject.cleanup_old_experiments
|
24
|
+
expect(@subject.keys).to be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'removes key if experiment has a winner' do
|
28
|
+
allow(Split::ExperimentCatalog).to receive(:find).with('link_color').and_return(experiment)
|
29
|
+
allow(experiment).to receive(:start_time).and_return(Date.today)
|
30
|
+
allow(experiment).to receive(:has_winner?).and_return(true)
|
31
|
+
@subject.cleanup_old_experiments
|
32
|
+
expect(@subject.keys).to be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'removes key if experiment has not started yet' do
|
36
|
+
allow(Split::ExperimentCatalog).to receive(:find).with('link_color').and_return(experiment)
|
37
|
+
allow(experiment).to receive(:has_winner?).and_return(false)
|
38
|
+
@subject.cleanup_old_experiments
|
39
|
+
expect(@subject.keys).to be_empty
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: split
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Nesbitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -203,6 +203,7 @@ files:
|
|
203
203
|
- lib/split/persistence/redis_adapter.rb
|
204
204
|
- lib/split/persistence/session_adapter.rb
|
205
205
|
- lib/split/trial.rb
|
206
|
+
- lib/split/user.rb
|
206
207
|
- lib/split/version.rb
|
207
208
|
- lib/split/zscore.rb
|
208
209
|
- spec/algorithms/weighted_sample_spec.rb
|
@@ -224,6 +225,7 @@ files:
|
|
224
225
|
- spec/spec_helper.rb
|
225
226
|
- spec/support/cookies_mock.rb
|
226
227
|
- spec/trial_spec.rb
|
228
|
+
- spec/user_spec.rb
|
227
229
|
- split.gemspec
|
228
230
|
homepage: https://github.com/splitrb/split
|
229
231
|
licenses:
|
@@ -269,3 +271,4 @@ test_files:
|
|
269
271
|
- spec/spec_helper.rb
|
270
272
|
- spec/support/cookies_mock.rb
|
271
273
|
- spec/trial_spec.rb
|
274
|
+
- spec/user_spec.rb
|