ab_panel 0.2.0 → 0.3.0

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: eddcde97ae111db6ebc623a046cb420165781b04
4
- data.tar.gz: 2eef6a7d7788394cc81c4d508cca4ce598c2aaf0
3
+ metadata.gz: 17de85b0bf79398d4c004cb2a7de53b13347843e
4
+ data.tar.gz: ec7bbc8ade945df459db9f83b754c2cefab9f9c9
5
5
  SHA512:
6
- metadata.gz: 364bb674be3048779273917e7a35fa51927356bf67e9187a323c296b30a0d5d61101d1fae1c8eac20dc3f28a4a8c51e6f7e8d9cee199feca714cb5771851704c
7
- data.tar.gz: 1c0dca5e98a83de0785a7654452ce68881eb6a471530d3758aaad0eb2f85761dfecb2d6b5c3d1626877380d70de84ca3f0ccf03444b18315e86c6735edbbbb69
6
+ metadata.gz: 556d32d1a6b2965db653703aea0a2e02914fc526f80e3a392ceb3bef66374912961b6ab82f7275903e4272fe2aab774d38e123c4b5dbfdc68370fdd69961f474
7
+ data.tar.gz: 9abeeb2287f2ec6626068d4ec89dc185d21cc8bf1d83c66ef29d7ec067439836a3b3c2e6226928fe8746a44369b348a9418cc9d9f9d43cc5b24f9910a5ce3c0a
data/README.md CHANGED
@@ -18,6 +18,35 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install ab_panel
20
20
 
21
+ ## Upgrading from 0.2.0 to 0.3.0
22
+
23
+ In this new version we've added weights to different conditions/scenarios. This
24
+ is so that you can rollout certain features slowly. We've also removed the
25
+ original (control scenario) that is added standard.
26
+
27
+ The only thing you need to do to upgrade is update the ``ab_panel.yml``.
28
+
29
+ Old:
30
+
31
+ ```yaml
32
+
33
+ foo:
34
+ - bar1
35
+ - bar2
36
+
37
+ ```
38
+
39
+ New (if you want to keep original or need original):
40
+
41
+ ```yaml
42
+
43
+ foo:
44
+ bar1: 2
45
+ bar2: 2
46
+ original: 2
47
+
48
+ ```
49
+
21
50
  ## Usage
22
51
 
23
52
  Create a config file with one or more experiments and conditions.
@@ -26,13 +55,14 @@ In `config/ab_panel.yml`
26
55
 
27
56
  ```yaml
28
57
  my_experiment:
29
- - condition_b
30
- - condition_c
58
+ original: 1
59
+ condition_b: 1
60
+ condition_c: 1
31
61
  ```
32
62
 
33
63
  Note that this will create 3 conditions:
34
64
 
35
- 1. Original condition (control condition)
65
+ 1. Original condition
36
66
  2. Condition B
37
67
  3. Condition C
38
68
 
data/ab_panel.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'ab_panel/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ab_panel"
8
8
  spec.version = AbPanel::VERSION
9
- spec.authors = ["Wouter de Vos", "Mark Mulder"]
10
- spec.email = ["wouter@springest.com", "markmulder@gmail.com"]
9
+ spec.authors = ["Wouter de Vos", "Mark Mulder", "Peter de Ruijter"]
10
+ spec.email = ["wouter@springest.com", "markmulder@gmail.com", "hello@thisiswho.im"]
11
11
  spec.description = %q{Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.}
12
12
  spec.summary = %q{Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.}
13
13
  spec.homepage = "https://github.com/Springest/ab_panel"
data/lib/ab_panel.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'set'
2
+ require_relative './array'
3
+
2
4
  Dir[File.expand_path(File.join(
3
5
  File.dirname(__FILE__),'ab_panel','**','*.rb'))]
4
6
  .each {|f| require f}
@@ -37,6 +39,10 @@ module AbPanel
37
39
  config.scenarios experiment
38
40
  end
39
41
 
42
+ def weights(experiment)
43
+ config.weights experiment
44
+ end
45
+
40
46
  def properties
41
47
  @env[:properties]
42
48
  end
@@ -83,7 +89,7 @@ module AbPanel
83
89
  selected = begin
84
90
  already_assigned.send(experiment).condition
85
91
  rescue
86
- scenarios(experiment)[rand(scenarios(experiment).size)]
92
+ scenarios(experiment).weighted_sample(weights(experiment))
87
93
  end
88
94
 
89
95
  cs[experiment]["#{selected}?"] = true
@@ -12,9 +12,13 @@ module AbPanel
12
12
 
13
13
  def scenarios(experiment)
14
14
  raise ArgumentError.new( "Fatal: Experiment config not found for #{experiment}" ) unless experiments.include? experiment.to_sym
15
- ( settings[experiment.to_sym].map(&:to_sym) + [:original] ).uniq
15
+ ( settings[experiment.to_sym].keys.map(&:to_sym)).uniq
16
16
  end
17
17
 
18
+ def weights(experiment)
19
+ raise ArgumentError.new( "Fatal: Experiment config not found for #{experiment}" ) unless experiments.include? experiment.to_sym
20
+ settings[experiment.to_sym].map { |s| s[1] }
21
+ end
18
22
 
19
23
  def settings
20
24
  @settings ||= YAML.load(
@@ -1,3 +1,3 @@
1
1
  module AbPanel
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/array.rb ADDED
@@ -0,0 +1,25 @@
1
+ class Array
2
+ def weighted_sample(weights=nil)
3
+ weights = Array.new(length, 1.0) if weights.nil? || weights.sum == 0
4
+ total = weights.sum
5
+
6
+ # The total sum of weights is multiplied by a random number
7
+ trigger = Kernel::rand * total
8
+
9
+ subtotal = 0
10
+ result = nil
11
+
12
+ # The subtotal is checked agains the trigger. The higher the sum, the higher
13
+ # the probability of triggering a result.
14
+ weights.each_with_index do |weight, index|
15
+ subtotal += weight
16
+
17
+ if subtotal > trigger
18
+ result = self[index]
19
+ break
20
+ end
21
+ end
22
+ # Returns self.last from current array if result is nil
23
+ result || last
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe AbPanel::Config do
4
+ let(:config) { AbPanel::Config.new }
5
+ before do
6
+ AbPanel::Config.any_instance.stub(:settings) { { exp1: { scenario1: 25, scenario2: 75 } } }
7
+ end
8
+
9
+ describe '.experiments' do
10
+ subject { config.experiments }
11
+ it { should =~ [:exp1] }
12
+ end
13
+
14
+ describe '.weights' do
15
+ subject { config.weights('exp1') }
16
+
17
+ it { should =~ [75.0, 25.0] }
18
+ end
19
+ end
@@ -7,6 +7,21 @@ describe AbPanel do
7
7
  it { should =~ %w(experiment1 experiment2).map(&:to_sym) }
8
8
  end
9
9
 
10
+ describe ".weights" do
11
+ let(:experiment) { AbPanel.experiments.first }
12
+ subject { AbPanel.weights(experiment) }
13
+
14
+ it { should == [25, 25, 25, 25] }
15
+
16
+ describe "With a nonexistent experiment" do
17
+ let(:experiment) { :does_not_exist }
18
+
19
+ it 'should throw an ArgumentError' do
20
+ expect { subject }.to raise_exception ArgumentError
21
+ end
22
+ end
23
+ end
24
+
10
25
  describe ".scenarios" do
11
26
  subject { AbPanel.scenarios(experiment) }
12
27
 
@@ -14,7 +29,7 @@ describe AbPanel do
14
29
 
15
30
  it { should =~ %w( scenario1 scenario2 scenario3 original ).map(&:to_sym) }
16
31
 
17
- describe "With an unexisting experiment" do
32
+ describe "With an nonexistent experiment" do
18
33
  let(:experiment) { :does_not_exist }
19
34
 
20
35
  it 'should throw an ArgumentError' do
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+ describe '.weighted_sample' do
5
+ before do
6
+ Kernel.stub(:rand) { 0.5 }
7
+ end
8
+
9
+ context "Stub test" do
10
+ subject { Kernel.rand }
11
+ it { should eq 0.5 }
12
+ end
13
+
14
+ let(:array) { [1, 2, 3, 4] }
15
+ subject { array.weighted_sample }
16
+
17
+ it { should eq 3 }
18
+
19
+ context "different random" do
20
+ before do
21
+ Kernel.stub(:rand) { 0 }
22
+ end
23
+
24
+ it { should eq 1 }
25
+ end
26
+
27
+ context "different random" do
28
+ before do
29
+ Kernel.stub(:rand) { 1 }
30
+ end
31
+
32
+ it { should eq 4 }
33
+ end
34
+
35
+ context "with weights" do
36
+ subject { array.weighted_sample([1, 0, 0, 0]) }
37
+ it { should eq 1 }
38
+ end
39
+
40
+ context "all the same weights" do
41
+ before { Kernel.stub(:rand) { 1 } }
42
+ subject { array.weighted_sample([0, 0, 0, 0]) }
43
+ it { should eq 4 }
44
+ context "random 0" do
45
+ before { Kernel.stub(:rand) { 0 } }
46
+ it { should eq 1 }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,9 +1,11 @@
1
1
  experiment1:
2
- - scenario1
3
- - scenario2
4
- - scenario3
2
+ scenario1: 25
3
+ scenario2: 25
4
+ scenario3: 25
5
+ original: 25
5
6
 
6
7
  experiment2:
7
- - scenario4
8
- - scenario5
8
+ scenario4: 33.4
9
+ scenario5: 33.3
10
+ original: 33.3
9
11
 
metadata CHANGED
@@ -1,124 +1,126 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ab_panel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter de Vos
8
8
  - Mark Mulder
9
+ - Peter de Ruijter
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-11-18 00:00:00.000000000 Z
13
+ date: 2014-03-18 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: bundler
16
17
  requirement: !ruby/object:Gem::Requirement
17
18
  requirements:
18
- - - ~>
19
+ - - "~>"
19
20
  - !ruby/object:Gem::Version
20
21
  version: '1.3'
21
22
  type: :development
22
23
  prerelease: false
23
24
  version_requirements: !ruby/object:Gem::Requirement
24
25
  requirements:
25
- - - ~>
26
+ - - "~>"
26
27
  - !ruby/object:Gem::Version
27
28
  version: '1.3'
28
29
  - !ruby/object:Gem::Dependency
29
30
  name: rails
30
31
  requirement: !ruby/object:Gem::Requirement
31
32
  requirements:
32
- - - ~>
33
+ - - "~>"
33
34
  - !ruby/object:Gem::Version
34
35
  version: '3.2'
35
36
  type: :development
36
37
  prerelease: false
37
38
  version_requirements: !ruby/object:Gem::Requirement
38
39
  requirements:
39
- - - ~>
40
+ - - "~>"
40
41
  - !ruby/object:Gem::Version
41
42
  version: '3.2'
42
43
  - !ruby/object:Gem::Dependency
43
44
  name: rake
44
45
  requirement: !ruby/object:Gem::Requirement
45
46
  requirements:
46
- - - '>='
47
+ - - ">="
47
48
  - !ruby/object:Gem::Version
48
49
  version: '0'
49
50
  type: :development
50
51
  prerelease: false
51
52
  version_requirements: !ruby/object:Gem::Requirement
52
53
  requirements:
53
- - - '>='
54
+ - - ">="
54
55
  - !ruby/object:Gem::Version
55
56
  version: '0'
56
57
  - !ruby/object:Gem::Dependency
57
58
  name: fakeweb
58
59
  requirement: !ruby/object:Gem::Requirement
59
60
  requirements:
60
- - - '>='
61
+ - - ">="
61
62
  - !ruby/object:Gem::Version
62
63
  version: '0'
63
64
  type: :development
64
65
  prerelease: false
65
66
  version_requirements: !ruby/object:Gem::Requirement
66
67
  requirements:
67
- - - '>='
68
+ - - ">="
68
69
  - !ruby/object:Gem::Version
69
70
  version: '0'
70
71
  - !ruby/object:Gem::Dependency
71
72
  name: rspec
72
73
  requirement: !ruby/object:Gem::Requirement
73
74
  requirements:
74
- - - '>='
75
+ - - ">="
75
76
  - !ruby/object:Gem::Version
76
77
  version: '0'
77
78
  type: :development
78
79
  prerelease: false
79
80
  version_requirements: !ruby/object:Gem::Requirement
80
81
  requirements:
81
- - - '>='
82
+ - - ">="
82
83
  - !ruby/object:Gem::Version
83
84
  version: '0'
84
85
  - !ruby/object:Gem::Dependency
85
86
  name: debugger
86
87
  requirement: !ruby/object:Gem::Requirement
87
88
  requirements:
88
- - - '>='
89
+ - - ">="
89
90
  - !ruby/object:Gem::Version
90
91
  version: '0'
91
92
  type: :development
92
93
  prerelease: false
93
94
  version_requirements: !ruby/object:Gem::Requirement
94
95
  requirements:
95
- - - '>='
96
+ - - ">="
96
97
  - !ruby/object:Gem::Version
97
98
  version: '0'
98
99
  - !ruby/object:Gem::Dependency
99
100
  name: mixpanel
100
101
  requirement: !ruby/object:Gem::Requirement
101
102
  requirements:
102
- - - '>='
103
+ - - ">="
103
104
  - !ruby/object:Gem::Version
104
105
  version: '0'
105
106
  type: :runtime
106
107
  prerelease: false
107
108
  version_requirements: !ruby/object:Gem::Requirement
108
109
  requirements:
109
- - - '>='
110
+ - - ">="
110
111
  - !ruby/object:Gem::Version
111
112
  version: '0'
112
113
  description: Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.
113
114
  email:
114
115
  - wouter@springest.com
115
116
  - markmulder@gmail.com
117
+ - hello@thisiswho.im
116
118
  executables: []
117
119
  extensions: []
118
120
  extra_rdoc_files: []
119
121
  files:
120
- - .gitignore
121
- - .travis.yml
122
+ - ".gitignore"
123
+ - ".travis.yml"
122
124
  - Gemfile
123
125
  - LICENSE.txt
124
126
  - README.md
@@ -196,9 +198,12 @@ files:
196
198
  - lib/ab_panel/javascript.rb
197
199
  - lib/ab_panel/mixpanel.rb
198
200
  - lib/ab_panel/version.rb
201
+ - lib/array.rb
202
+ - spec/ab_panel/config_spec.rb
199
203
  - spec/ab_panel/controller_additions_spec.rb
200
204
  - spec/ab_panel/javascript_spec.rb
201
205
  - spec/ab_panel_spec.rb
206
+ - spec/array_spec.rb
202
207
  - spec/spec_helper.rb
203
208
  - spec/support/fakeweb.rb
204
209
  - spec/support/files/config/ab_panel.yml
@@ -213,17 +218,17 @@ require_paths:
213
218
  - lib
214
219
  required_ruby_version: !ruby/object:Gem::Requirement
215
220
  requirements:
216
- - - '>='
221
+ - - ">="
217
222
  - !ruby/object:Gem::Version
218
223
  version: '0'
219
224
  required_rubygems_version: !ruby/object:Gem::Requirement
220
225
  requirements:
221
- - - '>='
226
+ - - ">="
222
227
  - !ruby/object:Gem::Version
223
228
  version: '0'
224
229
  requirements: []
225
230
  rubyforge_project:
226
- rubygems_version: 2.0.3
231
+ rubygems_version: 2.2.0
227
232
  signing_key:
228
233
  specification_version: 4
229
234
  summary: Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.
@@ -294,9 +299,11 @@ test_files:
294
299
  - example/vendor/assets/javascripts/.gitkeep
295
300
  - example/vendor/assets/stylesheets/.gitkeep
296
301
  - example/vendor/plugins/.gitkeep
302
+ - spec/ab_panel/config_spec.rb
297
303
  - spec/ab_panel/controller_additions_spec.rb
298
304
  - spec/ab_panel/javascript_spec.rb
299
305
  - spec/ab_panel_spec.rb
306
+ - spec/array_spec.rb
300
307
  - spec/spec_helper.rb
301
308
  - spec/support/fakeweb.rb
302
309
  - spec/support/files/config/ab_panel.yml