kissable 1.0.0a1 → 1.0.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: 5611d750b261b15bec5f0346201da93242760de9
4
- data.tar.gz: 5ded8116d3087727da8568298be44f2ac955284c
3
+ metadata.gz: 66f1916ee0bfa93ae6cbd1c4e92b692eaddbd61e
4
+ data.tar.gz: 85a2312187c0f231fb35f5706d4069d05b7e66ff
5
5
  SHA512:
6
- metadata.gz: 5a1fd37813bde009fcfec08855c54a00220685cf59603df7fc98927fd9771635de2fc0cc13096808122f0b9bb4a3a6af06ba538b4f6ddc155b61c168e835a5d4
7
- data.tar.gz: 1c413d7254748ec7e94ed7260973243f171a5175cf4e34e5f6515fd8291c2cc2ec84147fb5af5dac496e997de5355040a36aaf96a62ae77d85944e115b99fd43
6
+ metadata.gz: b269414862c154f45ddf6126b9888441095430c1fe5f0a42b36c6a164e5837e80f92dff25a720ad5cf3555dcedebd61c4d83298e5bb8ee0779e393dcc30b495b
7
+ data.tar.gz: 55570ccd11791c5f87a6bb6254cbeef05b6b34c1b5d6dd82c887c20ad9eb7fa135901cec823f84fdad360f8720df9d3fda01c78d5aad778c3a180b6a9215e639
data/.gitignore CHANGED
@@ -2,9 +2,11 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .vagrant
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
9
+ Vagrantfile
8
10
  _yardoc
9
11
  coverage
10
12
  doc/
data/README.md CHANGED
@@ -20,7 +20,9 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- Kissable enables you to conduct a/b tests contingent on users having cookies enabled. To conduct a test you need to have a name for a test and specify how many groups you want and the ratios of these groups.
23
+ Kissable helps you run A/B tests by breaking up your users into test groups (e.g. Original vs. Variant). Name your test, list your test groups, and the ratio at which people should be distributed to each group. Kissable does the assignment pseudo-randomly.
24
+
25
+ For anonymous users cookies must be enabled. Cookies are used to assign a user to a group and keep him there. For logged in users a unique identifier (e.g. login) is used instead for the same purpose.
24
26
 
25
27
  You instantiate the object with these items.
26
28
 
@@ -56,6 +58,14 @@ end
56
58
  ab_test.tracking_script(users_ab_group)
57
59
  ```
58
60
 
61
+ * For logged in users, you can use some unique identifier instead.
62
+
63
+ ```ruby
64
+ ab_test = Kissable::AB.new('top-navigation test')
65
+ users_ab_group = ab_test.group(email)
66
+ # Add your custom tracking code here.
67
+ ```
68
+
59
69
  ### Rails
60
70
 
61
71
  ```ruby
@@ -4,7 +4,7 @@ module Kissable
4
4
  class AB
5
5
  MAX_GROUP_COUNT = 4
6
6
 
7
- attr_reader :groups, :ratios, :test_name
7
+ attr_reader :groups, :login, :ratios, :test_name
8
8
 
9
9
  def initialize(test_name, groups=nil, ratios=nil)
10
10
  @test_name = test_name
@@ -19,8 +19,10 @@ module Kissable
19
19
  validate_ratios
20
20
  end
21
21
 
22
- def group(cookies)
23
- @cookies = cookies
22
+ # Assigns a test group based on the 'abid' cookie or login (email).
23
+ # Takes either a cookies object (Hash-like) or login (String).
24
+ def group(object)
25
+ (object.is_a? String) ? (@login = object) : (@cookies = object)
24
26
 
25
27
  abset.each do |i, val|
26
28
  return i if val > seed
@@ -46,7 +48,14 @@ module Kissable
46
48
  end
47
49
 
48
50
  def seed
49
- @seed ||= (sha ^ ab_cookie_value) % 100
51
+ return @seed if @seed
52
+
53
+ xor = @login ? login_sha : ab_cookie_value
54
+ @seed = (sha ^ xor) % 100
55
+ end
56
+
57
+ def login_sha
58
+ @login_sha = Digest::SHA1.hexdigest(login).to_i(16)
50
59
  end
51
60
 
52
61
  def abset
@@ -1,3 +1,3 @@
1
1
  module Kissable
2
- VERSION = "1.0.0a1"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -5,6 +5,7 @@ describe Kissable::AB do
5
5
  let(:groups) { nil }
6
6
  let(:ratios) { nil }
7
7
  let(:cookies) { {} }
8
+ let(:login) { 'jsmith@example.com' }
8
9
  let(:ab_test) { described_class.new(test_name, groups, ratios) }
9
10
 
10
11
  describe '#initialize' do
@@ -63,67 +64,84 @@ describe Kissable::AB do
63
64
  end
64
65
 
65
66
  describe '#group' do
66
- let(:group) { ab_test.group(cookies) }
67
+ context "when using cookies" do
68
+ let(:group) { ab_test.group(cookies) }
67
69
 
68
- it "is returns Original or Variant" do
69
- expect(group).to match(/Original|Variant/)
70
- end
71
-
72
- context "when cookie exists" do
73
- before :each do
74
- ab_test.stub(:cookies).and_return('abid' => 1)
70
+ it "returns Original or Variant" do
71
+ expect(group).to match(/Original|Variant/)
75
72
  end
76
73
 
77
- it "doesn't change the cookie" do
78
- expect { group }.to_not change { ab_test.cookies }
79
- end
80
- end
74
+ context "when cookie exists" do
75
+ before :each do
76
+ ab_test.stub(:cookies).and_return('abid' => 1)
77
+ end
81
78
 
82
- context "when cookie doesn't exist" do
83
- it "sets a cookie" do
84
- expect { group }.to change { ab_test.cookies }.from({})
79
+ it "doesn't change the cookie" do
80
+ expect { group }.to_not change { ab_test.cookies }
81
+ end
85
82
  end
86
83
 
87
- describe "the cookie" do
88
- let(:cookie) { ab_test.cookies['abid'] }
84
+ context "when cookie doesn't exist" do
85
+ it "sets a cookie" do
86
+ expect { group }.to change { ab_test.cookies }.from({})
87
+ end
88
+
89
+ describe "the cookie" do
90
+ let(:cookie) { ab_test.cookies['abid'] }
91
+
92
+ context "when the domain has been configured" do
93
+ let(:domain) { 'someaweseomedomain.com' }
89
94
 
90
- context "when the domain has been configured" do
91
- let(:domain) { 'someaweseomedomain.com' }
95
+ it "has the domain key set to the correct value" do
96
+ Kissable.configure do |config|
97
+ config.domain = domain
98
+ end
92
99
 
93
- it "has the domain key set to the correct value" do
94
- Kissable.configure do |config|
95
- config.domain = domain
100
+ group
101
+ expect(cookie).to include(:domain => domain)
96
102
  end
103
+ end
104
+
105
+ context "when the domain hasn't been configured" do
106
+ it "doesn't include a domain key" do
107
+ Kissable.configure do |config|
108
+ config.domain = nil
109
+ end
97
110
 
111
+ group
112
+ expect(cookie).to_not include(:domain)
113
+ end
114
+ end
115
+
116
+ it "expires" do
98
117
  group
99
- expect(cookie).to include(:domain => domain)
118
+ expect(cookie).to include(:expires)
100
119
  end
101
- end
102
120
 
103
- context "when the domain hasn't been configured" do
104
- it "doesn't include a domain key" do
105
- Kissable.configure do |config|
106
- config.domain = nil
107
- end
121
+ it "has a path" do
122
+ group
123
+ expect(cookie).to include(:path => "/")
124
+ end
108
125
 
126
+ it "contains a value" do
109
127
  group
110
- expect(cookie).to_not include(:domain)
128
+ expect(cookie).to include(:value)
111
129
  end
112
130
  end
131
+ end
132
+ end
113
133
 
114
- it "expires" do
115
- group
116
- expect(cookie).to include(:expires)
117
- end
134
+ context "when using login" do
135
+ let(:group) { ab_test.group(login) }
118
136
 
119
- it "has a path" do
120
- group
121
- expect(cookie).to include(:path => "/")
122
- end
137
+ it "returns Original or Variant" do
138
+ expect(group).to match(/Original|Variant/)
139
+ end
123
140
 
124
- it "contains a value" do
125
- group
126
- expect(cookie).to include(:value)
141
+ it "always returns the same group" do
142
+ 10.times do
143
+ test_copy = described_class.new(test_name)
144
+ expect(test_copy.group(login)).to eq(group)
127
145
  end
128
146
  end
129
147
  end
@@ -20,7 +20,7 @@ describe Kissable::Configuration do
20
20
 
21
21
  context "when Logger is written to" do
22
22
  it "doesn't have an error" do
23
- expect(Kissable.configuration.logger.info("test")).to_not raise_error
23
+ expect { Kissable.configuration.logger.info("test") }.to_not raise_error
24
24
  end
25
25
  end
26
26
  end
metadata CHANGED
@@ -1,167 +1,167 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kissable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0a1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Hardin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-28 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-nc
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: guard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: guard-rspec
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: pry
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: pry-remote
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: pry-nav
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: coveralls
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - '>='
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - '>='
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  description: Track and identify users via cookie in order to run A/B tests.
@@ -171,10 +171,10 @@ executables: []
171
171
  extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
- - .coveralls.yml
175
- - .gitignore
176
- - .hound.yml
177
- - .travis.yml
174
+ - ".coveralls.yml"
175
+ - ".gitignore"
176
+ - ".hound.yml"
177
+ - ".travis.yml"
178
178
  - Gemfile
179
179
  - Guardfile
180
180
  - LICENSE.txt
@@ -201,17 +201,17 @@ require_paths:
201
201
  - lib
202
202
  required_ruby_version: !ruby/object:Gem::Requirement
203
203
  requirements:
204
- - - '>='
204
+ - - ">="
205
205
  - !ruby/object:Gem::Version
206
206
  version: '0'
207
207
  required_rubygems_version: !ruby/object:Gem::Requirement
208
208
  requirements:
209
- - - '>'
209
+ - - ">="
210
210
  - !ruby/object:Gem::Version
211
- version: 1.3.1
211
+ version: '0'
212
212
  requirements: []
213
213
  rubyforge_project:
214
- rubygems_version: 2.0.14
214
+ rubygems_version: 2.4.3
215
215
  signing_key:
216
216
  specification_version: 4
217
217
  summary: Track and identify users via cookie in order to run A/B tests.