ablab 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82b09b75abb045ba604cc9940801370381565a4f
4
- data.tar.gz: 7687acf2d7bf62c7027eea04b411f143b6651093
3
+ metadata.gz: cd4478bb1810dd0d5afddf97eb299cf2ebaf343b
4
+ data.tar.gz: 0290705fe61858b5b355fee0ade8d9bb3e44a5fc
5
5
  SHA512:
6
- metadata.gz: dd0c52bec7918a4f6c783311647fc59e6f92b217c0807474036e97a173679e7d29e2d6b419c3de87c0c61b0809dcb0260500e64200dfc330d23573ec20778ca0
7
- data.tar.gz: 0ca01138cc6a81182efc7cd0bf862141fbd68baba8e516b10400315f9fe0088fcd54ef3a4d75570d99e1b10d2f3ee132600da5c06caf81d629a921450ba3f557
6
+ metadata.gz: e6ec28c30693a9030cd5d995d2d73242be556d16b0ac8167458d8bcec811c76a309250c0e610a02158654b04f9cb3d565dca8dea141ccca4b65658a9e53c380a
7
+ data.tar.gz: 1a4b4e194003966c232068aa3bc1f4e0bde85751746aee96c76ddf60b6ad1a828f63074185e57c5157f0a099589541bb172e4f00ec8cf23cc7b917ce68e4b5b4
@@ -16,4 +16,4 @@ var Ablab = (function(scripts) {
16
16
  currentScript.parentNode.appendChild(script);
17
17
  }
18
18
  }
19
- })(document.getElementsByTagName("script"));
19
+ }(document.getElementsByTagName("script")));
@@ -3,10 +3,14 @@
3
3
  They will automatically be included in application.css.
4
4
  */
5
5
 
6
- * {
6
+ html {
7
7
  box-sizing: border-box;
8
8
  }
9
9
 
10
+ *, *:before, *:after {
11
+ box-sizing: inherit;
12
+ }
13
+
10
14
  body {
11
15
  font-family: sans-serif;
12
16
  background: #f5f5f5;
@@ -91,9 +95,24 @@ table th {
91
95
  border: none;
92
96
  border-bottom: 2px solid #e96e25;
93
97
  border-left: 1px dotted #e96e25;
98
+ cursor: help;
94
99
  }
95
100
 
96
101
  table {
97
102
  border: 1px solid #ffa26b;
98
103
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
99
104
  }
105
+
106
+ th i {
107
+ display: none;
108
+ position: absolute;
109
+ font-size: 12px;
110
+ font-weight: normal;
111
+ background: #ffa26b;
112
+ padding: 0.5em 0.809em;
113
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
114
+ }
115
+
116
+ th:hover i {
117
+ display: block;
118
+ }
@@ -8,10 +8,12 @@ module Ablab
8
8
 
9
9
  def track
10
10
  exp = experiment(params[:experiment].to_sym)
11
- if params[:event] == 'success'
12
- exp.track_success!
13
- else
14
- exp.track_view!
11
+ Thread.new do
12
+ if params[:event] == 'success'
13
+ exp.track_success!
14
+ else
15
+ exp.track_view!
16
+ end
15
17
  end
16
18
  respond_to do |format|
17
19
  format.js
@@ -15,8 +15,9 @@ module Ablab
15
15
  '%.3f' % decimal
16
16
  end
17
17
 
18
- def significant?(z_score)
19
- z_score && z_score >= 1.65
18
+ def significant?(results)
19
+ return false if results[:sessions] < 30 || results[:conversions] < 5
20
+ results[:z_score] && results[:z_score] >= 1.65
20
21
  end
21
22
 
22
23
  def confidence(z_score, na = 'n/a')
@@ -40,7 +41,7 @@ module Ablab
40
41
  -1
41
42
  end
42
43
  end
43
- significant?(winner_results[:z_score]) && winner_name == group_name
44
+ significant?(winner_results) && winner_name == group_name
44
45
  end
45
46
  end
46
47
  end
@@ -11,15 +11,34 @@
11
11
  <% end %>
12
12
  <table>
13
13
  <tr>
14
- <th>Group</th>
15
- <th>Description</th>
16
- <th>Views</th>
17
- <th>Sessions</th>
18
- <th>Successes</th>
19
- <th>Conversions</th>
20
- <th>Conversion rate</th>
21
- <th>Z-score</th>
22
- <th>Confidence</th>
14
+ <th>Group
15
+ <i>The group, defining a variant of the experiment</i>
16
+ </th>
17
+ <th>Description
18
+ <i>The description of the variant of the experiment corresponding to a group</i>
19
+ </th>
20
+ <th>Views
21
+ <i>How many times the experiment was viewed in a group</i>
22
+ </th>
23
+ <th>Sessions
24
+ <i>How many unique visitors in a group viewed the experiment</i>
25
+ </th>
26
+ <th>Successes
27
+ <i>How many times the goal was reached for a group</i>
28
+ </th>
29
+ <th>Conversions
30
+ <i>How many unique visitors in a group reached the goal</i>
31
+ </th>
32
+ <th>Conversion rate
33
+ <i>Ratio of convertions over sessions</i>
34
+ </th>
35
+ <th>Z-score
36
+ <i>Z-score for the confidence testing</i>
37
+ </th>
38
+ <th>Confidence
39
+ <i>Probability that this group is having a real effect on the
40
+ conversion rate, compared to the control group</i>
41
+ </th>
23
42
  </tr>
24
43
  <% experiment.results.each do |group_name, results| %>
25
44
  <tr class="<%= 'winner' if winner?(experiment, group_name) %> <%= 'control' if results[:control] %>">
@@ -65,6 +65,11 @@ module Ablab
65
65
  @goal
66
66
  end
67
67
 
68
+ def percentage_of_visitors(percentage = nil)
69
+ @percentage_of_visitors = percentage if percentage
70
+ @percentage_of_visitors || 100
71
+ end
72
+
68
73
  def group(name, options = {})
69
74
  group = Group.new(name, options[:description])
70
75
  @groups << group
@@ -85,7 +90,6 @@ module Ablab
85
90
 
86
91
  def initialize(experiment, session_id)
87
92
  @experiment, @session_id = experiment, session_id
88
- @experiment = experiment
89
93
  end
90
94
 
91
95
  def in_group?(name)
@@ -102,8 +106,9 @@ module Ablab
102
106
 
103
107
  def group
104
108
  return @group unless @group.nil?
105
- idx = (draw / (1000.0 / experiment.groups.size)).floor
106
- @group = experiment.groups[idx].name
109
+ size = 1000.0 * (experiment.percentage_of_visitors) / 100.0
110
+ idx = (draw * experiment.groups.size / size).floor
111
+ @group = experiment.groups[idx].try(:name)
107
112
  end
108
113
 
109
114
  def draw
@@ -5,27 +5,25 @@ module Ablab
5
5
  class Memory
6
6
  def initialize
7
7
  @views = Hash.new do |hash, key|
8
- hash[key] = Hash.new { |hash, key| hash[key] = 0 }
8
+ hash[key] = Hash.new { |h, k| h[k] = 0 }
9
9
  end
10
10
  @sessions = Hash.new do |hash, key|
11
- hash[key] = Hash.new { |hash, key| hash[key] = Set.new }
11
+ hash[key] = Hash.new { |h, k| h[k] = Set.new }
12
12
  end
13
13
  @successes = Hash.new do |hash, key|
14
- hash[key] = Hash.new { |hash, key| hash[key] = 0 }
14
+ hash[key] = Hash.new { |h, k| h[k] = 0 }
15
15
  end
16
16
  @conversions = Hash.new do |hash, key|
17
- hash[key] = Hash.new { |hash, key| hash[key] = Set.new }
17
+ hash[key] = Hash.new { |h, k| h[k] = Set.new }
18
18
  end
19
19
  end
20
20
 
21
21
  def track_view!(experiment, bucket, session_id)
22
- @views[experiment][bucket] += 1
23
- @sessions[experiment][bucket].add(session_id)
22
+ track(experiment, bucket, session_id, @views, @sessions)
24
23
  end
25
24
 
26
25
  def track_success!(experiment, bucket, session_id)
27
- @successes[experiment][bucket] += 1
28
- @conversions[experiment][bucket].add(session_id)
26
+ track(experiment, bucket, session_id, @successes, @conversions)
29
27
  end
30
28
 
31
29
  def views(experiment, bucket)
@@ -52,6 +50,12 @@ module Ablab
52
50
  conversions: conversions(experiment, bucket)
53
51
  }
54
52
  end
53
+
54
+ private def track(experiment, bucket, session_id, counter, set)
55
+ return false if bucket.nil?
56
+ counter[experiment][bucket] += 1
57
+ set[experiment][bucket].add(session_id)
58
+ end
55
59
  end
56
60
  end
57
61
  end
@@ -11,17 +11,11 @@ module Ablab
11
11
  end
12
12
 
13
13
  def track_view!(experiment, bucket, session_id)
14
- redis.pipelined do
15
- redis.incr(key(:views, experiment, bucket))
16
- redis.pfadd(key(:sessions, experiment, bucket), session_id)
17
- end
14
+ track(experiment, bucket, session_id, :views, :sessions)
18
15
  end
19
16
 
20
17
  def track_success!(experiment, bucket, session_id)
21
- redis.pipelined do
22
- redis.incr(key(:successes, experiment, bucket))
23
- redis.pfadd(key(:conversions, experiment, bucket), session_id)
24
- end
18
+ track(experiment, bucket, session_id, :successes, :conversions)
25
19
  end
26
20
 
27
21
  def views(experiment, bucket)
@@ -59,6 +53,14 @@ module Ablab
59
53
  private def key(type, experiment, bucket)
60
54
  "#{@key_prefix}:#{type}:#{experiment}:#{bucket}"
61
55
  end
56
+
57
+ private def track(experiment, bucket, session_id, counter, set)
58
+ return false if bucket.nil?
59
+ redis.pipelined do
60
+ redis.incr(key(counter, experiment, bucket))
61
+ redis.pfadd(key(set, experiment, bucket), session_id)
62
+ end
63
+ end
62
64
  end
63
65
  end
64
66
  end
@@ -1,3 +1,3 @@
1
1
  module Ablab
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -2,6 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.shared_examples 'store' do
4
4
  describe '#track_view!' do
5
+ it 'returns false if group is nil' do
6
+ expect(store.track_view!(:foo, nil, 'abc')).to be(false)
7
+ end
8
+
5
9
  it 'tracks views' do
6
10
  5.times { store.track_view!(:foo, :a, 'abc') }
7
11
  7.times { store.track_view!(:foo, :b, 'abc') }
@@ -23,6 +27,10 @@ RSpec.shared_examples 'store' do
23
27
  end
24
28
 
25
29
  describe '#track_success!' do
30
+ it 'returns false if group is nil' do
31
+ expect(store.track_success!(:foo, nil, 'abc')).to be(false)
32
+ end
33
+
26
34
  it 'tracks successes' do
27
35
  5.times { store.track_success!(:foo, :a, 'abc') }
28
36
  7.times { store.track_success!(:foo, :b, 'abc') }
@@ -74,13 +74,24 @@ describe Ablab do
74
74
  end
75
75
  end
76
76
 
77
- describe '#description' do
77
+ describe '#goal' do
78
78
  it 'sets the experiment goal' do
79
79
  experiment.goal 'foo bar'
80
80
  expect(experiment.goal).to eq('foo bar')
81
81
  end
82
82
  end
83
83
 
84
+ describe '#percentage_of_visitors' do
85
+ it 'returns 100 if never set' do
86
+ expect(experiment.percentage_of_visitors).to eq(100)
87
+ end
88
+
89
+ it 'sets the percentage of visitors included in the experiment' do
90
+ experiment.percentage_of_visitors 25
91
+ expect(experiment.percentage_of_visitors).to eq(25)
92
+ end
93
+ end
94
+
84
95
  describe '#group' do
85
96
  it 'creates a group' do
86
97
  experiment.group :a, description: 'foo bar baz'
@@ -156,5 +167,21 @@ describe Ablab do
156
167
  run2 = Ablab::Run.new(experiment, 'foobar')
157
168
  expect(run1.group).to eq(run2.group)
158
169
  end
170
+
171
+ it 'selects only the given percentage of users' do
172
+ experiment.percentage_of_visitors 30
173
+ run = Ablab::Run.new(experiment, 0)
174
+ allow(run).to receive(:draw).and_return 0
175
+ expect(run).to be_in_group(:control)
176
+ run = Ablab::Run.new(experiment, 0)
177
+ allow(run).to receive(:draw).and_return 100
178
+ expect(run).to be_in_group(:a)
179
+ run = Ablab::Run.new(experiment, 0)
180
+ allow(run).to receive(:draw).and_return 200
181
+ expect(run).to be_in_group(:b)
182
+ run = Ablab::Run.new(experiment, 0)
183
+ allow(run).to receive(:draw).and_return 300
184
+ expect(run.group).to be_nil
185
+ end
159
186
  end
160
187
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ablab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Ongaro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-12 00:00:00.000000000 Z
11
+ date: 2016-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -115,7 +115,7 @@ files:
115
115
  - spec/ablab/store/store_examples.rb
116
116
  - spec/ablab_spec.rb
117
117
  - spec/spec_helper.rb
118
- homepage:
118
+ homepage: https://github.com/lucaong/ablab
119
119
  licenses:
120
120
  - MIT
121
121
  metadata: {}
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  version: '0'
136
136
  requirements: []
137
137
  rubyforge_project:
138
- rubygems_version: 2.5.1
138
+ rubygems_version: 2.2.2
139
139
  signing_key:
140
140
  specification_version: 4
141
141
  summary: Ablab - A/B testing on Rails