vanity 1.8.1 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +47 -5
- data/Appraisals +3 -1
- data/CHANGELOG +7 -1
- data/Gemfile +21 -10
- data/Gemfile.lock +1 -1
- data/README.rdoc +9 -6
- data/gemfiles/rails3.gemfile +9 -8
- data/gemfiles/rails3.gemfile.lock +8 -2
- data/gemfiles/rails31.gemfile +9 -8
- data/gemfiles/rails31.gemfile.lock +8 -2
- data/gemfiles/rails32.gemfile +9 -8
- data/gemfiles/rails32.gemfile.lock +8 -2
- data/lib/vanity.rb +1 -0
- data/lib/vanity/adapters/abstract_adapter.rb +5 -0
- data/lib/vanity/adapters/active_record_adapter.rb +12 -5
- data/lib/vanity/adapters/mongodb_adapter.rb +6 -0
- data/lib/vanity/adapters/redis_adapter.rb +8 -0
- data/lib/vanity/autoconnect.rb +61 -0
- data/lib/vanity/experiment/ab_test.rb +29 -23
- data/lib/vanity/experiment/base.rb +14 -0
- data/lib/vanity/frameworks/rails.rb +11 -4
- data/lib/vanity/playground.rb +24 -15
- data/lib/vanity/version.rb +1 -1
- data/test/autoconnect_test.rb +25 -0
- data/test/dummy/config/boot.rb +4 -6
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/experiment/ab_test.rb +40 -4
- data/test/experiment/base_test.rb +3 -1
- data/test/metric/base_test.rb +10 -10
- data/test/passenger_test.rb +7 -1
- data/test/playground_test.rb +11 -0
- data/test/rails_test.rb +149 -68
- data/test/test_helper.rb +1 -0
- metadata +58 -43
- checksums.yaml +0 -7
data/.travis.yml
CHANGED
@@ -1,23 +1,65 @@
|
|
1
1
|
language: ruby
|
2
2
|
bundler_args: --without development
|
3
|
-
script: 'rake
|
3
|
+
script: 'bundle exec rake test'
|
4
4
|
services:
|
5
5
|
- mongodb
|
6
6
|
rvm:
|
7
7
|
- 1.8.7
|
8
8
|
- 1.9.3
|
9
9
|
- 2.0.0
|
10
|
-
- ruby-head
|
11
10
|
env:
|
12
11
|
- DB=mongodb
|
13
12
|
- DB=redis
|
14
13
|
- DB=mysql
|
15
14
|
#- DB=postgres
|
15
|
+
gemfile:
|
16
|
+
- Gemfile
|
17
|
+
- gemfiles/rails3.gemfile
|
18
|
+
- gemfiles/rails31.gemfile
|
19
|
+
- gemfiles/rails32.gemfile
|
16
20
|
before_script:
|
21
|
+
- if [[ "`basename $BUNDLE_GEMFILE`" == "Gemfile" ]]; then rvm rubygems 1.8.25; fi # Rubygems 2.0.x fails with Rails 2.3
|
17
22
|
- "mysql -e 'create database vanity_test;' >/dev/null"
|
18
|
-
|
19
|
-
#- "psql -c 'create database vanity_test;' -U postgres >/dev/null"
|
23
|
+
#- if [[ "$DB" == "pgsql" ]]; then psql -c 'create database vanity_test;' -U postgres >/dev/null; fi
|
20
24
|
matrix:
|
21
|
-
|
25
|
+
exclude:
|
26
|
+
# Rails 2 is not officially supported on Ruby 1.9.3
|
27
|
+
- rvm: 1.9.3
|
28
|
+
env: DB=mongodb
|
29
|
+
gemfile: Gemfile
|
30
|
+
- rvm: 1.9.3
|
31
|
+
env: DB=redis
|
32
|
+
gemfile: Gemfile
|
33
|
+
- rvm: 1.9.3
|
34
|
+
env: DB=mysql
|
35
|
+
gemfile: Gemfile
|
36
|
+
# Rails <= 3.2 is not officially supported on Ruby 2.0.0
|
37
|
+
- rvm: 2.0.0
|
38
|
+
env: DB=mongodb
|
39
|
+
gemfile: Gemfile
|
40
|
+
- rvm: 2.0.0
|
41
|
+
env: DB=redis
|
42
|
+
gemfile: Gemfile
|
43
|
+
- rvm: 2.0.0
|
44
|
+
env: DB=mysql
|
45
|
+
gemfile: Gemfile
|
46
|
+
- rvm: 2.0.0
|
47
|
+
env: DB=mongodb
|
48
|
+
gemfile: gemfiles/rails3.gemfile
|
22
49
|
- rvm: 2.0.0
|
50
|
+
env: DB=redis
|
51
|
+
gemfile: gemfiles/rails3.gemfile
|
52
|
+
- rvm: 2.0.0
|
53
|
+
env: DB=mysql
|
54
|
+
gemfile: gemfiles/rails3.gemfile
|
55
|
+
allow_failures:
|
23
56
|
- rvm: ruby-head
|
57
|
+
- rvm: 2.0.0
|
58
|
+
env: DB=mongodb
|
59
|
+
gemfile: gemfiles/rails31.gemfile
|
60
|
+
- rvm: 2.0.0
|
61
|
+
env: DB=redis
|
62
|
+
gemfile: gemfiles/rails31.gemfile
|
63
|
+
- rvm: 2.0.0
|
64
|
+
env: DB=mysql
|
65
|
+
gemfile: gemfiles/rails31.gemfile
|
data/Appraisals
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
appraise "rails3" do
|
2
2
|
gem "rails", "3.0.11"
|
3
|
+
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
3
4
|
gem "passenger", "~>3.0"
|
4
5
|
end
|
5
6
|
|
6
7
|
appraise "rails31" do
|
7
8
|
gem "rails", "3.1.3"
|
9
|
+
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
8
10
|
gem "passenger", "~>3.0"
|
9
11
|
end
|
10
12
|
|
11
13
|
appraise "rails32" do
|
12
14
|
gem "rails", "3.2.1"
|
15
|
+
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
13
16
|
gem "passenger", "~>3.0"
|
14
17
|
end
|
15
|
-
|
data/CHANGELOG
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
== 1.8.2 (2013-10-27)
|
2
|
+
|
3
|
+
Optimize metric_values query (@zawaideh).
|
4
|
+
Add an on_assignment hook for experiments which is called when an identity is given an assignment in ab_test (@lotze)
|
5
|
+
Finish Ruby 2.0 compatiblity with testing setup and add ActionMailer test coverage (@phillbaker).
|
6
|
+
|
1
7
|
== 1.8.1 (2013-10-05)
|
2
8
|
|
3
9
|
Added vanity_experiments helper for rails to return read only copy of active experiments (@iceberg901).
|
4
10
|
Fixed support for Mass Assignment on Rails 3.2 (@hcarver).
|
5
|
-
Fixed
|
11
|
+
Fixed commandline usage (@phillbaker).
|
6
12
|
|
7
13
|
|
8
14
|
== 1.8.0 (2012-03-12)
|
data/Gemfile
CHANGED
@@ -1,22 +1,33 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
|
4
|
+
# Frameworks
|
5
|
+
gem "rack"
|
6
|
+
gem "rails", "~>2.3.8"
|
7
|
+
|
8
|
+
# Servers
|
9
|
+
gem "passenger", "~>2.0"
|
10
|
+
|
11
|
+
# Persistence
|
5
12
|
gem "bson_ext"
|
6
|
-
gem "garb"
|
7
|
-
gem "mocha"
|
8
13
|
gem "mongo"
|
9
|
-
gem "bson_ext"
|
10
14
|
gem "mysql"
|
11
|
-
gem "passenger", "~>2.0"
|
12
15
|
gem "pg"
|
13
|
-
|
14
|
-
|
15
|
-
gem "
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
# APIs
|
18
|
+
gem "garb"
|
19
|
+
|
20
|
+
# Compatibility
|
18
21
|
gem "SystemTimer", "1.2.3", :platforms => :mri_18
|
19
22
|
|
23
|
+
# Testing
|
24
|
+
gem "appraisal"
|
25
|
+
|
26
|
+
gem "mocha", :require=>false
|
27
|
+
gem "shoulda", :require=>false # Requires test/unit
|
28
|
+
gem "timecop", :require=>false
|
29
|
+
gem "webmock", :require=>false
|
30
|
+
|
20
31
|
group :development do
|
21
32
|
gem "jekyll"
|
22
33
|
gem "rake"
|
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
= Vanity
|
2
|
-
{<img src="https://travis-ci.org/assaf/vanity.png?branch=
|
2
|
+
{<img src="https://travis-ci.org/assaf/vanity.png?branch=master" alt="Build Status" />}[https://travis-ci.org/assaf/vanity]
|
3
3
|
|
4
4
|
Vanity is an Experiment Driven Development framework for Rails.
|
5
5
|
|
@@ -96,13 +96,16 @@ If robots or spiders make up a significant portion of your sites traffic they ca
|
|
96
96
|
|
97
97
|
== Compatibility Matrix
|
98
98
|
|
99
|
-
|
99
|
+
Here's what's tested and known to work:
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
Ruby 1.8.7, 1.9.3
|
102
|
+
Persistence: Redis, Mongo, ActiveRecord
|
103
|
+
Rails: 2.3, 3, 3.1, 3.2
|
104
|
+
Ruby 2.0
|
105
|
+
Persistence: Redis, Mongo, ActiveRecord
|
106
|
+
Rails: 3.2
|
104
107
|
|
105
|
-
NOTE: Support for Rails 4
|
108
|
+
NOTE: Support for Rails 4 is coming soon!
|
106
109
|
|
107
110
|
== Contributing
|
108
111
|
|
data/gemfiles/rails3.gemfile
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "garb"
|
7
|
-
gem "mocha"
|
8
|
-
gem "mongo"
|
5
|
+
gem "rack"
|
9
6
|
gem "bson_ext"
|
7
|
+
gem "mongo"
|
10
8
|
gem "mysql"
|
11
9
|
gem "pg"
|
12
|
-
gem "
|
13
|
-
gem "shoulda"
|
14
|
-
gem "timecop"
|
15
|
-
gem "webmock"
|
10
|
+
gem "garb"
|
16
11
|
gem "SystemTimer", "1.2.3", :platforms=>:mri_18
|
12
|
+
gem "appraisal"
|
13
|
+
gem "mocha", :require=>false
|
14
|
+
gem "shoulda", :require=>false
|
15
|
+
gem "timecop", :require=>false
|
16
|
+
gem "webmock", :require=>false
|
17
17
|
gem "rails", "3.0.11"
|
18
|
+
gem "fastthread", :git=>"git://github.com/zoltankiss/fastthread.git", :platforms=>:mri_20
|
18
19
|
gem "passenger", "~>3.0"
|
19
20
|
|
20
21
|
gemspec :path=>"../"
|
@@ -1,7 +1,13 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/zoltankiss/fastthread.git
|
3
|
+
revision: 56e6ce7c1780797a354d5befe9a9a9869bbc7e3e
|
4
|
+
specs:
|
5
|
+
fastthread (1.0.7)
|
6
|
+
|
1
7
|
PATH
|
2
8
|
remote: /Users/phill/Development/ruby/vanity
|
3
9
|
specs:
|
4
|
-
vanity (1.8.
|
10
|
+
vanity (1.8.2)
|
5
11
|
redis (~> 2.0)
|
6
12
|
redis-namespace (~> 1.0.0)
|
7
13
|
|
@@ -49,7 +55,6 @@ GEM
|
|
49
55
|
daemon_controller (1.0.0)
|
50
56
|
erubis (2.6.6)
|
51
57
|
abstract (>= 1.0.0)
|
52
|
-
fastthread (1.0.7)
|
53
58
|
garb (0.9.1)
|
54
59
|
activesupport (>= 2.2.0)
|
55
60
|
crack (>= 0.1.6)
|
@@ -121,6 +126,7 @@ DEPENDENCIES
|
|
121
126
|
SystemTimer (= 1.2.3)
|
122
127
|
appraisal
|
123
128
|
bson_ext
|
129
|
+
fastthread!
|
124
130
|
garb
|
125
131
|
mocha
|
126
132
|
mongo
|
data/gemfiles/rails31.gemfile
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "garb"
|
7
|
-
gem "mocha"
|
8
|
-
gem "mongo"
|
5
|
+
gem "rack"
|
9
6
|
gem "bson_ext"
|
7
|
+
gem "mongo"
|
10
8
|
gem "mysql"
|
11
9
|
gem "pg"
|
12
|
-
gem "
|
13
|
-
gem "shoulda"
|
14
|
-
gem "timecop"
|
15
|
-
gem "webmock"
|
10
|
+
gem "garb"
|
16
11
|
gem "SystemTimer", "1.2.3", :platforms=>:mri_18
|
12
|
+
gem "appraisal"
|
13
|
+
gem "mocha", :require=>false
|
14
|
+
gem "shoulda", :require=>false
|
15
|
+
gem "timecop", :require=>false
|
16
|
+
gem "webmock", :require=>false
|
17
17
|
gem "rails", "3.1.3"
|
18
|
+
gem "fastthread", :git=>"git://github.com/zoltankiss/fastthread.git", :platforms=>:mri_20
|
18
19
|
gem "passenger", "~>3.0"
|
19
20
|
|
20
21
|
gemspec :path=>"../"
|
@@ -1,7 +1,13 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/zoltankiss/fastthread.git
|
3
|
+
revision: 56e6ce7c1780797a354d5befe9a9a9869bbc7e3e
|
4
|
+
specs:
|
5
|
+
fastthread (1.0.7)
|
6
|
+
|
1
7
|
PATH
|
2
8
|
remote: /Users/phill/Development/ruby/vanity
|
3
9
|
specs:
|
4
|
-
vanity (1.8.
|
10
|
+
vanity (1.8.2)
|
5
11
|
redis (~> 2.0)
|
6
12
|
redis-namespace (~> 1.0.0)
|
7
13
|
|
@@ -49,7 +55,6 @@ GEM
|
|
49
55
|
crack (0.3.1)
|
50
56
|
daemon_controller (1.0.0)
|
51
57
|
erubis (2.7.0)
|
52
|
-
fastthread (1.0.7)
|
53
58
|
garb (0.9.1)
|
54
59
|
activesupport (>= 2.2.0)
|
55
60
|
crack (>= 0.1.6)
|
@@ -132,6 +137,7 @@ DEPENDENCIES
|
|
132
137
|
SystemTimer (= 1.2.3)
|
133
138
|
appraisal
|
134
139
|
bson_ext
|
140
|
+
fastthread!
|
135
141
|
garb
|
136
142
|
mocha
|
137
143
|
mongo
|
data/gemfiles/rails32.gemfile
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "garb"
|
7
|
-
gem "mocha"
|
8
|
-
gem "mongo"
|
5
|
+
gem "rack"
|
9
6
|
gem "bson_ext"
|
7
|
+
gem "mongo"
|
10
8
|
gem "mysql"
|
11
9
|
gem "pg"
|
12
|
-
gem "
|
13
|
-
gem "shoulda"
|
14
|
-
gem "timecop"
|
15
|
-
gem "webmock"
|
10
|
+
gem "garb"
|
16
11
|
gem "SystemTimer", "1.2.3", :platforms=>:mri_18
|
12
|
+
gem "appraisal"
|
13
|
+
gem "mocha", :require=>false
|
14
|
+
gem "shoulda", :require=>false
|
15
|
+
gem "timecop", :require=>false
|
16
|
+
gem "webmock", :require=>false
|
17
17
|
gem "rails", "3.2.1"
|
18
|
+
gem "fastthread", :git=>"git://github.com/zoltankiss/fastthread.git", :platforms=>:mri_20
|
18
19
|
gem "passenger", "~>3.0"
|
19
20
|
|
20
21
|
gemspec :path=>"../"
|
@@ -1,7 +1,13 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/zoltankiss/fastthread.git
|
3
|
+
revision: 56e6ce7c1780797a354d5befe9a9a9869bbc7e3e
|
4
|
+
specs:
|
5
|
+
fastthread (1.0.7)
|
6
|
+
|
1
7
|
PATH
|
2
8
|
remote: /Users/phill/Development/ruby/vanity
|
3
9
|
specs:
|
4
|
-
vanity (1.8.
|
10
|
+
vanity (1.8.2)
|
5
11
|
redis (~> 2.0)
|
6
12
|
redis-namespace (~> 1.0.0)
|
7
13
|
|
@@ -48,7 +54,6 @@ GEM
|
|
48
54
|
crack (0.3.1)
|
49
55
|
daemon_controller (1.0.0)
|
50
56
|
erubis (2.7.0)
|
51
|
-
fastthread (1.0.7)
|
52
57
|
garb (0.9.1)
|
53
58
|
activesupport (>= 2.2.0)
|
54
59
|
crack (>= 0.1.6)
|
@@ -130,6 +135,7 @@ DEPENDENCIES
|
|
130
135
|
SystemTimer (= 1.2.3)
|
131
136
|
appraisal
|
132
137
|
bson_ext
|
138
|
+
fastthread!
|
133
139
|
garb
|
134
140
|
mocha
|
135
141
|
mongo
|
data/lib/vanity.rb
CHANGED
@@ -31,6 +31,7 @@ require "vanity/adapters/mongodb_adapter"
|
|
31
31
|
require "vanity/adapters/mock_adapter"
|
32
32
|
# Playground.
|
33
33
|
require "vanity/playground"
|
34
|
+
require "vanity/autoconnect"
|
34
35
|
require "vanity/helpers"
|
35
36
|
# Integration with various frameworks.
|
36
37
|
require "vanity/frameworks"
|
@@ -110,6 +110,11 @@ module Vanity
|
|
110
110
|
fail "Not implemented"
|
111
111
|
end
|
112
112
|
|
113
|
+
# Determines if a participant already has seen this alternative in this experiment.
|
114
|
+
def ab_seen(experiment, identity, assignment)
|
115
|
+
fail "Not implemented"
|
116
|
+
end
|
117
|
+
|
113
118
|
# Records a conversion in this experiment for the given alternative.
|
114
119
|
# Associates a value with the conversion (default to 1). If implicit is
|
115
120
|
# true, add particpant if not already recorded for this experiment. If
|
@@ -42,7 +42,7 @@ module Vanity
|
|
42
42
|
class VanityExperiment < VanityRecord
|
43
43
|
self.table_name = :vanity_experiments
|
44
44
|
has_many :vanity_conversions, :dependent => :destroy
|
45
|
-
|
45
|
+
attr_accessible :experiment_id if respond_to?(:attr_accessible)
|
46
46
|
|
47
47
|
# Finds or creates the experiment
|
48
48
|
def self.retrieve(experiment)
|
@@ -64,7 +64,7 @@ module Vanity
|
|
64
64
|
# Participant model
|
65
65
|
class VanityParticipant < VanityRecord
|
66
66
|
self.table_name = :vanity_participants
|
67
|
-
|
67
|
+
attr_accessible :experiment_id, :identity, :seen, :shown, :converted if respond_to?(:attr_accessible)
|
68
68
|
|
69
69
|
# Finds the participant by experiment and identity. If
|
70
70
|
# create is true then it will create the participant
|
@@ -127,7 +127,7 @@ module Vanity
|
|
127
127
|
connection = VanityMetric.connection
|
128
128
|
record = VanityMetric.retrieve(metric)
|
129
129
|
dates = (from.to_date..to.to_date).map(&:to_s)
|
130
|
-
conditions = [connection.quote_column_name('date') + '
|
130
|
+
conditions = [connection.quote_column_name('date') + ' BETWEEN ? AND ?', from.to_date, to.to_date]
|
131
131
|
order = "#{connection.quote_column_name('date')}"
|
132
132
|
select = "sum(#{connection.quote_column_name('value')}) AS value, #{connection.quote_column_name('date')}"
|
133
133
|
group_by = "#{connection.quote_column_name('date')}"
|
@@ -216,12 +216,19 @@ module Vanity
|
|
216
216
|
VanityParticipant.retrieve(experiment, identity, true, :seen => alternative)
|
217
217
|
end
|
218
218
|
|
219
|
+
# Determines if a participant already has seen this alternative in this experiment.
|
220
|
+
def ab_seen(experiment, identity, alternative)
|
221
|
+
participant = VanityParticipant.retrieve(experiment, identity, false)
|
222
|
+
participant && participant.seen == alternative.id
|
223
|
+
end
|
224
|
+
|
219
225
|
# Records a conversion in this experiment for the given alternative.
|
220
226
|
# Associates a value with the conversion (default to 1). If implicit is
|
221
|
-
# true, add
|
222
|
-
# implicit is false (default), only add conversion
|
227
|
+
# true, add participant if not already recorded for this experiment. If
|
228
|
+
# implicit is false (default), only add conversion if participant
|
223
229
|
# previously recorded as participating in this experiment.
|
224
230
|
def ab_add_conversion(experiment, alternative, identity, count = 1, implicit = false)
|
231
|
+
participant = VanityParticipant.retrieve(experiment, identity, false)
|
225
232
|
VanityParticipant.retrieve(experiment, identity, implicit, :converted => alternative)
|
226
233
|
VanityExperiment.retrieve(experiment).increment_conversion(alternative, count)
|
227
234
|
end
|
@@ -150,6 +150,12 @@ module Vanity
|
|
150
150
|
@participants.update({ :experiment=>experiment, :identity=>identity }, { "$push"=>{ :seen=>alternative } }, :upsert=>true)
|
151
151
|
end
|
152
152
|
|
153
|
+
# Determines if a participant already has seen this alternative in this experiment.
|
154
|
+
def ab_seen(experiment, identity, alternative)
|
155
|
+
participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:seen] })
|
156
|
+
participant && participant["seen"].first == alternative.id
|
157
|
+
end
|
158
|
+
|
153
159
|
def ab_add_conversion(experiment, alternative, identity, count = 1, implicit = false)
|
154
160
|
if implicit
|
155
161
|
@participants.update({ :experiment=>experiment, :identity=>identity }, { "$push"=>{ :seen=>alternative } }, :upsert=>true)
|