vanity 1.8.1 → 1.8.2
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.
- 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)
|