vanity 1.8.4 → 1.9.0.beta

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.
Files changed (53) hide show
  1. data/.travis.yml +3 -2
  2. data/CHANGELOG +12 -0
  3. data/Gemfile +6 -3
  4. data/Gemfile.lock +12 -10
  5. data/README.rdoc +45 -16
  6. data/Rakefile +14 -9
  7. data/doc/_layouts/page.html +4 -6
  8. data/doc/ab_testing.textile +1 -1
  9. data/doc/configuring.textile +2 -4
  10. data/doc/email.textile +1 -3
  11. data/doc/index.textile +3 -63
  12. data/doc/rails.textile +34 -8
  13. data/gemfiles/rails3.gemfile +12 -3
  14. data/gemfiles/rails3.gemfile.lock +37 -11
  15. data/gemfiles/rails31.gemfile +12 -3
  16. data/gemfiles/rails31.gemfile.lock +37 -11
  17. data/gemfiles/rails32.gemfile +12 -3
  18. data/gemfiles/rails32.gemfile.lock +37 -11
  19. data/gemfiles/rails4.gemfile +12 -3
  20. data/gemfiles/rails4.gemfile.lock +37 -11
  21. data/lib/vanity/adapters/abstract_adapter.rb +4 -0
  22. data/lib/vanity/adapters/active_record_adapter.rb +18 -10
  23. data/lib/vanity/adapters/mock_adapter.rb +8 -4
  24. data/lib/vanity/adapters/mongodb_adapter.rb +11 -7
  25. data/lib/vanity/adapters/redis_adapter.rb +88 -37
  26. data/lib/vanity/commands/report.rb +9 -9
  27. data/lib/vanity/experiment/ab_test.rb +120 -101
  28. data/lib/vanity/experiment/alternative.rb +21 -21
  29. data/lib/vanity/experiment/base.rb +5 -5
  30. data/lib/vanity/experiment/bayesian_bandit_score.rb +51 -51
  31. data/lib/vanity/experiment/definition.rb +10 -10
  32. data/lib/vanity/frameworks/rails.rb +39 -36
  33. data/lib/vanity/helpers.rb +6 -4
  34. data/lib/vanity/metric/active_record.rb +1 -1
  35. data/lib/vanity/metric/base.rb +23 -24
  36. data/lib/vanity/metric/google_analytics.rb +5 -5
  37. data/lib/vanity/playground.rb +118 -24
  38. data/lib/vanity/templates/_report.erb +20 -6
  39. data/lib/vanity/templates/vanity.css +2 -0
  40. data/lib/vanity/version.rb +1 -1
  41. data/test/adapters/redis_adapter_test.rb +106 -1
  42. data/test/dummy/config/database.yml +21 -4
  43. data/test/dummy/config/routes.rb +1 -1
  44. data/test/experiment/ab_test.rb +93 -13
  45. data/test/metric/active_record_test.rb +9 -4
  46. data/test/passenger_test.rb +43 -42
  47. data/test/playground_test.rb +50 -1
  48. data/test/rails_dashboard_test.rb +38 -1
  49. data/test/rails_helper_test.rb +5 -0
  50. data/test/rails_test.rb +66 -15
  51. data/test/test_helper.rb +24 -2
  52. data/vanity.gemspec +0 -2
  53. metadata +45 -57
@@ -5,15 +5,14 @@ GIT
5
5
  fastthread (1.0.7)
6
6
 
7
7
  PATH
8
- remote: /Users/phill/Development/ruby/vanity
8
+ remote: ..
9
9
  specs:
10
- vanity (1.8.4)
11
- redis (>= 2.1)
12
- redis-namespace (>= 1.1.0)
10
+ vanity (1.8.3)
13
11
 
14
12
  GEM
15
13
  remote: https://rubygems.org/
16
14
  specs:
15
+ RedCloth (4.2.9)
17
16
  SystemTimer (1.2.3)
18
17
  actionmailer (3.2.1)
19
18
  actionpack (= 3.2.1)
@@ -43,30 +42,48 @@ GEM
43
42
  i18n (~> 0.6)
44
43
  multi_json (~> 1.0)
45
44
  addressable (2.2.7)
46
- appraisal (0.4.1)
45
+ albino (1.3.3)
46
+ posix-spawn (>= 0.3.6)
47
+ appraisal (1.0.0.beta2)
47
48
  bundler
48
49
  rake
50
+ thor (>= 0.14.0)
49
51
  arel (3.0.2)
50
52
  backports (3.3.5)
51
53
  bson (1.6.0)
52
54
  bson_ext (1.6.0)
53
55
  bson (= 1.6.0)
54
56
  builder (3.0.0)
57
+ classifier (1.3.3)
58
+ fast-stemmer (>= 1.0.0)
55
59
  crack (0.3.1)
56
60
  daemon_controller (1.0.0)
61
+ directory_watcher (1.4.1)
57
62
  erubis (2.7.0)
63
+ fast-stemmer (1.0.0)
58
64
  garb (0.9.1)
59
65
  activesupport (>= 2.2.0)
60
66
  crack (>= 0.1.6)
61
67
  hike (1.2.1)
62
68
  i18n (0.6.0)
63
69
  integration (0.1.0)
70
+ jekyll (0.11.2)
71
+ albino (~> 1.3)
72
+ classifier (~> 1.3)
73
+ directory_watcher (~> 1.1)
74
+ kramdown (~> 0.13)
75
+ liquid (~> 2.3)
76
+ maruku (~> 0.5)
64
77
  journey (1.0.3)
65
78
  json (1.6.5)
79
+ kramdown (0.13.5)
80
+ liquid (2.3.0)
66
81
  mail (2.4.1)
67
82
  i18n (>= 0.4.0)
68
83
  mime-types (~> 1.16)
69
84
  treetop (~> 1.4.8)
85
+ maruku (0.6.0)
86
+ syntax (>= 1.0.0)
70
87
  metaclass (0.0.1)
71
88
  mime-types (1.17.2)
72
89
  mocha (0.10.5)
@@ -80,8 +97,8 @@ GEM
80
97
  fastthread (>= 1.0.1)
81
98
  rack
82
99
  rake (>= 0.8.1)
83
- pg (0.13.2)
84
100
  polyglot (0.3.3)
101
+ posix-spawn (0.3.6)
85
102
  rack (1.4.1)
86
103
  rack-cache (1.1)
87
104
  rack (>= 0.4)
@@ -107,9 +124,9 @@ GEM
107
124
  rake (0.9.2.2)
108
125
  rdoc (3.12)
109
126
  json (~> 1.4)
110
- redis (3.2.0)
111
- redis-namespace (1.5.1)
112
- redis (~> 3.0, >= 3.0.4)
127
+ redis (3.0.6)
128
+ redis-namespace (1.3.2)
129
+ redis (~> 3.0.4)
113
130
  rubystats (0.2.3)
114
131
  shoulda (3.0.1)
115
132
  shoulda-context (~> 1.0.0)
@@ -120,6 +137,8 @@ GEM
120
137
  hike (~> 1.2)
121
138
  rack (~> 1.0)
122
139
  tilt (~> 1.1, != 1.3.0)
140
+ sqlite3 (1.3.8)
141
+ syntax (1.0.0)
123
142
  thor (0.14.6)
124
143
  tilt (1.3.3)
125
144
  timecop (0.3.5)
@@ -130,27 +149,34 @@ GEM
130
149
  webmock (1.8.0)
131
150
  addressable (>= 2.2.7)
132
151
  crack (>= 0.1.7)
152
+ yard (0.7.5)
133
153
 
134
154
  PLATFORMS
135
155
  ruby
136
156
 
137
157
  DEPENDENCIES
158
+ RedCloth
138
159
  SystemTimer (= 1.2.3)
139
- appraisal
160
+ appraisal (>= 1.0.0.beta2)
140
161
  backports
141
162
  bson_ext
142
163
  fastthread!
143
164
  garb
144
165
  integration
166
+ jekyll
145
167
  mocha
146
168
  mongo
147
169
  mysql
148
170
  passenger (~> 3.0)
149
- pg
150
171
  rack
151
172
  rails (= 3.2.1)
173
+ rake
174
+ redis (>= 2.1)
175
+ redis-namespace (>= 1.1.0)
152
176
  rubystats
153
177
  shoulda
178
+ sqlite3
154
179
  timecop
155
180
  vanity!
156
181
  webmock
182
+ yard
@@ -3,16 +3,17 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rack"
6
+ gem "redis", ">= 2.1"
7
+ gem "redis-namespace", ">= 1.1.0"
6
8
  gem "bson_ext"
7
9
  gem "mongo"
8
10
  gem "mysql"
9
- gem "pg"
11
+ gem "sqlite3"
10
12
  gem "backports", :platforms=>:mri_18
11
13
  gem "integration"
12
14
  gem "rubystats"
13
15
  gem "garb"
14
16
  gem "SystemTimer", "1.2.3", :platforms=>:mri_18
15
- gem "appraisal"
16
17
  gem "mocha", :require=>false
17
18
  gem "shoulda", :require=>false
18
19
  gem "timecop", :require=>false
@@ -21,4 +22,12 @@ gem "rails", "4.0.0"
21
22
  gem "fastthread", :git=>"git://github.com/zoltankiss/fastthread.git", :platforms=>:mri_20
22
23
  gem "passenger", "~>3.0"
23
24
 
24
- gemspec :path=>"../"
25
+ group :development do
26
+ gem "appraisal", ">= 1.0.0.beta2"
27
+ gem "jekyll"
28
+ gem "rake"
29
+ gem "RedCloth"
30
+ gem "yard"
31
+ end
32
+
33
+ gemspec :path=>".././"
@@ -5,15 +5,14 @@ GIT
5
5
  fastthread (1.0.7)
6
6
 
7
7
  PATH
8
- remote: /Users/phill/Development/ruby/vanity
8
+ remote: ..
9
9
  specs:
10
- vanity (1.8.4)
11
- redis (>= 2.1)
12
- redis-namespace (>= 1.1.0)
10
+ vanity (1.8.3)
13
11
 
14
12
  GEM
15
13
  remote: https://rubygems.org/
16
14
  specs:
15
+ RedCloth (4.2.9)
17
16
  SystemTimer (1.2.3)
18
17
  actionmailer (4.0.0)
19
18
  actionpack (= 4.0.0)
@@ -40,9 +39,12 @@ GEM
40
39
  thread_safe (~> 0.1)
41
40
  tzinfo (~> 0.3.37)
42
41
  addressable (2.3.5)
43
- appraisal (0.5.2)
42
+ albino (1.3.3)
43
+ posix-spawn (>= 0.3.6)
44
+ appraisal (1.0.0.beta2)
44
45
  bundler
45
46
  rake
47
+ thor (>= 0.14.0)
46
48
  arel (4.0.1)
47
49
  atomic (1.1.14)
48
50
  backports (3.3.5)
@@ -50,19 +52,34 @@ GEM
50
52
  bson_ext (1.9.2)
51
53
  bson (~> 1.9.2)
52
54
  builder (3.1.4)
55
+ classifier (1.3.3)
56
+ fast-stemmer (>= 1.0.0)
53
57
  crack (0.4.1)
54
58
  safe_yaml (~> 0.9.0)
55
59
  daemon_controller (1.1.7)
60
+ directory_watcher (1.4.1)
56
61
  erubis (2.7.0)
62
+ fast-stemmer (1.0.0)
57
63
  garb (0.9.1)
58
64
  activesupport (>= 2.2.0)
59
65
  crack (>= 0.1.6)
60
66
  hike (1.2.3)
61
67
  i18n (0.6.5)
62
68
  integration (0.1.0)
69
+ jekyll (0.11.2)
70
+ albino (~> 1.3)
71
+ classifier (~> 1.3)
72
+ directory_watcher (~> 1.1)
73
+ kramdown (~> 0.13)
74
+ liquid (~> 2.3)
75
+ maruku (~> 0.5)
76
+ kramdown (0.13.5)
77
+ liquid (2.3.0)
63
78
  mail (2.5.4)
64
79
  mime-types (~> 1.16)
65
80
  treetop (~> 1.4.8)
81
+ maruku (0.6.0)
82
+ syntax (>= 1.0.0)
66
83
  metaclass (0.0.1)
67
84
  mime-types (1.25)
68
85
  minitest (4.7.5)
@@ -77,8 +94,8 @@ GEM
77
94
  fastthread (>= 1.0.1)
78
95
  rack
79
96
  rake (>= 0.8.1)
80
- pg (0.17.0)
81
97
  polyglot (0.3.3)
98
+ posix-spawn (0.3.6)
82
99
  rack (1.5.2)
83
100
  rack-test (0.6.2)
84
101
  rack (>= 1.0)
@@ -96,9 +113,9 @@ GEM
96
113
  rake (>= 0.8.7)
97
114
  thor (>= 0.18.1, < 2.0)
98
115
  rake (10.1.0)
99
- redis (3.2.0)
100
- redis-namespace (1.5.1)
101
- redis (~> 3.0, >= 3.0.4)
116
+ redis (3.0.6)
117
+ redis-namespace (1.3.2)
118
+ redis (~> 3.0.4)
102
119
  rubystats (0.2.3)
103
120
  safe_yaml (0.9.7)
104
121
  shoulda (3.5.0)
@@ -116,6 +133,8 @@ GEM
116
133
  actionpack (>= 3.0)
117
134
  activesupport (>= 3.0)
118
135
  sprockets (~> 2.8)
136
+ sqlite3 (1.3.8)
137
+ syntax (1.0.0)
119
138
  thor (0.18.1)
120
139
  thread_safe (0.1.3)
121
140
  atomic
@@ -128,27 +147,34 @@ GEM
128
147
  webmock (1.15.2)
129
148
  addressable (>= 2.2.7)
130
149
  crack (>= 0.3.2)
150
+ yard (0.7.5)
131
151
 
132
152
  PLATFORMS
133
153
  ruby
134
154
 
135
155
  DEPENDENCIES
156
+ RedCloth
136
157
  SystemTimer (= 1.2.3)
137
- appraisal
158
+ appraisal (>= 1.0.0.beta2)
138
159
  backports
139
160
  bson_ext
140
161
  fastthread!
141
162
  garb
142
163
  integration
164
+ jekyll
143
165
  mocha
144
166
  mongo
145
167
  mysql
146
168
  passenger (~> 3.0)
147
- pg
148
169
  rack
149
170
  rails (= 4.0.0)
171
+ rake
172
+ redis (>= 2.1)
173
+ redis-namespace (>= 1.1.0)
150
174
  rubystats
151
175
  shoulda
176
+ sqlite3
152
177
  timecop
153
178
  vanity!
154
179
  webmock
180
+ yard
@@ -66,6 +66,10 @@ module Vanity
66
66
 
67
67
  # -- Experiments --
68
68
 
69
+ def experiment_persisted?(experiment)
70
+ fail "Not implemented"
71
+ end
72
+
69
73
  # Store when experiment was created (do not write over existing value).
70
74
  def set_experiment_created_at(experiment, time)
71
75
  fail "Not implemented"
@@ -27,8 +27,7 @@ module Vanity
27
27
  # Metric model
28
28
  class VanityMetric < VanityRecord
29
29
  self.table_name = :vanity_metrics
30
- has_many :vanity_metric_values,
31
- :class_name => 'Vanity::Adapters::ActiveRecordAdapter::VanityMetricValue'
30
+ has_many :vanity_metric_values
32
31
 
33
32
  def self.retrieve(metric)
34
33
  find_or_create_by_metric_id(metric.to_s)
@@ -40,15 +39,13 @@ module Vanity
40
39
  attr_accessible :date, :index, :value if needs_attr_accessible?
41
40
 
42
41
  self.table_name = :vanity_metric_values
43
- belongs_to :vanity_metric,
44
- :class_name => 'Vanity::Adapters::ActiveRecordAdapter::VanityMetric'
42
+ belongs_to :vanity_metric
45
43
  end
46
44
 
47
45
  # Experiment model
48
46
  class VanityExperiment < VanityRecord
49
47
  self.table_name = :vanity_experiments
50
- has_many :vanity_conversions, :dependent => :destroy,
51
- :class_name => 'Vanity::Adapters::ActiveRecordAdapter::VanityConversion'
48
+ has_many :vanity_conversions, :dependent => :destroy
52
49
  attr_accessible :experiment_id if needs_attr_accessible?
53
50
 
54
51
  # Finds or creates the experiment
@@ -65,8 +62,7 @@ module Vanity
65
62
  # Conversion model
66
63
  class VanityConversion < VanityRecord
67
64
  self.table_name = :vanity_conversions
68
- belongs_to :vanity_experiment,
69
- :class_name => 'Vanity::Adapters::ActiveRecordAdapter::VanityExperiment'
65
+ belongs_to :vanity_experiment
70
66
  end
71
67
 
72
68
  # Participant model
@@ -90,6 +86,8 @@ module Vanity
90
86
  end
91
87
 
92
88
  def initialize(options)
89
+
90
+
93
91
  @options = options.inject({}) { |h,kv| h[kv.first.to_s] = kv.last ; h }
94
92
  if @options["active_record_adapter"] && (@options["active_record_adapter"] != "default")
95
93
  @options["adapter"] = @options["active_record_adapter"]
@@ -115,6 +113,9 @@ module Vanity
115
113
  end
116
114
  end
117
115
 
116
+
117
+ # -- Metrics --
118
+
118
119
  def get_metric_last_update_at(metric)
119
120
  record = VanityMetric.find_by_metric_id(metric.to_s)
120
121
  record && record.updated_at
@@ -158,6 +159,13 @@ module Vanity
158
159
  record && record.destroy
159
160
  end
160
161
 
162
+
163
+ # -- Experiments --
164
+
165
+ def experiment_persisted?(experiment)
166
+ VanityExperiment.find_by_experiment_id(experiment.to_s).present?
167
+ end
168
+
161
169
  # Store when experiment was created (do not write over existing value).
162
170
  def set_experiment_created_at(experiment, time)
163
171
  record = VanityExperiment.find_by_experiment_id(experiment.to_s) ||
@@ -226,8 +234,8 @@ module Vanity
226
234
 
227
235
  # Determines if a participant already has seen this alternative in this experiment.
228
236
  def ab_seen(experiment, identity, alternative)
229
- participant = VanityParticipant.retrieve(experiment, identity, false)
230
- participant && participant.seen == alternative.id
237
+ participant = VanityParticipant.retrieve(experiment, identity, false)
238
+ participant && participant.seen == alternative.id
231
239
  end
232
240
 
233
241
  # Returns the participant's seen alternative in this experiment, if it exists
@@ -44,7 +44,7 @@ module Vanity
44
44
 
45
45
 
46
46
  # -- Metrics --
47
-
47
+
48
48
  def get_metric_last_update_at(metric)
49
49
  @metrics[metric] && @metrics[metric][:last_update_at]
50
50
  end
@@ -66,10 +66,14 @@ module Vanity
66
66
  def destroy_metric(metric)
67
67
  @metrics.delete metric
68
68
  end
69
-
69
+
70
70
 
71
71
  # -- Experiments --
72
-
72
+
73
+ def experiment_persisted?(experiment)
74
+ !!@experiments[experiment]
75
+ end
76
+
73
77
  def set_experiment_created_at(experiment, time)
74
78
  @experiments[experiment] ||= {}
75
79
  @experiments[experiment][:created_at] ||= time
@@ -133,7 +137,7 @@ module Vanity
133
137
  if implicit
134
138
  alt[:participants] << identity
135
139
  else
136
- participating = alt[:participants].include?(identity)
140
+ participating = alt[:participants].include?(identity)
137
141
  end
138
142
  alt[:converted] << identity if implicit || participating
139
143
  alt[:conversions] += count
@@ -73,10 +73,10 @@ module Vanity
73
73
  @experiments.drop
74
74
  @participants.drop
75
75
  end
76
-
76
+
77
77
 
78
78
  # -- Metrics --
79
-
79
+
80
80
  def get_metric_last_update_at(metric)
81
81
  record = @metrics.find_one(:_id=>metric)
82
82
  record && record["last_update_at"]
@@ -99,12 +99,16 @@ module Vanity
99
99
  def destroy_metric(metric)
100
100
  @metrics.remove :_id=>metric
101
101
  end
102
-
102
+
103
103
 
104
104
  # -- Experiments --
105
-
105
+
106
+ def experiment_persisted?(experiment)
107
+ !!@experiments.find_one({ :_id=>experiment })
108
+ end
109
+
106
110
  def set_experiment_created_at(experiment, time)
107
- @experiments.insert :_id=>experiment, :created_at=>time
111
+ @experiments.insert(:_id=>experiment, :created_at=>time)
108
112
  end
109
113
 
110
114
  def get_experiment_created_at(experiment)
@@ -152,8 +156,8 @@ module Vanity
152
156
 
153
157
  # Determines if a participant already has seen this alternative in this experiment.
154
158
  def ab_seen(experiment, identity, alternative)
155
- participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:seen] })
156
- participant && participant["seen"].first == alternative.id
159
+ participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:seen] })
160
+ participant && participant["seen"].first == alternative.id
157
161
  end
158
162
 
159
163
  # Returns the participant's seen alternative in this experiment, if it exists