split 0.4.6 → 0.5.0
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.
- data/.travis.yml +11 -3
- data/CHANGELOG.mdown +22 -1
- data/CONTRIBUTING.md +10 -0
- data/LICENSE +1 -1
- data/README.mdown +235 -60
- data/lib/split.rb +8 -9
- data/lib/split/algorithms.rb +3 -0
- data/lib/split/algorithms/weighted_sample.rb +17 -0
- data/lib/split/algorithms/whiplash.rb +35 -0
- data/lib/split/alternative.rb +12 -4
- data/lib/split/configuration.rb +91 -1
- data/lib/split/dashboard/helpers.rb +3 -3
- data/lib/split/dashboard/views/_experiment.erb +1 -1
- data/lib/split/exceptions.rb +4 -0
- data/lib/split/experiment.rb +112 -24
- data/lib/split/extensions.rb +3 -0
- data/lib/split/extensions/array.rb +4 -0
- data/lib/split/extensions/string.rb +15 -0
- data/lib/split/helper.rb +87 -55
- data/lib/split/metric.rb +68 -0
- data/lib/split/persistence.rb +28 -0
- data/lib/split/persistence/cookie_adapter.rb +44 -0
- data/lib/split/persistence/session_adapter.rb +28 -0
- data/lib/split/trial.rb +43 -0
- data/lib/split/version.rb +3 -3
- data/spec/algorithms/weighted_sample_spec.rb +18 -0
- data/spec/algorithms/whiplash_spec.rb +23 -0
- data/spec/alternative_spec.rb +81 -9
- data/spec/configuration_spec.rb +61 -9
- data/spec/dashboard_helpers_spec.rb +2 -5
- data/spec/dashboard_spec.rb +0 -2
- data/spec/experiment_spec.rb +144 -74
- data/spec/helper_spec.rb +234 -29
- data/spec/metric_spec.rb +30 -0
- data/spec/persistence/cookie_adapter_spec.rb +31 -0
- data/spec/persistence/session_adapter_spec.rb +31 -0
- data/spec/persistence_spec.rb +33 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/cookies_mock.rb +19 -0
- data/spec/trial_spec.rb +59 -0
- data/split.gemspec +7 -3
- metadata +58 -29
- data/Guardfile +0 -5
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Split::Persistence::SessionAdapter do
|
4
|
+
|
5
|
+
let(:context) { mock(:session => {}) }
|
6
|
+
subject { Split::Persistence::SessionAdapter.new(context) }
|
7
|
+
|
8
|
+
describe "#[] and #[]=" do
|
9
|
+
it "should set and return the value for given key" do
|
10
|
+
subject["my_key"] = "my_value"
|
11
|
+
subject["my_key"].should eq("my_value")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#delete" do
|
16
|
+
it "should delete the given key" do
|
17
|
+
subject["my_key"] = "my_value"
|
18
|
+
subject.delete("my_key")
|
19
|
+
subject["my_key"].should be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#keys" do
|
24
|
+
it "should return an array of the session's stored keys" do
|
25
|
+
subject["my_key"] = "my_value"
|
26
|
+
subject["my_second_key"] = "my_second_value"
|
27
|
+
subject.keys.should =~ ["my_key", "my_second_key"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Split::Persistence do
|
4
|
+
|
5
|
+
subject { Split::Persistence }
|
6
|
+
|
7
|
+
describe ".adapter" do
|
8
|
+
context "when the persistence config is a symbol" do
|
9
|
+
it "should return the appropriate adapter for the symbol" do
|
10
|
+
Split.configuration.stub(:persistence).and_return(:cookie)
|
11
|
+
subject.adapter.should eq(Split::Persistence::CookieAdapter)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return an adapter whose class is present in Split::Persistence::ADAPTERS" do
|
15
|
+
Split.configuration.stub(:persistence).and_return(:cookie)
|
16
|
+
Split::Persistence::ADAPTERS.values.should include(subject.adapter)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should raise if the adapter cannot be found" do
|
20
|
+
Split.configuration.stub(:persistence).and_return(:something_weird)
|
21
|
+
expect { subject.adapter }.to raise_error(Split::InvalidPersistenceAdapterError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
context "when the persistence config is a class" do
|
25
|
+
let(:custom_adapter_class) { MyCustomAdapterClass = Class.new }
|
26
|
+
it "should return that class" do
|
27
|
+
Split.configuration.stub(:persistence).and_return(custom_adapter_class)
|
28
|
+
subject.adapter.should eq(MyCustomAdapterClass)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,6 +6,18 @@ require 'split'
|
|
6
6
|
require 'ostruct'
|
7
7
|
require 'complex' if RUBY_VERSION.match(/1\.8/)
|
8
8
|
|
9
|
+
Dir['./spec/support/*.rb'].each { |f| require f }
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.order = 'random'
|
13
|
+
config.before(:each) do
|
14
|
+
Split.configuration = Split::Configuration.new
|
15
|
+
Split.redis.flushall
|
16
|
+
@ab_user = {}
|
17
|
+
params = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
9
21
|
def session
|
10
22
|
@session ||= {}
|
11
23
|
end
|
data/spec/trial_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'split/trial'
|
3
|
+
|
4
|
+
describe Split::Trial do
|
5
|
+
it "should be initializeable" do
|
6
|
+
experiment = mock('experiment')
|
7
|
+
alternative = mock('alternative')
|
8
|
+
trial = Split::Trial.new(:experiment => experiment, :alternative => alternative)
|
9
|
+
trial.experiment.should == experiment
|
10
|
+
trial.alternative.should == alternative
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "alternative" do
|
14
|
+
it "should use the alternative if specified" do
|
15
|
+
trial = Split::Trial.new(:experiment => experiment = mock('experiment'), :alternative => alternative = mock('alternative'))
|
16
|
+
trial.should_not_receive(:choose)
|
17
|
+
trial.alternative.should == alternative
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should populate alternative with a full alternative object after calling choose" do
|
21
|
+
experiment = Split::Experiment.new('basket_text', :alternative_names => ['basket', 'cart'])
|
22
|
+
experiment.save
|
23
|
+
trial = Split::Trial.new(:experiment => experiment)
|
24
|
+
trial.choose
|
25
|
+
trial.alternative.class.should == Split::Alternative
|
26
|
+
['basket', 'cart'].should include(trial.alternative.name)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should populate an alternative when only one option is offerred" do
|
30
|
+
experiment = Split::Experiment.new('basket_text', :alternative_names => ['basket'])
|
31
|
+
experiment.save
|
32
|
+
trial = Split::Trial.new(:experiment => experiment)
|
33
|
+
trial.choose
|
34
|
+
trial.alternative.class.should == Split::Alternative
|
35
|
+
trial.alternative.name.should == 'basket'
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
it "should choose from the available alternatives" do
|
40
|
+
trial = Split::Trial.new(:experiment => experiment = mock('experiment'))
|
41
|
+
experiment.should_receive(:next_alternative).and_return(alternative = mock('alternative'))
|
42
|
+
alternative.should_receive(:increment_participation)
|
43
|
+
experiment.should_receive(:winner).and_return nil
|
44
|
+
trial.choose!
|
45
|
+
|
46
|
+
trial.alternative.should == alternative
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "alternative_name" do
|
51
|
+
it "should load the alternative when the alternative name is set" do
|
52
|
+
experiment = Split::Experiment.new('basket_text', :alternative_names => ['basket', "cart"])
|
53
|
+
experiment.save
|
54
|
+
|
55
|
+
trial = Split::Trial.new(:experiment => experiment, :alternative_name => 'basket')
|
56
|
+
trial.alternative.name.should == 'basket'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/split.gemspec
CHANGED
@@ -15,16 +15,20 @@ Gem::Specification.new do |s|
|
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
18
|
s.require_paths = ["lib"]
|
20
19
|
|
21
20
|
s.add_dependency 'redis', '>= 2.1'
|
22
21
|
s.add_dependency 'redis-namespace', '>= 1.1.0'
|
23
22
|
s.add_dependency 'sinatra', '>= 1.2.6'
|
23
|
+
s.add_dependency 'simple-random'
|
24
|
+
|
25
|
+
# Ruby 1.8 doesn't include JSON in the std lib
|
26
|
+
if RUBY_VERSION < "1.9"
|
27
|
+
s.add_dependency 'json', '>= 1.7.5'
|
28
|
+
end
|
24
29
|
|
25
30
|
s.add_development_dependency 'rake'
|
26
31
|
s.add_development_dependency 'bundler', '~> 1.0'
|
27
|
-
s.add_development_dependency 'rspec', '~> 2.
|
32
|
+
s.add_development_dependency 'rspec', '~> 2.12'
|
28
33
|
s.add_development_dependency 'rack-test', '~> 0.6'
|
29
|
-
s.add_development_dependency 'guard-rspec', '~> 1.2'
|
30
34
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: split
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70342380332380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70342380332380
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redis-namespace
|
27
|
-
requirement: &
|
27
|
+
requirement: &70342380331880 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.1.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70342380331880
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sinatra
|
38
|
-
requirement: &
|
38
|
+
requirement: &70342380331420 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: 1.2.6
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70342380331420
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: simple-random
|
49
|
+
requirement: &70342380331040 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70342380331040
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rake
|
49
|
-
requirement: &
|
60
|
+
requirement: &70342380330560 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *70342380330560
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: bundler
|
60
|
-
requirement: &
|
71
|
+
requirement: &70342380330060 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ~>
|
@@ -65,21 +76,21 @@ dependencies:
|
|
65
76
|
version: '1.0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *70342380330060
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: rspec
|
71
|
-
requirement: &
|
82
|
+
requirement: &70342380329560 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ~>
|
75
86
|
- !ruby/object:Gem::Version
|
76
|
-
version: '2.
|
87
|
+
version: '2.12'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *70342380329560
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: rack-test
|
82
|
-
requirement: &
|
93
|
+
requirement: &70342380329100 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ~>
|
@@ -87,18 +98,7 @@ dependencies:
|
|
87
98
|
version: '0.6'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
91
|
-
- !ruby/object:Gem::Dependency
|
92
|
-
name: guard-rspec
|
93
|
-
requirement: &70093447018620 !ruby/object:Gem::Requirement
|
94
|
-
none: false
|
95
|
-
requirements:
|
96
|
-
- - ~>
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version: '1.2'
|
99
|
-
type: :development
|
100
|
-
prerelease: false
|
101
|
-
version_requirements: *70093447018620
|
101
|
+
version_requirements: *70342380329100
|
102
102
|
description:
|
103
103
|
email:
|
104
104
|
- andrewnez@gmail.com
|
@@ -109,12 +109,15 @@ files:
|
|
109
109
|
- .gitignore
|
110
110
|
- .travis.yml
|
111
111
|
- CHANGELOG.mdown
|
112
|
+
- CONTRIBUTING.md
|
112
113
|
- Gemfile
|
113
|
-
- Guardfile
|
114
114
|
- LICENSE
|
115
115
|
- README.mdown
|
116
116
|
- Rakefile
|
117
117
|
- lib/split.rb
|
118
|
+
- lib/split/algorithms.rb
|
119
|
+
- lib/split/algorithms/weighted_sample.rb
|
120
|
+
- lib/split/algorithms/whiplash.rb
|
118
121
|
- lib/split/alternative.rb
|
119
122
|
- lib/split/configuration.rb
|
120
123
|
- lib/split/dashboard.rb
|
@@ -126,16 +129,33 @@ files:
|
|
126
129
|
- lib/split/dashboard/views/index.erb
|
127
130
|
- lib/split/dashboard/views/layout.erb
|
128
131
|
- lib/split/engine.rb
|
132
|
+
- lib/split/exceptions.rb
|
129
133
|
- lib/split/experiment.rb
|
134
|
+
- lib/split/extensions.rb
|
135
|
+
- lib/split/extensions/array.rb
|
136
|
+
- lib/split/extensions/string.rb
|
130
137
|
- lib/split/helper.rb
|
138
|
+
- lib/split/metric.rb
|
139
|
+
- lib/split/persistence.rb
|
140
|
+
- lib/split/persistence/cookie_adapter.rb
|
141
|
+
- lib/split/persistence/session_adapter.rb
|
142
|
+
- lib/split/trial.rb
|
131
143
|
- lib/split/version.rb
|
144
|
+
- spec/algorithms/weighted_sample_spec.rb
|
145
|
+
- spec/algorithms/whiplash_spec.rb
|
132
146
|
- spec/alternative_spec.rb
|
133
147
|
- spec/configuration_spec.rb
|
134
148
|
- spec/dashboard_helpers_spec.rb
|
135
149
|
- spec/dashboard_spec.rb
|
136
150
|
- spec/experiment_spec.rb
|
137
151
|
- spec/helper_spec.rb
|
152
|
+
- spec/metric_spec.rb
|
153
|
+
- spec/persistence/cookie_adapter_spec.rb
|
154
|
+
- spec/persistence/session_adapter_spec.rb
|
155
|
+
- spec/persistence_spec.rb
|
138
156
|
- spec/spec_helper.rb
|
157
|
+
- spec/support/cookies_mock.rb
|
158
|
+
- spec/trial_spec.rb
|
139
159
|
- split.gemspec
|
140
160
|
homepage: https://github.com/andrew/split
|
141
161
|
licenses: []
|
@@ -162,10 +182,19 @@ signing_key:
|
|
162
182
|
specification_version: 3
|
163
183
|
summary: Rack based split testing framework
|
164
184
|
test_files:
|
185
|
+
- spec/algorithms/weighted_sample_spec.rb
|
186
|
+
- spec/algorithms/whiplash_spec.rb
|
165
187
|
- spec/alternative_spec.rb
|
166
188
|
- spec/configuration_spec.rb
|
167
189
|
- spec/dashboard_helpers_spec.rb
|
168
190
|
- spec/dashboard_spec.rb
|
169
191
|
- spec/experiment_spec.rb
|
170
192
|
- spec/helper_spec.rb
|
193
|
+
- spec/metric_spec.rb
|
194
|
+
- spec/persistence/cookie_adapter_spec.rb
|
195
|
+
- spec/persistence/session_adapter_spec.rb
|
196
|
+
- spec/persistence_spec.rb
|
171
197
|
- spec/spec_helper.rb
|
198
|
+
- spec/support/cookies_mock.rb
|
199
|
+
- spec/trial_spec.rb
|
200
|
+
has_rdoc:
|