ab_panel 0.3.3 → 0.4.4

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
- SHA1:
3
- metadata.gz: fe1dec59d88584288c8ada336cae1788b0fd0543
4
- data.tar.gz: d212f5ecd9685c359720bf935750582fe6036be9
2
+ SHA256:
3
+ metadata.gz: 37ee0a4c2ef876a4211289f684ba7db3d620d34bfdd2a54081bbc92c0b94240b
4
+ data.tar.gz: 47f71b412b1021c6b3f7034e209f4c80a490950b1ce1b92e68070b1d12ae84d8
5
5
  SHA512:
6
- metadata.gz: 980f2a2130011fce8dd78002f15546d701ddf15de16477588aeba852b140431e4931854d63ac660443757358d8b4fb38c74a094beb715583debf1bebde515fc3
7
- data.tar.gz: 582ef9a3270130ad244b76137225cf0df80b88154f00a2e20a4cee68706a924ada234619ddb8928ba8a20f946ccf505d32a1eab15890530ed9128cda6a37a854
6
+ metadata.gz: becb21058455ab271a01771df8643c0002141d0f8836ae77503f516aaaeee2f187cc7d6965c6207cee572ef54413a186e230c6bc64fb72f1f89f0c7a0051fde6
7
+ data.tar.gz: cbb3437fd90843d080251acf50302be43abd2f12403129442f5d1c439789bdcf8061cd9861327b1b9c5b3df1dc0d91120fd0f9e885c4723a8b24877444d5cd31
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  language: ruby
2
2
  script: 'bundle exec rspec spec'
3
3
  rvm:
4
- - 2.1.5
4
+ - 2.1.7
data/ab_panel.gemspec CHANGED
@@ -6,10 +6,9 @@ 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", "Peter de Ruijter"]
10
- spec.email = ["wouter@springest.com", "markmulder@gmail.com", "hello@thisiswho.im"]
11
- spec.description = %q{Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.}
12
- spec.summary = %q{Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.}
9
+ spec.authors = ["Dennis Paagman", "Eugene Pimenov", "Jordy van Gelder", "Mark Mulder", "Peter de Ruijter", "Tim Flapper", "Wouter de Vos"]
10
+ spec.description = %q{Run A/B test experiments on your Rails 4+ site using Mixpanel as a backend.}
11
+ spec.summary = %q{Run A/B test experiments on your Rails 4+ site using Mixpanel as a backend.}
13
12
  spec.homepage = "https://github.com/Springest/ab_panel"
14
13
  spec.license = "MIT"
15
14
 
@@ -19,11 +18,11 @@ Gem::Specification.new do |spec|
19
18
  spec.require_paths = ["lib"]
20
19
 
21
20
  spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rails", '~> 3.2'
23
21
  spec.add_development_dependency "rake"
24
22
  spec.add_development_dependency "fakeweb"
25
23
  spec.add_development_dependency "rspec"
26
24
  spec.add_development_dependency "byebug"
27
25
 
26
+ spec.add_runtime_dependency "rails", '>= 4.0'
28
27
  spec.add_runtime_dependency "mixpanel"
29
28
  end
data/lib/ab_panel.rb CHANGED
@@ -22,6 +22,16 @@ module AbPanel
22
22
  Thread.current[:ab_panel_conditions] ||= assign_conditions!
23
23
  end
24
24
 
25
+ def serialized_conditions
26
+ cs = {}
27
+
28
+ conditions.each_pair do |key, value|
29
+ cs[key] = value.marshal_dump
30
+ end
31
+
32
+ cs.to_json
33
+ end
34
+
25
35
  # Set the experiment's conditions.
26
36
  #
27
37
  # This is used to persist conditions from
@@ -74,11 +84,30 @@ module AbPanel
74
84
  funnels.add(funnel) if funnel.present?
75
85
  end
76
86
 
87
+ def environment
88
+ props = { distinct_id: self.env["distinct_id"] }
89
+ props.merge!(self.properties) if self.properties
90
+
91
+ self.funnels.each { |f| props["funnel_#{f}"] = true }
92
+
93
+ self.experiments.each { |exp| props[exp] = self.conditions.send(exp).condition }
94
+
95
+ props
96
+ end
97
+
77
98
  private # ----------------------------------------------------------------------------
78
99
 
79
100
  def assign_conditions!(already_assigned=nil)
80
101
  cs = {}
81
102
 
103
+ if already_assigned
104
+ already_assigned.each do |key, value|
105
+ already_assigned[key] = OpenStruct.new(already_assigned[key])
106
+ end
107
+ end
108
+
109
+ already_assigned = OpenStruct.new already_assigned
110
+
82
111
  experiments.each do |experiment|
83
112
  cs[experiment] ||= {}
84
113
 
@@ -27,8 +27,20 @@ module AbPanel
27
27
  #
28
28
  # `current_user.id` for logged in users.
29
29
  def distinct_id
30
- cookies.signed['distinct_id'] ||=
31
- (0..4).map { |i| i.even? ? ('A'..'Z').to_a[rand(26)] : rand(10) }.join
30
+ distinct_id = cookies.signed['distinct_id']
31
+
32
+ return distinct_id if distinct_id
33
+
34
+ distinct_id = (0..4).map { |i| i.even? ? ('A'..'Z').to_a[rand(26)] : rand(10) }.join
35
+
36
+ cookies.signed['distinct_id'] =
37
+ {
38
+ value: distinct_id,
39
+ httponly: true,
40
+ secure: request.ssl?
41
+ }
42
+
43
+ distinct_id
32
44
  end
33
45
 
34
46
  def ab_panel_options
@@ -48,10 +60,27 @@ module AbPanel
48
60
  # in the user's session.
49
61
  def initialize_ab_panel!(options = {})
50
62
  AbPanel.reset!
51
- AbPanel.conditions = cookies.signed['ab_panel_conditions']
52
- cookies.signed['ab_panel_conditions'] = AbPanel.conditions
53
- AbPanel.funnels = cookies.signed['ab_panel_funnels']
54
- cookies.signed['ab_panel_funnels'] = AbPanel.funnels
63
+
64
+
65
+ AbPanel.conditions =
66
+ if cookies.signed[:ab_panel_conditions]
67
+ JSON.parse(cookies.signed[:ab_panel_conditions])
68
+ else
69
+ nil
70
+ end
71
+
72
+ cookies.signed[:ab_panel_conditions] = {
73
+ value: AbPanel.serialized_conditions,
74
+ httponly: true,
75
+ secure: request.ssl?
76
+ }
77
+
78
+ AbPanel.funnels = Set.new(cookies.signed[:ab_panel_funnels])
79
+ cookies.signed[:ab_panel_funnels] = {
80
+ value: AbPanel.funnels,
81
+ httponly: true,
82
+ secure: request.ssl?
83
+ }
55
84
 
56
85
  {
57
86
  'distinct_id' => distinct_id,
@@ -80,7 +109,6 @@ module AbPanel
80
109
 
81
110
  options = {
82
111
  distinct_id: distinct_id,
83
- ip: request.remote_ip,
84
112
  time: Time.now.utc,
85
113
  }.merge(properties)
86
114
 
@@ -1,14 +1,8 @@
1
1
  module AbPanel
2
2
  class Javascript
3
3
  def self.environment
4
- props = { distinct_id: AbPanel.env["distinct_id"] }
5
- props.merge!(AbPanel.properties) if AbPanel.properties
6
-
7
- AbPanel.funnels.each { |f| props["funnel_#{f}"] = true }
8
-
9
- AbPanel.experiments.each { |exp| props[exp] = AbPanel.conditions.send(exp).condition }
10
-
11
- props.to_json
4
+ AbPanel.environment.to_json
12
5
  end
6
+
13
7
  end
14
8
  end
@@ -1,3 +1,3 @@
1
1
  module AbPanel
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.4"
3
3
  end
@@ -4,32 +4,32 @@ describe AbPanel::Config do
4
4
  let(:config) { AbPanel::Config.new }
5
5
  context "config" do
6
6
  before do
7
- AbPanel::Config.any_instance.stub(:settings) { { exp1: { scenario1: 25, scenario2: 75 } } }
7
+ allow_any_instance_of(AbPanel::Config).to receive(:settings) { { exp1: { scenario1: 25, scenario2: 75 } } }
8
8
  end
9
9
 
10
10
  describe '.experiments' do
11
11
  subject { config.experiments }
12
- it { should =~ [:exp1] }
12
+ it { is_expected.to match_array [:exp1] }
13
13
  end
14
14
 
15
15
  describe '.weights' do
16
16
  subject { config.weights('exp1') }
17
17
 
18
- it { should =~ [75.0, 25.0] }
18
+ it { is_expected.to match_array [75.0, 25.0] }
19
19
  end
20
20
  end
21
21
  context "empty config" do
22
22
  before do
23
- YAML.stub(:load) { false }
23
+ allow(YAML).to receive(:load) { false }
24
24
  end
25
25
  describe ".settings" do
26
26
  subject { config.settings }
27
- it { should eq nil }
27
+ it { is_expected.to eq nil }
28
28
  end
29
29
 
30
30
  describe ".experiments" do
31
31
  subject { config.experiments }
32
- it { should == {} }
32
+ it { is_expected.to eq({}) }
33
33
  end
34
34
  end
35
35
  end
@@ -13,9 +13,12 @@ describe AbPanel::ControllerAdditions do
13
13
 
14
14
  describe "#distinct_id" do
15
15
  let(:cookies) { {} }
16
- before { controller.stub_chain(:cookies, :signed).and_return(cookies) }
16
+ before do
17
+ allow(controller).to receive_message_chain(:request, :ssl?).and_return(true)
18
+ allow(controller).to receive_message_chain(:cookies, :signed).and_return(cookies)
19
+ end
17
20
  subject { controller.distinct_id }
18
21
 
19
- it { should match /^([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])$/ }
22
+ it { is_expected.to match /^([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])([A-Z]|[0-9])$/ }
20
23
  end
21
24
  end
@@ -5,12 +5,12 @@ describe AbPanel::Javascript do
5
5
  AbPanel.set_env('distinct_id', 'distinct_id')
6
6
  AbPanel.set_env(:properties, { post_name: 'test' })
7
7
  result = JSON.parse(AbPanel::Javascript.environment)
8
- result['distinct_id'].should == 'distinct_id'
8
+ expect(result['distinct_id']).to eq 'distinct_id'
9
9
  end
10
10
 
11
11
  it 'works without extra properties' do
12
12
  AbPanel.set_env(:properties, nil)
13
13
  result = JSON.parse(AbPanel::Javascript.environment)
14
- result['distinct_id'].should == 'distinct_id'
14
+ expect(result['distinct_id']).to eq 'distinct_id'
15
15
  end
16
16
  end
@@ -4,14 +4,14 @@ describe AbPanel do
4
4
  describe ".experiments" do
5
5
  subject { AbPanel.experiments }
6
6
 
7
- it { should =~ %w(experiment1 experiment2).map(&:to_sym) }
7
+ it { is_expected.to match_array %w(experiment1 experiment2).map(&:to_sym) }
8
8
  end
9
9
 
10
10
  describe ".weights" do
11
11
  let(:experiment) { AbPanel.experiments.first }
12
12
  subject { AbPanel.weights(experiment) }
13
13
 
14
- it { should == [25, 25, 25, 25] }
14
+ it { is_expected.to eq [25, 25, 25, 25] }
15
15
 
16
16
  describe "With a nonexistent experiment" do
17
17
  let(:experiment) { :does_not_exist }
@@ -27,7 +27,7 @@ describe AbPanel do
27
27
 
28
28
  let(:experiment) { AbPanel.experiments.first }
29
29
 
30
- it { should =~ %w( scenario1 scenario2 scenario3 original ).map(&:to_sym) }
30
+ it { is_expected.to match_array %w( scenario1 scenario2 scenario3 original ).map(&:to_sym) }
31
31
 
32
32
  describe "With an nonexistent experiment" do
33
33
  let(:experiment) { :does_not_exist }
@@ -41,8 +41,8 @@ describe AbPanel do
41
41
  describe ".conditions" do
42
42
  subject { AbPanel.conditions.experiment1 }
43
43
 
44
- it { should respond_to :scenario1? }
45
- it { should respond_to :original? }
44
+ it { is_expected.to respond_to :scenario1? }
45
+ it { is_expected.to respond_to :original? }
46
46
 
47
47
  describe 'uniqueness' do
48
48
  let(:conditions) do
@@ -54,10 +54,10 @@ describe AbPanel do
54
54
  ]
55
55
  end
56
56
 
57
- it { conditions.any?.should be true }
58
- it { conditions.all?.should be false }
59
- it { conditions.select{|c| c}.size.should be 1 }
60
- it { conditions.reject{|c| c}.size.should be 3 }
57
+ it { expect(conditions.any?).to be true }
58
+ it { expect(conditions.all?).to be false }
59
+ it { expect(conditions.select{|c| c}.size).to be 1 }
60
+ it { expect(conditions.reject{|c| c}.size).to be 3 }
61
61
  end
62
62
  end
63
63
 
@@ -72,24 +72,24 @@ describe AbPanel do
72
72
 
73
73
  it 'adds a funnel' do
74
74
  AbPanel.add_funnel('search')
75
- AbPanel.funnels.to_a.should == ['search']
75
+ expect(AbPanel.funnels.to_a).to eq ['search']
76
76
  end
77
77
 
78
78
  it 'only adds a funnel when present' do
79
79
  AbPanel.add_funnel(nil)
80
- AbPanel.funnels.to_a.should == []
80
+ expect(AbPanel.funnels.to_a).to eq []
81
81
  end
82
82
 
83
83
  it 'does not add a funnel twice' do
84
84
  AbPanel.add_funnel('search')
85
85
  AbPanel.add_funnel('search')
86
- AbPanel.funnels.to_a.should == ['search']
86
+ expect(AbPanel.funnels.to_a).to eq ['search']
87
87
  end
88
88
 
89
89
  it 'sets funnels' do
90
90
  funnels = Set.new ['search', 'cta']
91
91
  AbPanel.funnels = funnels
92
- AbPanel.funnels.to_a.should == funnels.to_a
92
+ expect(AbPanel.funnels.to_a).to eq funnels.to_a
93
93
  end
94
94
  end
95
95
 
data/spec/array_spec.rb CHANGED
@@ -3,47 +3,47 @@ require 'spec_helper'
3
3
  describe Array do
4
4
  describe '.weighted_sample' do
5
5
  before do
6
- Kernel.stub(:rand) { 0.5 }
6
+ allow(Kernel).to receive(:rand) { 0.5 }
7
7
  end
8
8
 
9
9
  context "Stub test" do
10
10
  subject { Kernel.rand }
11
- it { should eq 0.5 }
11
+ it { is_expected.to eq 0.5 }
12
12
  end
13
13
 
14
14
  let(:array) { [1, 2, 3, 4] }
15
15
  subject { array.weighted_sample }
16
16
 
17
- it { should eq 3 }
17
+ it { is_expected.to eq 3 }
18
18
 
19
19
  context "different random" do
20
20
  before do
21
- Kernel.stub(:rand) { 0 }
21
+ allow(Kernel).to receive(:rand) { 0 }
22
22
  end
23
23
 
24
- it { should eq 1 }
24
+ it { is_expected.to eq 1 }
25
25
  end
26
26
 
27
27
  context "different random" do
28
28
  before do
29
- Kernel.stub(:rand) { 1 }
29
+ allow(Kernel).to receive(:rand) { 1 }
30
30
  end
31
31
 
32
- it { should eq 4 }
32
+ it { is_expected.to eq 4 }
33
33
  end
34
34
 
35
35
  context "with weights" do
36
36
  subject { array.weighted_sample([1, 0, 0, 0]) }
37
- it { should eq 1 }
37
+ it { is_expected.to eq 1 }
38
38
  end
39
-
39
+
40
40
  context "all the same weights" do
41
- before { Kernel.stub(:rand) { 1 } }
41
+ before { allow(Kernel).to receive(:rand) { 1 } }
42
42
  subject { array.weighted_sample([0, 0, 0, 0]) }
43
- it { should eq 4 }
43
+ it { is_expected.to eq 4 }
44
44
  context "random 0" do
45
- before { Kernel.stub(:rand) { 0 } }
46
- it { should eq 1 }
45
+ before { allow(Kernel).to receive(:rand) { 0 } }
46
+ it { is_expected.to eq 1 }
47
47
  end
48
48
  end
49
49
  end
data/spec/spec_helper.rb CHANGED
@@ -5,4 +5,3 @@ require 'active_support/all'
5
5
  require File.join(File.dirname(__FILE__), "../lib", "ab_panel")
6
6
 
7
7
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
8
-
@@ -2,7 +2,7 @@ require 'rails'
2
2
 
3
3
  RSpec.configure do |c|
4
4
  c.before do
5
- Rails.stub(:root) { File.expand_path( '../files', __FILE__ ) }
6
- Rails.stub(:env) { 'test' }
5
+ allow(Rails).to receive(:root) { File.expand_path( '../files', __FILE__ ) }
6
+ allow(Rails).to receive(:env) { 'test' }
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,16 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ab_panel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
- - Wouter de Vos
7
+ - Dennis Paagman
8
+ - Eugene Pimenov
9
+ - Jordy van Gelder
8
10
  - Mark Mulder
9
11
  - Peter de Ruijter
10
- autorequire:
12
+ - Tim Flapper
13
+ - Wouter de Vos
14
+ autorequire:
11
15
  bindir: bin
12
16
  cert_chain: []
13
- date: 2015-08-11 00:00:00.000000000 Z
17
+ date: 2021-07-01 00:00:00.000000000 Z
14
18
  dependencies:
15
19
  - !ruby/object:Gem::Dependency
16
20
  name: bundler
@@ -27,21 +31,21 @@ dependencies:
27
31
  - !ruby/object:Gem::Version
28
32
  version: '1.3'
29
33
  - !ruby/object:Gem::Dependency
30
- name: rails
34
+ name: rake
31
35
  requirement: !ruby/object:Gem::Requirement
32
36
  requirements:
33
- - - "~>"
37
+ - - ">="
34
38
  - !ruby/object:Gem::Version
35
- version: '3.2'
39
+ version: '0'
36
40
  type: :development
37
41
  prerelease: false
38
42
  version_requirements: !ruby/object:Gem::Requirement
39
43
  requirements:
40
- - - "~>"
44
+ - - ">="
41
45
  - !ruby/object:Gem::Version
42
- version: '3.2'
46
+ version: '0'
43
47
  - !ruby/object:Gem::Dependency
44
- name: rake
48
+ name: fakeweb
45
49
  requirement: !ruby/object:Gem::Requirement
46
50
  requirements:
47
51
  - - ">="
@@ -55,7 +59,7 @@ dependencies:
55
59
  - !ruby/object:Gem::Version
56
60
  version: '0'
57
61
  - !ruby/object:Gem::Dependency
58
- name: fakeweb
62
+ name: rspec
59
63
  requirement: !ruby/object:Gem::Requirement
60
64
  requirements:
61
65
  - - ">="
@@ -69,7 +73,7 @@ dependencies:
69
73
  - !ruby/object:Gem::Version
70
74
  version: '0'
71
75
  - !ruby/object:Gem::Dependency
72
- name: rspec
76
+ name: byebug
73
77
  requirement: !ruby/object:Gem::Requirement
74
78
  requirements:
75
79
  - - ">="
@@ -83,19 +87,19 @@ dependencies:
83
87
  - !ruby/object:Gem::Version
84
88
  version: '0'
85
89
  - !ruby/object:Gem::Dependency
86
- name: byebug
90
+ name: rails
87
91
  requirement: !ruby/object:Gem::Requirement
88
92
  requirements:
89
93
  - - ">="
90
94
  - !ruby/object:Gem::Version
91
- version: '0'
92
- type: :development
95
+ version: '4.0'
96
+ type: :runtime
93
97
  prerelease: false
94
98
  version_requirements: !ruby/object:Gem::Requirement
95
99
  requirements:
96
100
  - - ">="
97
101
  - !ruby/object:Gem::Version
98
- version: '0'
102
+ version: '4.0'
99
103
  - !ruby/object:Gem::Dependency
100
104
  name: mixpanel
101
105
  requirement: !ruby/object:Gem::Requirement
@@ -110,11 +114,8 @@ dependencies:
110
114
  - - ">="
111
115
  - !ruby/object:Gem::Version
112
116
  version: '0'
113
- description: Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.
117
+ description: Run A/B test experiments on your Rails 4+ site using Mixpanel as a backend.
114
118
  email:
115
- - wouter@springest.com
116
- - markmulder@gmail.com
117
- - hello@thisiswho.im
118
119
  executables: []
119
120
  extensions: []
120
121
  extra_rdoc_files: []
@@ -212,7 +213,7 @@ homepage: https://github.com/Springest/ab_panel
212
213
  licenses:
213
214
  - MIT
214
215
  metadata: {}
215
- post_install_message:
216
+ post_install_message:
216
217
  rdoc_options: []
217
218
  require_paths:
218
219
  - lib
@@ -227,11 +228,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
228
  - !ruby/object:Gem::Version
228
229
  version: '0'
229
230
  requirements: []
230
- rubyforge_project:
231
- rubygems_version: 2.2.2
232
- signing_key:
231
+ rubygems_version: 3.0.3
232
+ signing_key:
233
233
  specification_version: 4
234
- summary: Run A/B test experiments on your Rails 3+ site using Mixpanel as a backend.
234
+ summary: Run A/B test experiments on your Rails 4+ site using Mixpanel as a backend.
235
235
  test_files:
236
236
  - example/.gitignore
237
237
  - example/Gemfile