split 1.4.1 → 1.4.2
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 +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
|