split 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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