ablab 0.2.0 → 0.2.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.
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