split 0.2.1 → 0.2.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.
- data/.gitignore +1 -0
- data/CHANGELOG.mdown +15 -0
- data/README.mdown +28 -2
- data/lib/split.rb +16 -0
- data/lib/split/alternative.rb +12 -0
- data/lib/split/configuration.rb +11 -0
- data/lib/split/dashboard.rb +5 -2
- data/lib/split/dashboard/public/dashboard.js +8 -0
- data/lib/split/dashboard/public/style.css +8 -0
- data/lib/split/dashboard/views/index.erb +16 -3
- data/lib/split/experiment.rb +19 -7
- data/lib/split/helper.rb +15 -3
- data/lib/split/version.rb +1 -1
- data/spec/alternative_spec.rb +11 -2
- data/spec/configuration_spec.rb +10 -0
- data/spec/dashboard_spec.rb +48 -0
- data/spec/experiment_spec.rb +37 -4
- data/spec/helper_spec.rb +46 -0
- data/spec/spec_helper.rb +1 -0
- data/split.gemspec +2 -1
- metadata +28 -8
data/.gitignore
CHANGED
data/CHANGELOG.mdown
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 0.2.2 (June 11, 2011)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Updated redis-namespace requirement to 1.0.3
|
6
|
+
- Added a configuration object for changing options
|
7
|
+
- Robot regex can now be changed via a configuration options
|
8
|
+
- Added ability to ignore visits from specified IP addresses
|
9
|
+
- Dashboard now shows percentage improvement of alternatives compared to the control
|
10
|
+
- If the alternatives of an experiment are changed it resets the experiment and uses the new alternatives
|
11
|
+
|
12
|
+
Bugfixes:
|
13
|
+
|
14
|
+
- Saving an experiment multiple times no longer creates duplicate alternatives
|
15
|
+
|
1
16
|
## 0.2.1 (May 29, 2011)
|
2
17
|
|
3
18
|
Bugfixes:
|
data/README.mdown
CHANGED
@@ -8,6 +8,8 @@ Split is heavily inspired by the Abingo and Vanity rails ab testing plugins and
|
|
8
8
|
|
9
9
|
Split uses redis as a datastore.
|
10
10
|
|
11
|
+
Split only supports redis 2.0 or greater.
|
12
|
+
|
11
13
|
If you're on OS X, Homebrew is the simplest way to install Redis:
|
12
14
|
|
13
15
|
$ brew install redis
|
@@ -33,6 +35,14 @@ and require it in your project:
|
|
33
35
|
|
34
36
|
require 'split'
|
35
37
|
|
38
|
+
### SystemTimer
|
39
|
+
|
40
|
+
If you are using Redis on Ruby 1.8.x then you will likely want to also use the SystemTimer gem if you want to make sure the Redis client will not hang.
|
41
|
+
|
42
|
+
Put the following in your gemfile as well:
|
43
|
+
|
44
|
+
gem 'SystemTimer'
|
45
|
+
|
36
46
|
### Rails
|
37
47
|
|
38
48
|
Split is autoloaded when rails starts up, as long as you've configured redis it will 'just work'.
|
@@ -114,6 +124,15 @@ You may want to password protect that page, you can do so with `Rack::Auth::Basi
|
|
114
124
|
|
115
125
|
## Configuration
|
116
126
|
|
127
|
+
You can override the default configuration options of Split like so:
|
128
|
+
|
129
|
+
Split.configure do |config|
|
130
|
+
config.robot_regex = /my_custom_robot_regex/
|
131
|
+
config.ignore_ip_addresses << '81.19.48.130'
|
132
|
+
end
|
133
|
+
|
134
|
+
### Redis
|
135
|
+
|
117
136
|
You may want to change the Redis host and port Split connects to, or
|
118
137
|
set various other options at startup.
|
119
138
|
|
@@ -157,7 +176,7 @@ in your Redis server.
|
|
157
176
|
|
158
177
|
Simply use the `Split.redis.namespace` accessor:
|
159
178
|
|
160
|
-
Split.redis.namespace = "
|
179
|
+
Split.redis.namespace = "split:blog"
|
161
180
|
|
162
181
|
We recommend sticking this in your initializer somewhere after Redis
|
163
182
|
is configured.
|
@@ -169,7 +188,14 @@ Special thanks to the following people for submitting patches:
|
|
169
188
|
* Lloyd Pick
|
170
189
|
* Jeffery Chupp
|
171
190
|
|
172
|
-
##
|
191
|
+
## Development
|
192
|
+
|
193
|
+
Source hosted at [GitHub](http://github.com/andrew/split).
|
194
|
+
Report Issues/Feature requests on [GitHub Issues](http://github.com/andrew/split/issues).
|
195
|
+
|
196
|
+
Tests can be ran with `rake spec`
|
197
|
+
|
198
|
+
### Note on Patches/Pull Requests
|
173
199
|
|
174
200
|
* Fork the project.
|
175
201
|
* Make your feature addition or bug fix.
|
data/lib/split.rb
CHANGED
@@ -3,10 +3,13 @@ require 'split/experiment'
|
|
3
3
|
require 'split/alternative'
|
4
4
|
require 'split/helper'
|
5
5
|
require 'split/version'
|
6
|
+
require 'split/configuration'
|
6
7
|
require 'redis/namespace'
|
7
8
|
|
8
9
|
module Split
|
9
10
|
extend self
|
11
|
+
attr_accessor :configuration
|
12
|
+
|
10
13
|
# Accepts:
|
11
14
|
# 1. A 'hostname:port' string
|
12
15
|
# 2. A 'hostname:port:db' string (to select the Redis db)
|
@@ -41,8 +44,21 @@ module Split
|
|
41
44
|
self.redis = 'localhost:6379'
|
42
45
|
self.redis
|
43
46
|
end
|
47
|
+
|
48
|
+
# Call this method to modify defaults in your initializers.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Split.configure do |config|
|
52
|
+
# config.ignore_ips = '192.168.2.1'
|
53
|
+
# end
|
54
|
+
def configure
|
55
|
+
self.configuration ||= Configuration.new
|
56
|
+
yield(configuration)
|
57
|
+
end
|
44
58
|
end
|
45
59
|
|
60
|
+
Split.configure {}
|
61
|
+
|
46
62
|
if defined?(Rails)
|
47
63
|
class ActionController::Base
|
48
64
|
ActionController::Base.send :include, Split::Helper
|
data/lib/split/alternative.rb
CHANGED
@@ -12,6 +12,10 @@ module Split
|
|
12
12
|
@completed_count = counters['completed_count'].to_i
|
13
13
|
end
|
14
14
|
|
15
|
+
def to_s
|
16
|
+
name
|
17
|
+
end
|
18
|
+
|
15
19
|
def increment_participation
|
16
20
|
@participant_count +=1
|
17
21
|
self.save
|
@@ -22,6 +26,10 @@ module Split
|
|
22
26
|
self.save
|
23
27
|
end
|
24
28
|
|
29
|
+
def control?
|
30
|
+
experiment.control.name == self.name
|
31
|
+
end
|
32
|
+
|
25
33
|
def conversion_rate
|
26
34
|
return 0 if participant_count.zero?
|
27
35
|
(completed_count.to_f/participant_count.to_f)
|
@@ -71,6 +79,10 @@ module Split
|
|
71
79
|
save
|
72
80
|
end
|
73
81
|
|
82
|
+
def delete
|
83
|
+
Split.redis.del("#{experiment_name}:#{name}")
|
84
|
+
end
|
85
|
+
|
74
86
|
def self.find(name, experiment_name)
|
75
87
|
counters = Split.redis.hgetall "#{experiment_name}:#{name}"
|
76
88
|
self.new(name, experiment_name, counters)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Split
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :robot_regex
|
4
|
+
attr_accessor :ignore_ip_addresses
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@robot_regex = /\b(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)\b/i
|
8
|
+
@ignore_ip_addresses = []
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/split/dashboard.rb
CHANGED
@@ -20,7 +20,11 @@ module Split
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def number_to_percentage(number, precision = 2)
|
23
|
-
|
23
|
+
round(number * 100)
|
24
|
+
end
|
25
|
+
|
26
|
+
def round(number, precision = 2)
|
27
|
+
BigDecimal.new(number.to_s).round(precision).to_f
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
@@ -33,7 +37,6 @@ module Split
|
|
33
37
|
@experiment = Split::Experiment.find(params[:experiment])
|
34
38
|
@alternative = Split::Alternative.find(params[:alternative], params[:experiment])
|
35
39
|
@experiment.winner = @alternative.name
|
36
|
-
@experiment.save
|
37
40
|
redirect url('/')
|
38
41
|
end
|
39
42
|
|
@@ -25,8 +25,21 @@
|
|
25
25
|
<td><%= alternative.participant_count %></td>
|
26
26
|
<td><%= alternative.participant_count - alternative.completed_count %></td>
|
27
27
|
<td><%= alternative.completed_count %></td>
|
28
|
-
<td
|
29
|
-
|
28
|
+
<td>
|
29
|
+
<%= number_to_percentage(alternative.conversion_rate) %>%
|
30
|
+
<% if experiment.control.conversion_rate > 0 && !alternative.control? %>
|
31
|
+
<% if alternative.conversion_rate > experiment.control.conversion_rate %>
|
32
|
+
<span class='better'>
|
33
|
+
+<%= number_to_percentage((alternative.conversion_rate/experiment.control.conversion_rate)-1) %>%
|
34
|
+
</span>
|
35
|
+
<% elsif alternative.conversion_rate < experiment.control.conversion_rate %>
|
36
|
+
<span class='worse'>
|
37
|
+
<%= number_to_percentage((alternative.conversion_rate/experiment.control.conversion_rate)-1) %>%
|
38
|
+
</span>
|
39
|
+
<% end %>
|
40
|
+
<% end %>
|
41
|
+
</td>
|
42
|
+
<td><%= round(alternative.z_score, 3) %></td>
|
30
43
|
<td>
|
31
44
|
<% if experiment.winner %>
|
32
45
|
<% if experiment.winner.name == alternative.name %>
|
@@ -35,7 +48,7 @@
|
|
35
48
|
Loser
|
36
49
|
<% end %>
|
37
50
|
<% else %>
|
38
|
-
<form action="<%= url experiment.name %>" method='post'>
|
51
|
+
<form action="<%= url experiment.name %>" method='post' onclick="return confirmWinner()">
|
39
52
|
<input type='hidden' name='alternative' value='<%= alternative.name %>'>
|
40
53
|
<input type="submit" value="Use this">
|
41
54
|
</form>
|
data/lib/split/experiment.rb
CHANGED
@@ -38,15 +38,19 @@ module Split
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def reset
|
41
|
-
alternatives.each
|
42
|
-
alternative.reset
|
43
|
-
end
|
41
|
+
alternatives.each(&:reset)
|
44
42
|
reset_winner
|
45
43
|
end
|
46
44
|
|
45
|
+
def new_record?
|
46
|
+
!Split.redis.exists(name)
|
47
|
+
end
|
48
|
+
|
47
49
|
def save
|
48
|
-
|
49
|
-
|
50
|
+
if new_record?
|
51
|
+
Split.redis.sadd(:experiments, name)
|
52
|
+
@alternative_names.reverse.each {|a| Split.redis.lpush(name, a) }
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
def self.load_alternatives_for(name)
|
@@ -75,12 +79,20 @@ module Split
|
|
75
79
|
|
76
80
|
def self.find_or_create(name, *alternatives)
|
77
81
|
if Split.redis.exists(name)
|
78
|
-
|
82
|
+
if load_alternatives_for(name) == alternatives
|
83
|
+
experiment = self.new(name, *load_alternatives_for(name))
|
84
|
+
else
|
85
|
+
exp = self.new(name, *load_alternatives_for(name))
|
86
|
+
exp.reset
|
87
|
+
exp.alternatives.each(&:delete)
|
88
|
+
experiment = self.new(name, *alternatives)
|
89
|
+
experiment.save
|
90
|
+
end
|
79
91
|
else
|
80
92
|
experiment = self.new(name, *alternatives)
|
81
93
|
experiment.save
|
82
|
-
return experiment
|
83
94
|
end
|
95
|
+
return experiment
|
84
96
|
end
|
85
97
|
end
|
86
98
|
end
|
data/lib/split/helper.rb
CHANGED
@@ -8,7 +8,7 @@ module Split
|
|
8
8
|
return forced_alternative
|
9
9
|
end
|
10
10
|
|
11
|
-
ab_user[experiment_name] = experiment.control.name if
|
11
|
+
ab_user[experiment_name] = experiment.control.name if exclude_visitor?
|
12
12
|
|
13
13
|
if ab_user[experiment_name]
|
14
14
|
return ab_user[experiment_name]
|
@@ -21,7 +21,7 @@ module Split
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def finished(experiment_name)
|
24
|
-
return if
|
24
|
+
return if exclude_visitor?
|
25
25
|
alternative_name = ab_user[experiment_name]
|
26
26
|
alternative = Split::Alternative.find(alternative_name, experiment_name)
|
27
27
|
alternative.increment_completion
|
@@ -36,8 +36,20 @@ module Split
|
|
36
36
|
session[:split] ||= {}
|
37
37
|
end
|
38
38
|
|
39
|
+
def exclude_visitor?
|
40
|
+
is_robot? or is_ignored_ip_address?
|
41
|
+
end
|
42
|
+
|
39
43
|
def is_robot?
|
40
|
-
request.user_agent =~
|
44
|
+
request.user_agent =~ Split.configuration.robot_regex
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_ignored_ip_address?
|
48
|
+
if Split.configuration.ignore_ip_addresses.any?
|
49
|
+
Split.configuration.ignore_ip_addresses.include?(request.ip)
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
43
55
|
end
|
data/lib/split/version.rb
CHANGED
data/spec/alternative_spec.rb
CHANGED
@@ -50,7 +50,7 @@ describe Split::Alternative do
|
|
50
50
|
alternative.increment_completion
|
51
51
|
alternative.completed_count.should eql(old_completed_count+1)
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
it "can be reset" do
|
55
55
|
alternative = Split::Alternative.new('Basket', 'basket_text', {'participant_count' => 10, 'completed_count' =>4})
|
56
56
|
alternative.save
|
@@ -59,6 +59,15 @@ describe Split::Alternative do
|
|
59
59
|
alternative.completed_count.should eql(0)
|
60
60
|
end
|
61
61
|
|
62
|
+
it "should know if it is the control of an experiment" do
|
63
|
+
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
64
|
+
experiment.save
|
65
|
+
alternative = Split::Alternative.find('Basket', 'basket_text')
|
66
|
+
alternative.control?.should be_true
|
67
|
+
alternative = Split::Alternative.find('Cart', 'basket_text')
|
68
|
+
alternative.control?.should be_false
|
69
|
+
end
|
70
|
+
|
62
71
|
describe 'conversion rate' do
|
63
72
|
it "should be 0 if there are no conversions" do
|
64
73
|
alternative = Split::Alternative.new('Basket', 'basket_text')
|
@@ -84,7 +93,7 @@ describe Split::Alternative do
|
|
84
93
|
alternative = Split::Alternative.find('red', 'link_color')
|
85
94
|
alternative.z_score.should eql(0)
|
86
95
|
end
|
87
|
-
|
96
|
+
|
88
97
|
it "should be N/A for the control" do
|
89
98
|
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
90
99
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Split::Configuration do
|
4
|
+
it "should provide default values" do
|
5
|
+
config = Split::Configuration.new
|
6
|
+
|
7
|
+
config.ignore_ip_addresses.should eql([])
|
8
|
+
config.robot_regex.should eql(/\b(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)\b/i)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'split/dashboard'
|
4
|
+
|
5
|
+
describe Split::Dashboard do
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
def app
|
9
|
+
@app ||= Split::Dashboard
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should respond to /" do
|
13
|
+
get '/'
|
14
|
+
last_response.should be_ok
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should reset an experiment" do
|
18
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
19
|
+
red = Split::Alternative.find('red', 'link_color').participant_count
|
20
|
+
|
21
|
+
red = Split::Alternative.find('red', 'link_color')
|
22
|
+
blue = Split::Alternative.find('blue', 'link_color')
|
23
|
+
red.participant_count = 5
|
24
|
+
red.save
|
25
|
+
blue.participant_count = 6
|
26
|
+
blue.save
|
27
|
+
|
28
|
+
post '/reset/link_color'
|
29
|
+
|
30
|
+
last_response.should be_redirect
|
31
|
+
|
32
|
+
new_red_count = Split::Alternative.find('red', 'link_color').participant_count
|
33
|
+
new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
|
34
|
+
|
35
|
+
new_blue_count.should eql(0)
|
36
|
+
new_red_count.should eql(0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should mark an alternative as the winner" do
|
40
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
41
|
+
experiment.winner.should be_nil
|
42
|
+
|
43
|
+
post '/link_color', :alternative => 'red'
|
44
|
+
|
45
|
+
last_response.should be_redirect
|
46
|
+
experiment.winner.name.should eql('red')
|
47
|
+
end
|
48
|
+
end
|
data/spec/experiment_spec.rb
CHANGED
@@ -8,18 +8,39 @@ describe Split::Experiment do
|
|
8
8
|
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
9
9
|
experiment.name.should eql('basket_text')
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
it "should have alternatives" do
|
13
13
|
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
14
14
|
experiment.alternatives.length.should be 2
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should save to redis" do
|
18
18
|
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
19
19
|
experiment.save
|
20
20
|
Split.redis.exists('basket_text').should be true
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
|
+
it "should not create duplicates when saving multiple times" do
|
24
|
+
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
25
|
+
experiment.save
|
26
|
+
experiment.save
|
27
|
+
Split.redis.exists('basket_text').should be true
|
28
|
+
Split.redis.lrange('basket_text', 0, -1).should eql(['Basket', "Cart"])
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'new record?' do
|
32
|
+
it "should know if it hasn't been saved yet" do
|
33
|
+
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
34
|
+
experiment.new_record?.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should know if it has been saved yet" do
|
38
|
+
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
39
|
+
experiment.save
|
40
|
+
experiment.new_record?.should be_false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
23
44
|
it "should return an existing experiment" do
|
24
45
|
experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
|
25
46
|
experiment.save
|
@@ -101,5 +122,17 @@ describe Split::Experiment do
|
|
101
122
|
experiment.next_alternative.name.should eql('green')
|
102
123
|
end
|
103
124
|
end
|
104
|
-
end
|
105
125
|
|
126
|
+
describe 'changing an existing experiment' do
|
127
|
+
it "should reset an experiment if it is loaded with different alternatives" do
|
128
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red', 'green')
|
129
|
+
blue = Split::Alternative.find('blue', 'link_color')
|
130
|
+
blue.participant_count = 5
|
131
|
+
blue.save
|
132
|
+
same_experiment = Split::Experiment.find_or_create('link_color', 'blue', 'yellow', 'orange')
|
133
|
+
same_experiment.alternatives.map(&:name).should eql(['blue', 'yellow', 'orange'])
|
134
|
+
new_blue = Split::Alternative.find('blue', 'link_color')
|
135
|
+
new_blue.participant_count.should eql(0)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/helper_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# TODO change some of these tests to use Rack::Test
|
4
|
+
|
3
5
|
describe Split::Helper do
|
4
6
|
include Split::Helper
|
5
7
|
|
@@ -97,6 +99,50 @@ describe Split::Helper do
|
|
97
99
|
@request = OpenStruct.new(:user_agent => 'Googlebot/2.1 (+http://www.google.com/bot.html)')
|
98
100
|
end
|
99
101
|
|
102
|
+
describe 'ab_test' do
|
103
|
+
it 'should return the control' do
|
104
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
105
|
+
alternative = ab_test('link_color', 'blue', 'red')
|
106
|
+
alternative.should eql experiment.control.name
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not increment the participation count" do
|
110
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
111
|
+
|
112
|
+
previous_red_count = Split::Alternative.find('red', 'link_color').participant_count
|
113
|
+
previous_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
|
114
|
+
|
115
|
+
ab_test('link_color', 'blue', 'red')
|
116
|
+
|
117
|
+
new_red_count = Split::Alternative.find('red', 'link_color').participant_count
|
118
|
+
new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
|
119
|
+
|
120
|
+
(new_red_count + new_blue_count).should eql(previous_red_count + previous_blue_count)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
describe 'finished' do
|
124
|
+
it "should not increment the completed count" do
|
125
|
+
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
126
|
+
alternative_name = ab_test('link_color', 'blue', 'red')
|
127
|
+
|
128
|
+
previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
|
129
|
+
|
130
|
+
finished('link_color')
|
131
|
+
|
132
|
+
new_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
|
133
|
+
|
134
|
+
new_completion_count.should eql(previous_completion_count)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
describe 'when ip address is ignored' do
|
139
|
+
before(:each) do
|
140
|
+
@request = OpenStruct.new(:ip => '81.19.48.130')
|
141
|
+
Split.configure do |c|
|
142
|
+
c.ignore_ip_addresses << '81.19.48.130'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
100
146
|
describe 'ab_test' do
|
101
147
|
it 'should return the control' do
|
102
148
|
experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
|
data/spec/spec_helper.rb
CHANGED
data/split.gemspec
CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
21
|
s.add_dependency(%q<redis>, ["~> 2.1"])
|
22
|
-
s.add_dependency(%q<redis-namespace>, ["~> 0.
|
22
|
+
s.add_dependency(%q<redis-namespace>, ["~> 1.0.3"])
|
23
23
|
s.add_dependency(%q<sinatra>, ["~> 1.2.6"])
|
24
24
|
|
25
25
|
# Development Dependencies
|
26
26
|
s.add_development_dependency(%q<rspec>, ["~> 2.6"])
|
27
|
+
s.add_development_dependency(%q<rack-test>, ["~> 0.6"])
|
27
28
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: split
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Nesbitt
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-06-12 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -41,12 +41,12 @@ dependencies:
|
|
41
41
|
requirements:
|
42
42
|
- - ~>
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
44
|
+
hash: 17
|
45
45
|
segments:
|
46
|
+
- 1
|
46
47
|
- 0
|
47
|
-
-
|
48
|
-
|
49
|
-
version: 0.10.0
|
48
|
+
- 3
|
49
|
+
version: 1.0.3
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
52
|
- !ruby/object:Gem::Dependency
|
@@ -80,6 +80,21 @@ dependencies:
|
|
80
80
|
version: "2.6"
|
81
81
|
type: :development
|
82
82
|
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rack-test
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 7
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
- 6
|
95
|
+
version: "0.6"
|
96
|
+
type: :development
|
97
|
+
version_requirements: *id005
|
83
98
|
description:
|
84
99
|
email:
|
85
100
|
- andrewnez@gmail.com
|
@@ -98,6 +113,7 @@ files:
|
|
98
113
|
- Rakefile
|
99
114
|
- lib/split.rb
|
100
115
|
- lib/split/alternative.rb
|
116
|
+
- lib/split/configuration.rb
|
101
117
|
- lib/split/dashboard.rb
|
102
118
|
- lib/split/dashboard/public/dashboard.js
|
103
119
|
- lib/split/dashboard/public/reset.css
|
@@ -108,6 +124,8 @@ files:
|
|
108
124
|
- lib/split/helper.rb
|
109
125
|
- lib/split/version.rb
|
110
126
|
- spec/alternative_spec.rb
|
127
|
+
- spec/configuration_spec.rb
|
128
|
+
- spec/dashboard_spec.rb
|
111
129
|
- spec/experiment_spec.rb
|
112
130
|
- spec/helper_spec.rb
|
113
131
|
- spec/spec_helper.rb
|
@@ -148,6 +166,8 @@ specification_version: 3
|
|
148
166
|
summary: Rack based split testing framework
|
149
167
|
test_files:
|
150
168
|
- spec/alternative_spec.rb
|
169
|
+
- spec/configuration_spec.rb
|
170
|
+
- spec/dashboard_spec.rb
|
151
171
|
- spec/experiment_spec.rb
|
152
172
|
- spec/helper_spec.rb
|
153
173
|
- spec/spec_helper.rb
|