split 0.3.0 → 0.3.1

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.
@@ -1,3 +1,16 @@
1
+ ## 0.3.1 (November 19, 2011)
2
+
3
+ Features:
4
+
5
+ - General code tidy up (@ryanlecompte, #22, @mocoso, #28)
6
+ - Lazy loading data from Redis (@lautis, #25)
7
+
8
+ Bugfixes:
9
+
10
+ - Handle unstarted experiments (@mocoso, #27)
11
+ - Relaxed Sinatra version requirement (@martinclu, #24)
12
+
13
+
1
14
  ## 0.3.0 (October 9, 2011)
2
15
 
3
16
  Features:
@@ -1,16 +1,12 @@
1
1
  module Split
2
2
  class Alternative
3
3
  attr_accessor :name
4
- attr_accessor :participant_count
5
- attr_accessor :completed_count
6
4
  attr_accessor :experiment_name
7
5
  attr_accessor :weight
8
6
 
9
- def initialize(name, experiment_name, counters = {})
7
+ def initialize(name, experiment_name)
10
8
  @experiment_name = experiment_name
11
- @participant_count = counters['participant_count'].to_i
12
- @completed_count = counters['completed_count'].to_i
13
- if name.class == Hash
9
+ if Hash === name
14
10
  @name = name.keys.first
15
11
  @weight = name.values.first
16
12
  else
@@ -23,14 +19,28 @@ module Split
23
19
  name
24
20
  end
25
21
 
22
+ def participant_count
23
+ Split.redis.hget(key, 'participant_count').to_i
24
+ end
25
+
26
+ def participant_count=(count)
27
+ Split.redis.hset(key, 'participant_count', count.to_i)
28
+ end
29
+
30
+ def completed_count
31
+ Split.redis.hget(key, 'completed_count').to_i
32
+ end
33
+
34
+ def completed_count=(count)
35
+ Split.redis.hset(key, 'completed_count', count.to_i)
36
+ end
37
+
26
38
  def increment_participation
27
- @participant_count +=1
28
- Split.redis.hincrby "#{experiment_name}:#{name}", 'participant_count', 1
39
+ Split.redis.hincrby key, 'participant_count', 1
29
40
  end
30
41
 
31
42
  def increment_completion
32
- @completed_count +=1
33
- Split.redis.hincrby "#{experiment_name}:#{name}", 'completed_count', 1
43
+ Split.redis.hincrby key, 'completed_count', 1
34
44
  end
35
45
 
36
46
  def control?
@@ -72,49 +82,30 @@ module Split
72
82
  end
73
83
 
74
84
  def save
75
- if Split.redis.hgetall("#{experiment_name}:#{name}")
76
- Split.redis.hset "#{experiment_name}:#{name}", 'participant_count', @participant_count
77
- Split.redis.hset "#{experiment_name}:#{name}", 'completed_count', @completed_count
78
- else
79
- Split.redis.hmset "#{experiment_name}:#{name}", 'participant_count', 'completed_count', @participant_count, @completed_count
80
- end
85
+ Split.redis.hsetnx key, 'participant_count', 0
86
+ Split.redis.hsetnx key, 'completed_count', 0
81
87
  end
82
88
 
83
89
  def reset
84
- @participant_count = 0
85
- @completed_count = 0
86
- save
90
+ Split.redis.hmset key, 'participant_count', 0, 'completed_count', 0
87
91
  end
88
92
 
89
93
  def delete
90
- Split.redis.del("#{experiment_name}:#{name}")
91
- end
92
-
93
- def self.find(name, experiment_name)
94
- counters = Split.redis.hgetall "#{experiment_name}:#{name}"
95
- self.new(name, experiment_name, counters)
96
- end
97
-
98
- def self.find_or_create(name, experiment_name)
99
- self.find(name, experiment_name) || self.create(name, experiment_name)
100
- end
101
-
102
- def self.create(name, experiment_name)
103
- alt = self.new(name, experiment_name)
104
- alt.save
105
- alt
94
+ Split.redis.del(key)
106
95
  end
107
96
 
108
97
  def self.valid?(name)
109
- string?(name) or hash_with_correct_values?(name)
98
+ String === name || hash_with_correct_values?(name)
110
99
  end
111
100
 
112
- def self.string?(name)
113
- name.class == String
101
+ def self.hash_with_correct_values?(name)
102
+ Hash === name && String === name.keys.first && Float(name.values.first) rescue false
114
103
  end
115
104
 
116
- def self.hash_with_correct_values?(name)
117
- name.class == Hash && name.keys.first.class == String && Float(name.values.first) rescue false
105
+ private
106
+
107
+ def key
108
+ "#{experiment_name}:#{name}"
118
109
  end
119
110
  end
120
111
  end
@@ -3,7 +3,7 @@ module Split
3
3
  attr_accessor :robot_regex
4
4
  attr_accessor :ignore_ip_addresses
5
5
 
6
- def initialize()
6
+ def initialize
7
7
  @robot_regex = /\b(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)\b/i
8
8
  @ignore_ip_addresses = []
9
9
  end
@@ -7,7 +7,7 @@ module Split
7
7
  dir = File.dirname(File.expand_path(__FILE__))
8
8
 
9
9
  set :views, "#{dir}/dashboard/views"
10
- set :public, "#{dir}/dashboard/public"
10
+ set :public_folder, "#{dir}/dashboard/public"
11
11
  set :static, true
12
12
  set :method_override, true
13
13
 
@@ -63,7 +63,7 @@ module Split
63
63
 
64
64
  post '/:experiment' do
65
65
  @experiment = Split::Experiment.find(params[:experiment])
66
- @alternative = Split::Alternative.find(params[:alternative], params[:experiment])
66
+ @alternative = Split::Alternative.new(params[:alternative], params[:experiment])
67
67
  @experiment.winner = @alternative.name
68
68
  redirect url('/')
69
69
  end
@@ -1,22 +1,18 @@
1
1
  module Split
2
2
  class Experiment
3
3
  attr_accessor :name
4
- attr_accessor :alternative_names
5
4
  attr_accessor :winner
6
- attr_accessor :version
7
5
 
8
6
  def initialize(name, *alternative_names)
9
7
  @name = name.to_s
10
- @alternative_names = alternative_names.map do |alternative|
11
- Split::Alternative.new(alternative, name)
12
- end.map(&:name)
13
-
14
- @version = (Split.redis.get("#{name.to_s}:version").to_i || 0)
8
+ @alternatives = alternative_names.map do |alternative|
9
+ Split::Alternative.new(alternative, name)
10
+ end
15
11
  end
16
12
 
17
13
  def winner
18
14
  if w = Split.redis.hget(:experiment_winner, name)
19
- return Split::Alternative.find(w, name)
15
+ Split::Alternative.new(w, name)
20
16
  else
21
17
  nil
22
18
  end
@@ -30,12 +26,17 @@ module Split
30
26
  Split.redis.hdel(:experiment_winner, name)
31
27
  end
32
28
 
29
+
33
30
  def winner=(winner_name)
34
31
  Split.redis.hset(:experiment_winner, name, winner_name.to_s)
35
32
  end
36
33
 
37
34
  def alternatives
38
- @alternative_names.map {|a| Split::Alternative.find_or_create(a, name)}
35
+ @alternatives.dup
36
+ end
37
+
38
+ def alternative_names
39
+ @alternatives.map(&:name)
39
40
  end
40
41
 
41
42
  def next_alternative
@@ -45,7 +46,7 @@ module Split
45
46
  def random_alternative
46
47
  weights = alternatives.map(&:weight)
47
48
 
48
- total = weights.inject(0.0) {|t,w| t+w}
49
+ total = weights.inject(:+)
49
50
  point = rand * total
50
51
 
51
52
  alternatives.zip(weights).each do |n,w|
@@ -55,12 +56,11 @@ module Split
55
56
  end
56
57
 
57
58
  def version
58
- @version ||= 0
59
+ @version ||= (Split.redis.get("#{name.to_s}:version").to_i || 0)
59
60
  end
60
61
 
61
62
  def increment_version
62
- @version += 1
63
- Split.redis.set("#{name}:version", @version)
63
+ @version = Split.redis.incr("#{name}:version")
64
64
  end
65
65
 
66
66
  def key
@@ -92,7 +92,7 @@ module Split
92
92
  def save
93
93
  if new_record?
94
94
  Split.redis.sadd(:experiments, name)
95
- @alternative_names.reverse.each {|a| Split.redis.lpush(name, a) }
95
+ @alternatives.reverse.each {|a| Split.redis.lpush(name, a.name) }
96
96
  end
97
97
  end
98
98
 
@@ -115,8 +115,6 @@ module Split
115
115
  def self.find(name)
116
116
  if Split.redis.exists(name)
117
117
  self.new(name, *load_alternatives_for(name))
118
- else
119
- raise 'Experiment not found'
120
118
  end
121
119
  end
122
120
 
@@ -148,12 +146,12 @@ module Split
148
146
  experiment.save
149
147
  end
150
148
  return experiment
151
-
149
+
152
150
  end
153
151
 
154
152
  def self.initialize_alternatives(alternatives, name)
155
153
 
156
- if alternatives.reject {|a| Split::Alternative.valid? a}.any?
154
+ unless alternatives.all? { |a| Split::Alternative.valid?(a) }
157
155
  raise InvalidArgument, 'Alternatives must be strings'
158
156
  end
159
157
 
@@ -27,7 +27,7 @@ module Split
27
27
  concat(capture(ret, &block))
28
28
  false
29
29
  else
30
- yield(ret)
30
+ yield(ret)
31
31
  end
32
32
  else
33
33
  ret
@@ -36,16 +36,16 @@ module Split
36
36
 
37
37
  def finished(experiment_name, options = {:reset => true})
38
38
  return if exclude_visitor?
39
- experiment = Split::Experiment.find(experiment_name)
39
+ return unless (experiment = Split::Experiment.find(experiment_name))
40
40
  if alternative_name = ab_user[experiment.key]
41
- alternative = Split::Alternative.find(alternative_name, experiment_name)
41
+ alternative = Split::Alternative.new(alternative_name, experiment_name)
42
42
  alternative.increment_completion
43
43
  session[:split].delete(experiment_name) if options[:reset]
44
44
  end
45
45
  end
46
46
 
47
47
  def override(experiment_name, alternatives)
48
- return params[experiment_name] if defined?(params) && alternatives.include?(params[experiment_name])
48
+ params[experiment_name] if defined?(params) && alternatives.include?(params[experiment_name])
49
49
  end
50
50
 
51
51
  def begin_experiment(experiment, alternative_name)
@@ -1,3 +1,3 @@
1
1
  module Split
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -9,7 +9,7 @@ describe Split::Alternative do
9
9
  alternative = Split::Alternative.new('Basket', 'basket_text')
10
10
  alternative.name.should eql('Basket')
11
11
  end
12
-
12
+
13
13
  it "return only the name" do
14
14
  experiment = Split::Experiment.new('basket_text', {'Basket' => 0.6}, {"Cart" => 0.4})
15
15
  alternative = Split::Alternative.new('Basket', 'basket_text')
@@ -29,7 +29,7 @@ describe Split::Alternative do
29
29
  it "should belong to an experiment" do
30
30
  experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
31
31
  experiment.save
32
- alternative = Split::Alternative.find('Basket', 'basket_text')
32
+ alternative = Split::Alternative.new('Basket', 'basket_text')
33
33
  alternative.experiment.name.should eql(experiment.name)
34
34
  end
35
35
 
@@ -42,28 +42,29 @@ describe Split::Alternative do
42
42
  it "should increment participation count" do
43
43
  experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
44
44
  experiment.save
45
- alternative = Split::Alternative.find('Basket', 'basket_text')
45
+ alternative = Split::Alternative.new('Basket', 'basket_text')
46
46
  old_participant_count = alternative.participant_count
47
47
  alternative.increment_participation
48
48
  alternative.participant_count.should eql(old_participant_count+1)
49
49
 
50
- Split::Alternative.find('Basket', 'basket_text').participant_count.should eql(old_participant_count+1)
50
+ Split::Alternative.new('Basket', 'basket_text').participant_count.should eql(old_participant_count+1)
51
51
  end
52
52
 
53
53
  it "should increment completed count" do
54
54
  experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
55
55
  experiment.save
56
- alternative = Split::Alternative.find('Basket', 'basket_text')
56
+ alternative = Split::Alternative.new('Basket', 'basket_text')
57
57
  old_completed_count = alternative.participant_count
58
58
  alternative.increment_completion
59
59
  alternative.completed_count.should eql(old_completed_count+1)
60
60
 
61
- Split::Alternative.find('Basket', 'basket_text').completed_count.should eql(old_completed_count+1)
61
+ Split::Alternative.new('Basket', 'basket_text').completed_count.should eql(old_completed_count+1)
62
62
  end
63
63
 
64
64
  it "can be reset" do
65
- alternative = Split::Alternative.new('Basket', 'basket_text', {'participant_count' => 10, 'completed_count' =>4})
66
- alternative.save
65
+ alternative = Split::Alternative.new('Basket', 'basket_text')
66
+ alternative.participant_count = 10
67
+ alternative.completed_count = 4
67
68
  alternative.reset
68
69
  alternative.participant_count.should eql(0)
69
70
  alternative.completed_count.should eql(0)
@@ -72,9 +73,9 @@ describe Split::Alternative do
72
73
  it "should know if it is the control of an experiment" do
73
74
  experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
74
75
  experiment.save
75
- alternative = Split::Alternative.find('Basket', 'basket_text')
76
+ alternative = Split::Alternative.new('Basket', 'basket_text')
76
77
  alternative.control?.should be_true
77
- alternative = Split::Alternative.find('Cart', 'basket_text')
78
+ alternative = Split::Alternative.new('Cart', 'basket_text')
78
79
  alternative.control?.should be_false
79
80
  end
80
81
 
@@ -86,21 +87,18 @@ describe Split::Alternative do
86
87
  end
87
88
 
88
89
  it "does something" do
89
- alternative = Split::Alternative.new('Basket', 'basket_text', {'participant_count' => 10, 'completed_count' =>4})
90
+ alternative = Split::Alternative.new('Basket', 'basket_text')
91
+ alternative.stub(:participant_count).and_return(10)
92
+ alternative.stub(:completed_count).and_return(4)
90
93
  alternative.conversion_rate.should eql(0.4)
91
94
  end
92
95
  end
93
96
 
94
- it "should return an existing alternative" do
95
- alternative = Split::Alternative.create('Basket', 'basket_text')
96
- Split::Alternative.find('Basket', 'basket_text').name.should eql('Basket')
97
- end
98
-
99
97
  describe 'z score' do
100
98
  it 'should be zero when the control has no conversions' do
101
99
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
102
100
 
103
- alternative = Split::Alternative.find('red', 'link_color')
101
+ alternative = Split::Alternative.new('red', 'link_color')
104
102
  alternative.z_score.should eql(0)
105
103
  end
106
104
 
@@ -18,21 +18,18 @@ describe Split::Dashboard do
18
18
 
19
19
  it "should reset an experiment" do
20
20
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
21
- red = Split::Alternative.find('red', 'link_color').participant_count
22
21
 
23
- red = Split::Alternative.find('red', 'link_color')
24
- blue = Split::Alternative.find('blue', 'link_color')
22
+ red = Split::Alternative.new('red', 'link_color')
23
+ blue = Split::Alternative.new('blue', 'link_color')
25
24
  red.participant_count = 5
26
- red.save
27
25
  blue.participant_count = 6
28
- blue.save
29
26
 
30
27
  post '/reset/link_color'
31
28
 
32
29
  last_response.should be_redirect
33
30
 
34
- new_red_count = Split::Alternative.find('red', 'link_color').participant_count
35
- new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
31
+ new_red_count = Split::Alternative.new('red', 'link_color').participant_count
32
+ new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
36
33
 
37
34
  new_blue_count.should eql(0)
38
35
  new_red_count.should eql(0)
@@ -42,7 +39,7 @@ describe Split::Dashboard do
42
39
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
43
40
  delete '/link_color'
44
41
  last_response.should be_redirect
45
- lambda { Split::Experiment.find('link_color') }.should raise_error
42
+ Split::Experiment.find('link_color').should be_nil
46
43
  end
47
44
 
48
45
  it "should mark an alternative as the winner" do
@@ -35,7 +35,7 @@ describe Split::Experiment do
35
35
 
36
36
  experiment.delete
37
37
  Split.redis.exists('basket_text').should be false
38
- lambda { Split::Experiment.find('link_color') }.should raise_error
38
+ Split::Experiment.find('link_color').should be_nil
39
39
  end
40
40
 
41
41
  it "should increment the version" do
@@ -59,10 +59,16 @@ describe Split::Experiment do
59
59
  end
60
60
  end
61
61
 
62
- it "should return an existing experiment" do
63
- experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
64
- experiment.save
65
- Split::Experiment.find('basket_text').name.should eql('basket_text')
62
+ describe 'find' do
63
+ it "should return an existing experiment" do
64
+ experiment = Split::Experiment.new('basket_text', 'Basket', "Cart")
65
+ experiment.save
66
+ Split::Experiment.find('basket_text').name.should eql('basket_text')
67
+ end
68
+
69
+ it "should return an existing experiment" do
70
+ Split::Experiment.find('non_existent_experiment').should be_nil
71
+ end
66
72
  end
67
73
 
68
74
  describe 'control' do
@@ -91,7 +97,7 @@ describe Split::Experiment do
91
97
  describe 'reset' do
92
98
  it 'should reset all alternatives' do
93
99
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red', 'green')
94
- green = Split::Alternative.find('green', 'link_color')
100
+ green = Split::Alternative.new('green', 'link_color')
95
101
  experiment.winner = 'green'
96
102
 
97
103
  experiment.next_alternative.name.should eql('green')
@@ -99,14 +105,14 @@ describe Split::Experiment do
99
105
 
100
106
  experiment.reset
101
107
 
102
- reset_green = Split::Alternative.find('green', 'link_color')
108
+ reset_green = Split::Alternative.new('green', 'link_color')
103
109
  reset_green.participant_count.should eql(0)
104
110
  reset_green.completed_count.should eql(0)
105
111
  end
106
112
 
107
113
  it 'should reset the winner' do
108
114
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red', 'green')
109
- green = Split::Alternative.find('green', 'link_color')
115
+ green = Split::Alternative.new('green', 'link_color')
110
116
  experiment.winner = 'green'
111
117
 
112
118
  experiment.next_alternative.name.should eql('green')
@@ -128,7 +134,7 @@ describe Split::Experiment do
128
134
  describe 'next_alternative' do
129
135
  it "should always return the winner if one exists" do
130
136
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red', 'green')
131
- green = Split::Alternative.find('green', 'link_color')
137
+ green = Split::Alternative.new('green', 'link_color')
132
138
  experiment.winner = 'green'
133
139
 
134
140
  experiment.next_alternative.name.should eql('green')
@@ -142,12 +148,12 @@ describe Split::Experiment do
142
148
  describe 'changing an existing experiment' do
143
149
  it "should reset an experiment if it is loaded with different alternatives" do
144
150
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red', 'green')
145
- blue = Split::Alternative.find('blue', 'link_color')
151
+ blue = Split::Alternative.new('blue', 'link_color')
146
152
  blue.participant_count = 5
147
153
  blue.save
148
154
  same_experiment = Split::Experiment.find_or_create('link_color', 'blue', 'yellow', 'orange')
149
155
  same_experiment.alternatives.map(&:name).should eql(['blue', 'yellow', 'orange'])
150
- new_blue = Split::Alternative.find('blue', 'link_color')
156
+ new_blue = Split::Alternative.new('blue', 'link_color')
151
157
  new_blue.participant_count.should eql(0)
152
158
  end
153
159
  end
@@ -20,13 +20,13 @@ describe Split::Helper do
20
20
  it "should increment the participation counter after assignment to a new user" do
21
21
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
22
22
 
23
- previous_red_count = Split::Alternative.find('red', 'link_color').participant_count
24
- previous_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
23
+ previous_red_count = Split::Alternative.new('red', 'link_color').participant_count
24
+ previous_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
25
25
 
26
26
  ab_test('link_color', 'blue', 'red')
27
27
 
28
- new_red_count = Split::Alternative.find('red', 'link_color').participant_count
29
- new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
28
+ new_red_count = Split::Alternative.new('red', 'link_color').participant_count
29
+ new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
30
30
 
31
31
  (new_red_count + new_blue_count).should eql(previous_red_count + previous_blue_count + 1)
32
32
  end
@@ -57,12 +57,12 @@ describe Split::Helper do
57
57
  ret = ab_test('link_color', 'blue', 'red') { |alternative| "shared/#{alternative}" }
58
58
  ret.should eql("shared/#{alt}")
59
59
  end
60
-
60
+
61
61
  it "should allow the share of visitors see an alternative to be specificed" do
62
62
  ab_test('link_color', {'blue' => 0.8}, {'red' => 20})
63
63
  ['red', 'blue'].should include(ab_user['link_color'])
64
64
  end
65
-
65
+
66
66
  it "should allow alternative weighting interface as a single hash" do
67
67
  ab_test('link_color', 'blue' => 0.01, 'red' => 0.2)
68
68
  experiment = Split::Experiment.find('link_color')
@@ -75,11 +75,11 @@ describe Split::Helper do
75
75
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
76
76
  alternative_name = ab_test('link_color', 'blue', 'red')
77
77
 
78
- previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
78
+ previous_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
79
79
 
80
80
  finished('link_color')
81
81
 
82
- new_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
82
+ new_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
83
83
 
84
84
  new_completion_count.should eql(previous_completion_count + 1)
85
85
  end
@@ -88,7 +88,7 @@ describe Split::Helper do
88
88
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
89
89
  alternative_name = ab_test('link_color', 'blue', 'red')
90
90
 
91
- previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
91
+ previous_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
92
92
 
93
93
  session[:split].should eql("link_color" => alternative_name)
94
94
  finished('link_color')
@@ -99,12 +99,17 @@ describe Split::Helper do
99
99
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
100
100
  alternative_name = ab_test('link_color', 'blue', 'red')
101
101
 
102
- previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
102
+ previous_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
103
103
 
104
104
  session[:split].should eql("link_color" => alternative_name)
105
105
  finished('link_color', :reset => false)
106
106
  session[:split].should eql("link_color" => alternative_name)
107
107
  end
108
+
109
+ it "should do nothing where the experiment was not started by this user" do
110
+ session[:split] = nil
111
+ lambda { finished('some_experiment_not_started_by_the_user') }.should_not raise_exception
112
+ end
108
113
  end
109
114
 
110
115
  describe 'conversions' do
@@ -112,12 +117,12 @@ describe Split::Helper do
112
117
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
113
118
  alternative_name = ab_test('link_color', 'blue', 'red')
114
119
 
115
- previous_convertion_rate = Split::Alternative.find(alternative_name, 'link_color').conversion_rate
120
+ previous_convertion_rate = Split::Alternative.new(alternative_name, 'link_color').conversion_rate
116
121
  previous_convertion_rate.should eql(0.0)
117
122
 
118
123
  finished('link_color')
119
124
 
120
- new_convertion_rate = Split::Alternative.find(alternative_name, 'link_color').conversion_rate
125
+ new_convertion_rate = Split::Alternative.new(alternative_name, 'link_color').conversion_rate
121
126
  new_convertion_rate.should eql(1.0)
122
127
  end
123
128
  end
@@ -137,13 +142,13 @@ describe Split::Helper do
137
142
  it "should not increment the participation count" do
138
143
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
139
144
 
140
- previous_red_count = Split::Alternative.find('red', 'link_color').participant_count
141
- previous_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
145
+ previous_red_count = Split::Alternative.new('red', 'link_color').participant_count
146
+ previous_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
142
147
 
143
148
  ab_test('link_color', 'blue', 'red')
144
149
 
145
- new_red_count = Split::Alternative.find('red', 'link_color').participant_count
146
- new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
150
+ new_red_count = Split::Alternative.new('red', 'link_color').participant_count
151
+ new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
147
152
 
148
153
  (new_red_count + new_blue_count).should eql(previous_red_count + previous_blue_count)
149
154
  end
@@ -153,11 +158,11 @@ describe Split::Helper do
153
158
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
154
159
  alternative_name = ab_test('link_color', 'blue', 'red')
155
160
 
156
- previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
161
+ previous_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
157
162
 
158
163
  finished('link_color')
159
164
 
160
- new_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
165
+ new_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
161
166
 
162
167
  new_completion_count.should eql(previous_completion_count)
163
168
  end
@@ -181,13 +186,13 @@ describe Split::Helper do
181
186
  it "should not increment the participation count" do
182
187
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
183
188
 
184
- previous_red_count = Split::Alternative.find('red', 'link_color').participant_count
185
- previous_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
189
+ previous_red_count = Split::Alternative.new('red', 'link_color').participant_count
190
+ previous_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
186
191
 
187
192
  ab_test('link_color', 'blue', 'red')
188
193
 
189
- new_red_count = Split::Alternative.find('red', 'link_color').participant_count
190
- new_blue_count = Split::Alternative.find('blue', 'link_color').participant_count
194
+ new_red_count = Split::Alternative.new('red', 'link_color').participant_count
195
+ new_blue_count = Split::Alternative.new('blue', 'link_color').participant_count
191
196
 
192
197
  (new_red_count + new_blue_count).should eql(previous_red_count + previous_blue_count)
193
198
  end
@@ -197,11 +202,11 @@ describe Split::Helper do
197
202
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
198
203
  alternative_name = ab_test('link_color', 'blue', 'red')
199
204
 
200
- previous_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
205
+ previous_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
201
206
 
202
207
  finished('link_color')
203
208
 
204
- new_completion_count = Split::Alternative.find(alternative_name, 'link_color').completed_count
209
+ new_completion_count = Split::Alternative.new(alternative_name, 'link_color').completed_count
205
210
 
206
211
  new_completion_count.should eql(previous_completion_count)
207
212
  end
@@ -238,17 +243,17 @@ describe Split::Helper do
238
243
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
239
244
  alternative_name = ab_test('link_color', 'blue', 'red')
240
245
  session[:split].should eql({'link_color' => alternative_name})
241
- alternative = Split::Alternative.find(alternative_name, 'link_color')
246
+ alternative = Split::Alternative.new(alternative_name, 'link_color')
242
247
  alternative.participant_count.should eql(1)
243
248
 
244
249
  experiment.reset
245
250
  experiment.version.should eql(1)
246
- alternative = Split::Alternative.find(alternative_name, 'link_color')
251
+ alternative = Split::Alternative.new(alternative_name, 'link_color')
247
252
  alternative.participant_count.should eql(0)
248
253
 
249
254
  new_alternative_name = ab_test('link_color', 'blue', 'red')
250
255
  session[:split]['link_color:1'].should eql(new_alternative_name)
251
- new_alternative = Split::Alternative.find(new_alternative_name, 'link_color')
256
+ new_alternative = Split::Alternative.new(new_alternative_name, 'link_color')
252
257
  new_alternative.participant_count.should eql(1)
253
258
  end
254
259
 
@@ -256,13 +261,13 @@ describe Split::Helper do
256
261
  experiment = Split::Experiment.find_or_create('link_color', 'blue', 'red')
257
262
  alternative_name = ab_test('link_color', 'blue', 'red')
258
263
  session[:split].should eql({'link_color' => alternative_name})
259
- alternative = Split::Alternative.find(alternative_name, 'link_color')
264
+ alternative = Split::Alternative.new(alternative_name, 'link_color')
260
265
 
261
266
  experiment.reset
262
267
  experiment.version.should eql(1)
263
268
 
264
269
  finished('link_color')
265
- alternative = Split::Alternative.find(alternative_name, 'link_color')
270
+ alternative = Split::Alternative.new(alternative_name, 'link_color')
266
271
  alternative.completed_count.should eql(0)
267
272
  end
268
273
  end
@@ -20,8 +20,9 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency 'redis', '~> 2.1'
22
22
  s.add_dependency 'redis-namespace', '~> 1.0.3'
23
- s.add_dependency 'sinatra', '~> 1.2.6'
23
+ s.add_dependency 'sinatra', '>= 1.2.6'
24
24
 
25
+ s.add_development_dependency 'rake'
25
26
  s.add_development_dependency 'bundler', '~> 1.0'
26
27
  s.add_development_dependency 'rspec', '~> 2.6'
27
28
  s.add_development_dependency 'rack-test', '~> 0.6'
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.3.0
4
+ version: 0.3.1
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: 2011-10-09 00:00:00.000000000Z
12
+ date: 2011-11-19 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &70155561576500 !ruby/object:Gem::Requirement
16
+ requirement: &70308912822720 !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: *70155561576500
24
+ version_requirements: *70308912822720
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis-namespace
27
- requirement: &70155561575180 !ruby/object:Gem::Requirement
27
+ requirement: &70308912821980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,21 +32,32 @@ dependencies:
32
32
  version: 1.0.3
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70155561575180
35
+ version_requirements: *70308912821980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sinatra
38
- requirement: &70155561564480 !ruby/object:Gem::Requirement
38
+ requirement: &70308912821300 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
- - - ~>
41
+ - - ! '>='
42
42
  - !ruby/object:Gem::Version
43
43
  version: 1.2.6
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70155561564480
46
+ version_requirements: *70308912821300
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70308912820460 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70308912820460
47
58
  - !ruby/object:Gem::Dependency
48
59
  name: bundler
49
- requirement: &70155561563360 !ruby/object:Gem::Requirement
60
+ requirement: &70308912819780 !ruby/object:Gem::Requirement
50
61
  none: false
51
62
  requirements:
52
63
  - - ~>
@@ -54,10 +65,10 @@ dependencies:
54
65
  version: '1.0'
55
66
  type: :development
56
67
  prerelease: false
57
- version_requirements: *70155561563360
68
+ version_requirements: *70308912819780
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: rspec
60
- requirement: &70155561562780 !ruby/object:Gem::Requirement
71
+ requirement: &70308912819060 !ruby/object:Gem::Requirement
61
72
  none: false
62
73
  requirements:
63
74
  - - ~>
@@ -65,10 +76,10 @@ dependencies:
65
76
  version: '2.6'
66
77
  type: :development
67
78
  prerelease: false
68
- version_requirements: *70155561562780
79
+ version_requirements: *70308912819060
69
80
  - !ruby/object:Gem::Dependency
70
81
  name: rack-test
71
- requirement: &70155561562200 !ruby/object:Gem::Requirement
82
+ requirement: &70308912818400 !ruby/object:Gem::Requirement
72
83
  none: false
73
84
  requirements:
74
85
  - - ~>
@@ -76,10 +87,10 @@ dependencies:
76
87
  version: '0.6'
77
88
  type: :development
78
89
  prerelease: false
79
- version_requirements: *70155561562200
90
+ version_requirements: *70308912818400
80
91
  - !ruby/object:Gem::Dependency
81
92
  name: guard-rspec
82
- requirement: &70155561561580 !ruby/object:Gem::Requirement
93
+ requirement: &70308912817760 !ruby/object:Gem::Requirement
83
94
  none: false
84
95
  requirements:
85
96
  - - ~>
@@ -87,7 +98,7 @@ dependencies:
87
98
  version: '0.4'
88
99
  type: :development
89
100
  prerelease: false
90
- version_requirements: *70155561561580
101
+ version_requirements: *70308912817760
91
102
  description:
92
103
  email:
93
104
  - andrewnez@gmail.com
@@ -134,12 +145,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
145
  - - ! '>='
135
146
  - !ruby/object:Gem::Version
136
147
  version: '0'
148
+ segments:
149
+ - 0
150
+ hash: -3943651241702022185
137
151
  required_rubygems_version: !ruby/object:Gem::Requirement
138
152
  none: false
139
153
  requirements:
140
154
  - - ! '>='
141
155
  - !ruby/object:Gem::Version
142
156
  version: '0'
157
+ segments:
158
+ - 0
159
+ hash: -3943651241702022185
143
160
  requirements: []
144
161
  rubyforge_project: split
145
162
  rubygems_version: 1.8.6