vanity 2.1.2 → 2.2.0

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: e624cf4ffac44db90b2d87b2142487870e8d8313
4
- data.tar.gz: d2f59e2b24bf57977ac7e6494416b5a8eab08c6b
3
+ metadata.gz: a239324275cb444df1667c84c26134d4cea832af
4
+ data.tar.gz: 3640a24cc2166d34f1211f629a6d5334bbcc1021
5
5
  SHA512:
6
- metadata.gz: 4f7713ef88ad77be3d31a16767ea3e5bf5cc5bb50478208aa3bb506e8f316eec26d1fb3e1752b7b6cae73c918a98cf5ad1dae78513e9e6e7c5bb20e329569861
7
- data.tar.gz: 3ff7a9e8f111e3aa83c56bcd7d4c3c834c76c9e0118ce6cacca8921362f78d1016c8c21555fd43f4a42f972557dac32e673becab80c1aacedfa2526fd00daba8
6
+ metadata.gz: b12cf807e8c67be3090a3d96bed156c8237dd8c127c3498a93c5ffc46ac9ebb70435cbf87a7b82f61f293b013fb10f5c4f0dd773e3fa4e9fb81364f90cbae817
7
+ data.tar.gz: 820e507831da2346e52f9589b1494cd30d6a83c3f508b6f5b67631e3f48ad5313e050ff04d5b09823116103ccc040d35e327a5b6412e4b975927d77ddb1d07e1
data/.travis.yml CHANGED
@@ -11,7 +11,6 @@ services:
11
11
  - mongodb
12
12
  - redis-server
13
13
  rvm:
14
- - 2.0.0
15
14
  - 2.1.0
16
15
  - 2.2.0
17
16
  - 2.3.0
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 2.2.0 (2016-3-26)
2
+ * Update mongo integration for mongo ruby driver 2.x. (@phillbaker)
3
+ * Centralize warnings to use `Vanity.logger` (@phillbaker)
4
+
1
5
  == 2.1.2 (2016-2-20)
2
6
 
3
7
  * Fix infinite loop on loading Vanity when using Redis and Redis fails to connect. #292 (@phillbaker)
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ gem "rack"
7
7
  # Persistence
8
8
  gem "redis", ">= 2.1"
9
9
  gem "redis-namespace", ">= 1.1.0"
10
- gem "mongo"
10
+ gem "mongo", "~> 2.1"
11
11
 
12
12
  # Math libraries
13
13
  gem "integration", "<= 0.1.0"
@@ -22,7 +22,7 @@ gem "webmock", :require=>false
22
22
  gem "fakefs", :require => "fakefs/safe"
23
23
 
24
24
  platform :ruby do
25
- gem "bson_ext"
25
+ # gem "bson_ext"
26
26
  gem "sqlite3", "~> 1.3.10"
27
27
  end
28
28
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- vanity (2.1.2)
4
+ vanity (2.2.0)
5
5
  i18n
6
6
 
7
7
  GEM
@@ -20,10 +20,8 @@ GEM
20
20
  rake
21
21
  thor (>= 0.14.0)
22
22
  blankslate (2.1.2.4)
23
- bson (1.6.0)
24
- bson (1.6.0-java)
25
- bson_ext (1.6.0)
26
- bson (= 1.6.0)
23
+ bson (4.0.2)
24
+ bson (4.0.2-java)
27
25
  celluloid (0.16.0)
28
26
  timers (~> 4.0.0)
29
27
  classifier-reborn (2.0.3)
@@ -76,8 +74,8 @@ GEM
76
74
  rb-inotify (>= 0.9)
77
75
  mercenary (0.3.5)
78
76
  minitest (4.7.5)
79
- mongo (1.6.0)
80
- bson (= 1.6.0)
77
+ mongo (2.2.3)
78
+ bson (~> 4.0)
81
79
  parslet (1.5.0)
82
80
  blankslate (~> 2.0)
83
81
  posix-spawn (0.3.11)
@@ -117,7 +115,6 @@ DEPENDENCIES
117
115
  RedCloth
118
116
  activerecord-jdbc-adapter
119
117
  appraisal (~> 1.0.2)
120
- bson_ext
121
118
  bundler (>= 1.8.0)
122
119
  fakefs
123
120
  garb (< 0.9.2)
@@ -125,7 +122,7 @@ DEPENDENCIES
125
122
  jdbc-sqlite3
126
123
  jekyll
127
124
  minitest (>= 4.2)
128
- mongo
125
+ mongo (~> 2.1)
129
126
  rack
130
127
  rake
131
128
  redis (>= 2.1)
data/README.md CHANGED
@@ -65,8 +65,7 @@ test:
65
65
  Add to your Gemfile:
66
66
 
67
67
  ```ruby
68
- gem "bson_ext"
69
- gem "mongo"
68
+ gem "mongo", "~> 2.0" # For Mongo 1.x support see Vanity versions 2.1 and below.
70
69
  ```
71
70
 
72
71
  A sample `config/vanity.yml` might look like:
@@ -249,9 +248,6 @@ your view no participants will be recorded.
249
248
 
250
249
  Here's what's tested and known to work:
251
250
 
252
- Ruby 2.0
253
- Persistence: Redis, Mongo, ActiveRecord
254
- Rails: 3.2, 4.1, 4.2
255
251
  Ruby 2.1
256
252
  Persistence: Redis, Mongo, ActiveRecord
257
253
  Rails: 3.2, 4.1, 4.2
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "rack"
6
6
  gem "redis", ">= 2.1"
7
7
  gem "redis-namespace", ">= 1.1.0"
8
- gem "mongo"
8
+ gem "mongo", "~> 2.1"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats", ">= 0.2.4"
11
11
  gem "garb", "< 0.9.2", :require => false
@@ -29,7 +29,6 @@ group :development do
29
29
  end
30
30
 
31
31
  platforms :ruby do
32
- gem "bson_ext"
33
32
  gem "sqlite3", "~> 1.3.10"
34
33
  end
35
34
 
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ..
9
9
  specs:
10
- vanity (2.1.2)
10
+ vanity (2.2.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -51,10 +51,7 @@ GEM
51
51
  thor (>= 0.14.0)
52
52
  arel (3.0.3)
53
53
  blankslate (2.1.2.4)
54
- bson (1.6.0)
55
- bson (1.6.0-java)
56
- bson_ext (1.6.0)
57
- bson (= 1.6.0)
54
+ bson (4.0.2)
58
55
  builder (3.0.4)
59
56
  celluloid (0.16.0)
60
57
  timers (~> 4.0.0)
@@ -121,8 +118,8 @@ GEM
121
118
  minitest (4.2.0)
122
119
  mocha (1.1.0)
123
120
  metaclass (~> 0.0.1)
124
- mongo (1.6.0)
125
- bson (= 1.6.0)
121
+ mongo (2.2.3)
122
+ bson (~> 4.0)
126
123
  multi_json (1.11.1)
127
124
  parslet (1.5.0)
128
125
  blankslate (~> 2.0)
@@ -205,7 +202,6 @@ DEPENDENCIES
205
202
  RedCloth
206
203
  activerecord-jdbc-adapter
207
204
  appraisal (~> 1.0.2)
208
- bson_ext
209
205
  bundler (>= 1.8.0)
210
206
  fakefs
211
207
  fastthread!
@@ -216,7 +212,7 @@ DEPENDENCIES
216
212
  minitest (~> 4.2.0)
217
213
  minitest_tu_shim (~> 1.3.3)
218
214
  mocha (~> 1.0)
219
- mongo
215
+ mongo (~> 2.1)
220
216
  passenger (~> 3.0)
221
217
  rack
222
218
  rails (= 3.2.22)
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "rack"
6
6
  gem "redis", ">= 2.1"
7
7
  gem "redis-namespace", ">= 1.1.0"
8
- gem "mongo"
8
+ gem "mongo", "~> 2.1"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats", ">= 0.2.4"
11
11
  gem "garb", "< 0.9.2", :require => false
@@ -26,7 +26,6 @@ group :development do
26
26
  end
27
27
 
28
28
  platforms :ruby do
29
- gem "bson_ext"
30
29
  gem "sqlite3", "~> 1.3.10"
31
30
  end
32
31
 
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: .././
9
9
  specs:
10
- vanity (2.1.2)
10
+ vanity (2.2.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -50,10 +50,7 @@ GEM
50
50
  thor (>= 0.14.0)
51
51
  arel (5.0.1.20140414130214)
52
52
  blankslate (2.1.2.4)
53
- bson (1.10.0)
54
- bson (1.10.0-java)
55
- bson_ext (1.10.0)
56
- bson (~> 1.10.0)
53
+ bson (4.0.2)
57
54
  builder (3.2.2)
58
55
  celluloid (0.16.0)
59
56
  timers (~> 4.0.0)
@@ -119,10 +116,8 @@ GEM
119
116
  minitest (5.5.1)
120
117
  mocha (1.1.0)
121
118
  metaclass (~> 0.0.1)
122
- mongo (1.10.0)
123
- bson (~> 1.10.0)
124
- mongo (1.10.0-java)
125
- bson (~> 1.10.0)
119
+ mongo (2.2.3)
120
+ bson (~> 4.0)
126
121
  multi_json (1.10.1)
127
122
  parslet (1.5.0)
128
123
  blankslate (~> 2.0)
@@ -199,7 +194,6 @@ DEPENDENCIES
199
194
  RedCloth
200
195
  activerecord-jdbc-adapter
201
196
  appraisal (~> 1.0.2)
202
- bson_ext
203
197
  bundler (>= 1.8.0)
204
198
  fakefs
205
199
  fastthread!
@@ -209,7 +203,7 @@ DEPENDENCIES
209
203
  jekyll
210
204
  minitest (>= 4.2)
211
205
  mocha (~> 1.0)
212
- mongo
206
+ mongo (~> 2.1)
213
207
  passenger (~> 3.0)
214
208
  rack
215
209
  rails (= 4.1.9)
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "rack"
6
6
  gem "redis", ">= 2.1"
7
7
  gem "redis-namespace", ">= 1.1.0"
8
- gem "mongo"
8
+ gem "mongo", "~> 2.1"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats", ">= 0.2.4"
11
11
  gem "garb", "< 0.9.2", :require => false
@@ -26,7 +26,6 @@ group :development do
26
26
  end
27
27
 
28
28
  platforms :ruby do
29
- gem "bson_ext"
30
29
  gem "sqlite3", "~> 1.3.10"
31
30
  end
32
31
 
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ..
9
9
  specs:
10
- vanity (2.1.2)
10
+ vanity (2.2.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -59,10 +59,7 @@ GEM
59
59
  thor (>= 0.14.0)
60
60
  arel (6.0.0)
61
61
  blankslate (2.1.2.4)
62
- bson (1.10.0)
63
- bson (1.10.0-java)
64
- bson_ext (1.10.0)
65
- bson (~> 1.10.0)
62
+ bson (4.0.2)
66
63
  builder (3.2.2)
67
64
  celluloid (0.16.0)
68
65
  timers (~> 4.0.0)
@@ -133,10 +130,8 @@ GEM
133
130
  minitest (5.5.1)
134
131
  mocha (1.1.0)
135
132
  metaclass (~> 0.0.1)
136
- mongo (1.10.0)
137
- bson (~> 1.10.0)
138
- mongo (1.10.0-java)
139
- bson (~> 1.10.0)
133
+ mongo (2.2.3)
134
+ bson (~> 4.0)
140
135
  multi_json (1.10.1)
141
136
  nokogiri (1.6.5)
142
137
  mini_portile (~> 0.6.0)
@@ -225,7 +220,6 @@ DEPENDENCIES
225
220
  RedCloth
226
221
  activerecord-jdbc-adapter
227
222
  appraisal (~> 1.0.2)
228
- bson_ext
229
223
  bundler (>= 1.8.0)
230
224
  fakefs
231
225
  fastthread!
@@ -235,7 +229,7 @@ DEPENDENCIES
235
229
  jekyll
236
230
  minitest (>= 4.2)
237
231
  mocha (~> 1.0)
238
- mongo
232
+ mongo (~> 2.1)
239
233
  passenger (~> 3.0)
240
234
  rack
241
235
  rails (= 4.2.0)
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "rack"
6
6
  gem "redis", ">= 2.1"
7
7
  gem "redis-namespace", ">= 1.1.0"
8
- gem "mongo"
8
+ gem "mongo", "~> 2.1"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats", ">= 0.2.4"
11
11
  gem "garb", "< 0.9.2", :require => false
@@ -27,7 +27,6 @@ group :development do
27
27
  end
28
28
 
29
29
  platforms :ruby do
30
- gem "bson_ext"
31
30
  gem "sqlite3", "~> 1.3.10"
32
31
  end
33
32
 
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ../
9
9
  specs:
10
- vanity (2.1.2)
10
+ vanity (2.2.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -55,9 +55,7 @@ GEM
55
55
  rake
56
56
  thor (>= 0.14.0)
57
57
  arel (6.0.3)
58
- bson (1.12.5)
59
- bson_ext (1.12.5)
60
- bson (~> 1.12.5)
58
+ bson (4.0.2)
61
59
  builder (3.2.2)
62
60
  colorator (0.1)
63
61
  concurrent-ruby (1.0.0)
@@ -105,8 +103,8 @@ GEM
105
103
  minitest (5.8.3)
106
104
  mocha (1.1.0)
107
105
  metaclass (~> 0.0.1)
108
- mongo (1.12.5)
109
- bson (= 1.12.5)
106
+ mongo (2.2.3)
107
+ bson (~> 4.0)
110
108
  nokogiri (1.6.7.1)
111
109
  mini_portile2 (~> 2.0.0.rc2)
112
110
  passenger (3.0.21)
@@ -180,7 +178,6 @@ DEPENDENCIES
180
178
  RedCloth
181
179
  activerecord-jdbc-adapter
182
180
  appraisal (~> 1.0.2)
183
- bson_ext
184
181
  bundler (>= 1.8.0)
185
182
  fakefs
186
183
  fastthread!
@@ -190,7 +187,7 @@ DEPENDENCIES
190
187
  jekyll
191
188
  minitest (>= 4.2)
192
189
  mocha (~> 1.0)
193
- mongo
190
+ mongo (~> 2.1)
194
191
  passenger (~> 3.0)
195
192
  protected_attributes (= 1.1.0)
196
193
  rack
@@ -71,7 +71,7 @@ module Vanity
71
71
  def set_experiment_enabled(experiment, enabled)
72
72
  fail "Not implemented"
73
73
  end
74
-
74
+
75
75
  # Returns true if experiment is enabled, the default (Vanity.configuration.experiments_start_enabled) is true.
76
76
  # (*except for mock_adapter, where default is true for testing)
77
77
  def is_experiment_enabled?(experiment)
@@ -95,7 +95,7 @@ module Vanity
95
95
  def is_experiment_completed?(experiment)
96
96
  @experiments[experiment] && @experiments[experiment][:completed_at]
97
97
  end
98
-
98
+
99
99
  def set_experiment_enabled(experiment, enabled)
100
100
  @experiments[experiment] ||= {}
101
101
  @experiments[experiment][:enabled] = enabled
@@ -18,24 +18,13 @@ module Vanity
18
18
  attr_reader :mongo
19
19
 
20
20
  def initialize(options)
21
- setup_connection(options)
22
21
  @options = options.clone
23
22
  @options[:database] ||= (@options[:path] && @options[:path].split("/")[1]) || "vanity"
24
23
  connect!
25
24
  end
26
25
 
27
- def setup_connection(options = {})
28
- if options[:hosts]
29
- args = (options[:hosts].map{|host| [host, options[:port]] } << {:connect => false})
30
- @mongo = Mongo::ReplSetConnection.new(*args)
31
- else
32
- @mongo = Mongo::Connection.new(options[:host], options[:port], :connect => false)
33
- end
34
- @mongo
35
- end
36
-
37
26
  def active?
38
- @mongo.connected?
27
+ !!@mongo
39
28
  end
40
29
 
41
30
  def disconnect!
@@ -50,16 +39,21 @@ module Vanity
50
39
  end
51
40
 
52
41
  def connect!
53
- @mongo ||= setup_connection(@options)
54
- @mongo.connect
55
- database = @mongo.db(@options[:database])
56
- database.authenticate @options[:username], @options[:password], true if @options[:username]
57
- @metrics = database.collection("vanity.metrics")
58
- @experiments = database.collection("vanity.experiments")
59
- @participants = database.collection("vanity.participants")
60
- @participants.create_index [[:experiment, 1], [:identity, 1]], :unique=>true
61
- @participants.create_index [[:experiment, 1], [:seen, 1]]
62
- @participants.create_index [[:experiment, 1], [:converted, 1]]
42
+ Mongo::Logger.logger = Vanity.logger
43
+ setup_connection(@options)
44
+
45
+ @metrics = @mongo["vanity.metrics"]
46
+ @metrics.create unless @mongo.database.collection_names.include?("vanity.metrics")
47
+ @experiments = @mongo["vanity.experiments"]
48
+ @experiments.create unless @mongo.database.collection_names.include?("vanity.experiments")
49
+ @participants = @mongo["vanity.participants"]
50
+ @participants.create unless @mongo.database.collection_names.include?("vanity.participants")
51
+ @participants.indexes.create_many(
52
+ { :key => { :experiment => 1, :identity => 1 }, :unique=>true },
53
+ { :key => { :experiment => 1, :seen => 1 } },
54
+ { :key => { :experiment => 1, :converted => 1 } }
55
+ )
56
+
63
57
  @mongo
64
58
  end
65
59
 
@@ -78,7 +72,7 @@ module Vanity
78
72
  # -- Metrics --
79
73
 
80
74
  def get_metric_last_update_at(metric)
81
- record = @metrics.find_one(:_id=>metric)
75
+ record = @metrics.find(:_id=>metric).limit(1).first
82
76
  record && record["last_update_at"]
83
77
  end
84
78
 
@@ -87,55 +81,77 @@ module Vanity
87
81
  values.each_with_index do |v,i|
88
82
  inc["data.#{timestamp.to_date}.#{i}"] = v
89
83
  end
90
- @metrics.update({ :_id=>metric }, { "$inc"=>inc, "$set"=>{ :last_update_at=>Time.now } }, :upsert=>true)
84
+ @metrics.find(:_id=>metric).find_one_and_replace(
85
+ {
86
+ "$inc"=>inc,
87
+ "$set"=>{ :last_update_at=>Time.now }
88
+ },
89
+ :upsert=>true
90
+ )
91
91
  end
92
92
 
93
93
  def metric_values(metric, from, to)
94
- record = @metrics.find_one(:_id=>metric)
94
+ record = @metrics.find(:_id=>metric).limit(1).first
95
95
  data = record && record["data"] || {}
96
96
  (from.to_date..to.to_date).map { |date| (data[date.to_s] || {}).values }
97
97
  end
98
98
 
99
99
  def destroy_metric(metric)
100
- @metrics.remove :_id=>metric
100
+ @metrics.find(:_id=>metric).delete_one
101
101
  end
102
102
 
103
103
 
104
104
  # -- Experiments --
105
105
 
106
106
  def experiment_persisted?(experiment)
107
- !!@experiments.find_one({ :_id=>experiment })
107
+ !!@experiments.find(:_id=>experiment).limit(1).first
108
108
  end
109
109
 
110
110
  def set_experiment_created_at(experiment, time)
111
- @experiments.insert(:_id=>experiment, :created_at=>time)
111
+ # @experiments.insert_one(:_id=>experiment, :created_at=>time)
112
+ @experiments.find(:_id=>experiment).find_one_and_replace(
113
+ {
114
+ "$setOnInsert"=>{ :created_at=>time }
115
+ },
116
+ :upsert=>true
117
+ )
112
118
  end
113
119
 
114
120
  def get_experiment_created_at(experiment)
115
- record = @experiments.find_one({ :_id=>experiment }, { :fields=>[:created_at] })
121
+ record = @experiments.find(:_id=>experiment).limit(1).projection(:created_at=>1).first
116
122
  record && record["created_at"]
117
123
  #Returns nil if either the record or the field doesn't exist
118
124
  end
119
125
 
120
126
  def set_experiment_completed_at(experiment, time)
121
- @experiments.update({ :_id=>experiment }, { "$set"=>{ :completed_at=>time } }, :upsert=>true)
127
+ @experiments.find(:_id=>experiment).find_one_and_replace(
128
+ {
129
+ "$set"=>{ :completed_at=>time }
130
+ },
131
+ :upsert=>true
132
+ )
122
133
  end
123
134
 
124
135
  def get_experiment_completed_at(experiment)
125
- record = @experiments.find_one({ :_id=>experiment }, { :fields=>[:completed_at] })
136
+ record = @experiments.find(:_id=>experiment).limit(1).projection(:completed_at=>1).first
126
137
  record && record["completed_at"]
127
138
  end
128
139
 
129
140
  def is_experiment_completed?(experiment)
130
- !!@experiments.find_one(:_id=>experiment, :completed_at=>{ "$exists"=>true })
141
+ !!@experiments.find(:_id=>experiment, :completed_at=>{ "$exists"=>true }).limit(1).first
131
142
  end
132
143
 
133
144
  def set_experiment_enabled(experiment, enabled)
134
- @experiments.update({ :_id=>experiment }, { "$set"=>{ :enabled=>enabled } }, :upsert=>true)
145
+ @experiments.find(:_id=>experiment).find_one_and_replace(
146
+ {
147
+ "$set"=>{ :enabled=>enabled }
148
+ },
149
+ :upsert=>true
150
+ )
135
151
  end
136
152
 
137
153
  def is_experiment_enabled?(experiment)
138
- record = @experiments.find_one({ :_id=>experiment}, { :fields=>[:enabled] })
154
+ record = @experiments.find(:_id=>experiment).limit(1).projection(:enabled=>1).first
139
155
  if Vanity.configuration.experiments_start_enabled
140
156
  record == nil || record["enabled"] != false
141
157
  else
@@ -144,7 +160,7 @@ module Vanity
144
160
  end
145
161
 
146
162
  def ab_counts(experiment, alternative)
147
- record = @experiments.find_one({ :_id=>experiment }, { :fields=>[:conversions] })
163
+ record = @experiments.find(:_id=>experiment ).limit(1).projection(:conversions=>1).first
148
164
  conversions = record && record["conversions"]
149
165
  { :participants => @participants.find({ :experiment=>experiment, :seen=>alternative }).count,
150
166
  :converted => @participants.find({ :experiment=>experiment, :converted=>alternative }).count,
@@ -152,56 +168,109 @@ module Vanity
152
168
  end
153
169
 
154
170
  def ab_show(experiment, identity, alternative)
155
- @participants.update({ :experiment=>experiment, :identity=>identity }, { "$set"=>{ :show=>alternative } }, :upsert=>true)
171
+ @participants.find(:experiment=>experiment, :identity=>identity).find_one_and_replace(
172
+ {
173
+ "$set"=>{ :show=>alternative }
174
+ },
175
+ :upsert=>true
176
+ )
156
177
  end
157
178
 
158
179
  def ab_showing(experiment, identity)
159
- participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:show] })
180
+ participant = @participants.find(:experiment=>experiment, :identity=>identity).limit(1).projection(:show=>1).first
160
181
  participant && participant["show"]
161
182
  end
162
183
 
163
184
  def ab_not_showing(experiment, identity)
164
- @participants.update({ :experiment=>experiment, :identity=>identity }, { "$unset"=>:show })
185
+ @participants.find(:experiment=>experiment, :identity=>identity).find_one_and_replace(
186
+ {
187
+ "$unset"=> { :show => "" }
188
+ },
189
+ :upsert=>true
190
+ )
165
191
  end
166
192
 
167
193
  def ab_add_participant(experiment, alternative, identity)
168
- @participants.update({ :experiment=>experiment, :identity=>identity }, { "$push"=>{ :seen=>alternative } }, :upsert=>true)
194
+ @participants.find(:experiment=>experiment, :identity=>identity).find_one_and_replace(
195
+ {
196
+ "$push"=>{ :seen=>alternative }
197
+ },
198
+ :upsert=>true
199
+ )
169
200
  end
170
201
 
171
202
  # Determines if a participant already has seen this alternative in this experiment.
172
203
  def ab_seen(experiment, identity, alternative)
173
- participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:seen] })
204
+ participant = @participants.find(:experiment=>experiment, :identity=>identity).limit(1).projection(:seen=>1).first
174
205
  participant && participant["seen"].first == alternative.id
175
206
  end
176
207
 
177
208
  # Returns the participant's seen alternative in this experiment, if it exists
178
209
  def ab_assigned(experiment, identity)
179
- participant = @participants.find_one({ :experiment=>experiment, :identity=>identity }, { :fields=>[:seen] })
210
+ participant = @participants.find(:experiment=>experiment, :identity=>identity).limit(1).projection(:seen=>1).first
180
211
  participant && participant["seen"].first
181
212
  end
182
213
 
183
214
  def ab_add_conversion(experiment, alternative, identity, count = 1, implicit = false)
184
215
  if implicit
185
- @participants.update({ :experiment=>experiment, :identity=>identity }, { "$push"=>{ :seen=>alternative } }, :upsert=>true)
216
+ @participants.find(:experiment=>experiment, :identity=>identity).find_one_and_replace(
217
+ {
218
+ "$push"=>{ :seen=>alternative }
219
+ },
220
+ :upsert=>true
221
+ )
186
222
  else
187
- participating = @participants.find_one(:experiment=>experiment, :identity=>identity, :seen=>alternative)
223
+ participating = @participants.find(:experiment=>experiment, :identity=>identity, :seen=>alternative).limit(1).first
224
+ end
225
+
226
+ if implicit || participating
227
+ @participants.find(:experiment=>experiment, :identity=>identity).find_one_and_replace(
228
+ {
229
+ "$push"=>{ :converted=>alternative }
230
+ },
231
+ :upsert=>true
232
+ )
188
233
  end
189
- @participants.update({ :experiment=>experiment, :identity=>identity }, { "$push"=>{ :converted=>alternative } }, :upsert=>true) if implicit || participating
190
- @experiments.update({ :_id=>experiment }, { "$inc"=>{ "conversions.#{alternative}"=>count } }, :upsert=>true)
234
+
235
+ @experiments.find(:_id=>experiment).find_one_and_replace(
236
+ {
237
+ "$inc"=>{ "conversions.#{alternative}"=>count }
238
+ },
239
+ :upsert=>true
240
+ )
191
241
  end
192
242
 
193
243
  def ab_get_outcome(experiment)
194
- experiment = @experiments.find_one({ :_id=>experiment }, { :fields=>[:outcome] })
244
+ experiment = @experiments.find(:_id=>experiment).limit(1).projection(:outcome=>1).first
195
245
  experiment && experiment["outcome"]
196
246
  end
197
247
 
198
248
  def ab_set_outcome(experiment, alternative = 0)
199
- @experiments.update({ :_id=>experiment }, { "$set"=>{ :outcome=>alternative } }, :upsert=>true)
249
+ @experiments.find(:_id=>experiment).find_one_and_replace(
250
+ {
251
+ "$set"=>{ :outcome=>alternative }
252
+ },
253
+ :upsert=>true
254
+ )
200
255
  end
201
256
 
202
257
  def destroy_experiment(experiment)
203
- @experiments.remove :_id=>experiment
204
- @participants.remove :experiment=>experiment
258
+ @experiments.find(:_id=>experiment).delete_one
259
+ @participants.find(:experiment=>experiment).delete_many
260
+ end
261
+
262
+ private
263
+
264
+ def setup_connection(options)
265
+ options[:user] = options[:username] if options[:username]
266
+
267
+ hosts = options.delete(:hosts) || [options.delete(:host)]
268
+ hosts.map! { |host| "#{host}:#{options.delete(:port)}" }
269
+
270
+ @mongo = Mongo::Client.new(
271
+ hosts,
272
+ options
273
+ )
205
274
  end
206
275
  end
207
276
  end
@@ -44,7 +44,7 @@ module Vanity
44
44
  begin
45
45
  redis.client.disconnect
46
46
  rescue Exception => e
47
- warn("Error while disconnecting from redis: #{e.message}")
47
+ Vanity.logger.warn("Error while disconnecting from redis: #{e.message}")
48
48
  end
49
49
  end
50
50
  @redis = nil
@@ -25,9 +25,9 @@ module Vanity
25
25
  nil
26
26
  end
27
27
 
28
- #
29
- # Filter all User-Agents that have 'bot', 'crawler', 'spider', URL.
30
- #
28
+ #
29
+ # Filter all User-Agents that have 'bot', 'crawler', 'spider', URL.
30
+ #
31
31
  def default_request_filter(request) # :nodoc:
32
32
  request &&
33
33
  request.env &&
@@ -27,10 +27,10 @@ module Vanity
27
27
  @use_probabilities = nil
28
28
  @is_default_set = false
29
29
  end
30
-
30
+
31
31
  # -- Default --
32
32
 
33
- # Call this method once to set a default alternative. Call without
33
+ # Call this method once to set a default alternative. Call without
34
34
  # arguments to obtain the current default. If default is not specified,
35
35
  # the first alternative is used.
36
36
  #
@@ -55,12 +55,12 @@ module Vanity
55
55
  end
56
56
 
57
57
  # -- Enabled --
58
-
58
+
59
59
  # Returns true if experiment is enabled, false if disabled.
60
60
  def enabled?
61
61
  !@playground.collecting? || (active? && connection.is_experiment_enabled?(@id))
62
62
  end
63
-
63
+
64
64
  # Enable or disable the experiment. Only works if the playground is collecting
65
65
  # and this experiment is enabled.
66
66
  #
@@ -70,8 +70,10 @@ module Vanity
70
70
  def enabled=(bool)
71
71
  return unless @playground.collecting? && active?
72
72
  if created_at.nil?
73
- warn 'DB has no created_at for this experiment! This most likely means' +
74
- 'you didn\'t call #save before calling enabled=, which you should.'
73
+ Vanity.logger.warn(
74
+ 'DB has no created_at for this experiment! This most likely means' +
75
+ 'you didn\'t call #save before calling enabled=, which you should.'
76
+ )
75
77
  else
76
78
  connection.set_experiment_enabled(@id, bool)
77
79
  end
@@ -187,9 +189,9 @@ module Vanity
187
189
  if @playground.collecting?
188
190
  if active?
189
191
  if enabled?
190
- return assignment_for_identity(request)
192
+ return assignment_for_identity(request)
191
193
  else
192
- # Show the default if experiment is disabled.
194
+ # Show the default if experiment is disabled.
193
195
  return default
194
196
  end
195
197
  else
@@ -340,13 +342,13 @@ module Vanity
340
342
  require "integration"
341
343
  require "rubystats"
342
344
  rescue LoadError
343
- fail "to use bayes_bandit_score, install integration and rubystats gems"
345
+ fail("to use bayes_bandit_score, install integration and rubystats gems")
344
346
  end
345
347
 
346
348
  begin
347
349
  require "gsl"
348
350
  rescue LoadError
349
- warn "for better integration performance, install gsl gem"
351
+ Vanity.logger.warn("for better integration performance, install gsl gem")
350
352
  end
351
353
 
352
354
  BayesianBanditScore.new(alternatives, outcome).calculate!
@@ -480,8 +482,8 @@ module Vanity
480
482
  begin
481
483
  result = @outcome_is.call
482
484
  outcome = result.id if Alternative === result && result.experiment == self
483
- rescue
484
- warn "Error in AbTest#complete!: #{$!}"
485
+ rescue => e
486
+ Vanity.logger.warn("Error in AbTest#complete!: #{e}")
485
487
  end
486
488
  else
487
489
  best = score.best
@@ -499,7 +501,7 @@ module Vanity
499
501
  connection.destroy_experiment(@id)
500
502
  super
501
503
  end
502
-
504
+
503
505
  # clears all collected data for the experiment
504
506
  def reset
505
507
  return unless @playground.collecting?
@@ -524,7 +526,7 @@ module Vanity
524
526
  # and declared.
525
527
  def save
526
528
  if @saved
527
- warn "Experiment #{name} has already been saved"
529
+ Vanity.logger.warn("Experiment #{name} has already been saved")
528
530
  return
529
531
  end
530
532
  @saved = true
@@ -532,21 +534,21 @@ module Vanity
532
534
  fail "Experiment #{name} needs at least two alternatives" unless @alternatives.size >= 2
533
535
  if !@is_default_set
534
536
  default(@alternatives.first)
535
- warn "No default alternative specified; choosing #{@default} as default."
537
+ Vanity.logger.warn("No default alternative specified; choosing #{@default} as default.")
536
538
  elsif alternative(@default).nil?
537
- #Specified a default that wasn't listed as an alternative; warn and override.
538
- warn "Attempted to set unknown alternative #{@default} as default! Using #{@alternatives.first} instead."
539
- #Set the instance variable directly since default(value) is no longer defined
539
+ # Specified a default that wasn't listed as an alternative; warn and override.
540
+ Vanity.logger.warn("Attempted to set unknown alternative #{@default} as default! Using #{@alternatives.first} instead.")
541
+ # Set the instance variable directly since default(value) is no longer defined
540
542
  @default = @alternatives.first
541
543
  end
542
544
  super
543
545
  if @metrics.nil? || @metrics.empty?
544
- warn "Please use metrics method to explicitly state which metric you are measuring against."
546
+ Vanity.logger.warn("Please use metrics method to explicitly state which metric you are measuring against.")
545
547
  metric = @playground.metrics[id] ||= Vanity::Metric.new(@playground, name)
546
548
  @metrics = [metric]
547
549
  end
548
550
  @metrics.each do |metric|
549
- metric.hook &method(:track!)
551
+ metric.hook(&method(:track!))
550
552
  end
551
553
  end
552
554
 
@@ -587,7 +589,7 @@ module Vanity
587
589
  end
588
590
 
589
591
  # Returns the assigned alternative, previously chosen alternative, or
590
- # alternative_for for a given identity.
592
+ # alternative_for for a given identity.
591
593
  def assignment_for_identity(request)
592
594
  identity = identity()
593
595
  if filter_visitor?(request, identity)
@@ -633,7 +635,7 @@ module Vanity
633
635
  end
634
636
 
635
637
  def filter_visitor?(request, identity)
636
- @playground.request_filter.call(request) ||
638
+ @playground.request_filter.call(request) ||
637
639
  (@request_filter_block && @request_filter_block.call(request, identity))
638
640
  end
639
641
 
@@ -158,7 +158,7 @@ module Vanity
158
158
  return unless @playground.collecting?
159
159
  connection.set_experiment_created_at @id, Time.now
160
160
  end
161
-
161
+
162
162
  # -- Filtering Particpants --
163
163
 
164
164
  # Define an experiment specific request filter. For example:
@@ -191,8 +191,8 @@ module Vanity
191
191
  if @complete_block
192
192
  begin
193
193
  complete! if @complete_block.call
194
- rescue
195
- warn "Error in Vanity::Experiment::Base: #{$!}"
194
+ rescue => e
195
+ Vanity.logger.warn("Error in Vanity::Experiment::Base: #{e}")
196
196
  end
197
197
  end
198
198
  end
@@ -106,7 +106,7 @@ module Vanity
106
106
  identity ||= if @ar_identity_block
107
107
  @ar_identity_block.call(record)
108
108
  end
109
-
109
+
110
110
  call_hooks record.send(@ar_timestamp), identity, [count] if count > 0 && @ar_scoped.exists?(record.id)
111
111
  end
112
112
  end
@@ -1,5 +1,5 @@
1
1
  module Vanity
2
- VERSION = "2.1.2"
2
+ VERSION = "2.2.0"
3
3
 
4
4
  module Version
5
5
  version = VERSION.to_s.split(".").map { |i| i.to_i }
@@ -14,7 +14,7 @@ describe Vanity::Adapters::RedisAdapter do
14
14
  mocked_redis.expects(:client).raises(RuntimeError)
15
15
  redis_adapter = Vanity::Adapters::RedisAdapter.new({})
16
16
  redis_adapter.stubs(:redis).returns(mocked_redis)
17
- redis_adapter.expects(:warn).with("Error while disconnecting from redis: RuntimeError")
17
+ Vanity.logger.expects(:warn).with("Error while disconnecting from redis: RuntimeError")
18
18
  redis_adapter.disconnect!
19
19
  end
20
20
  end
@@ -181,28 +181,28 @@ class AbTestTest < ActionController::TestCase
181
181
  exp = experiment(:nil_default_default)
182
182
  assert_equal exp.default, exp.alternative(nil)
183
183
  end
184
-
185
-
184
+
185
+
186
186
  # -- Experiment Enabled/disabled --
187
-
187
+
188
188
  # @example new test should be enabled regardless of collecting?
189
189
  # regardless_of "Vanity.playground.collecting" do
190
190
  # assert (new_ab_test :test).enabled?
191
191
  # end
192
192
  def regardless_of(attr_name, &block)
193
193
  prev_val = eval "#{attr_name}?"
194
-
194
+
195
195
  eval "#{attr_name}=true"
196
196
  block.call(eval "#{attr_name}?")
197
197
  nuke_playground
198
-
198
+
199
199
  eval "#{attr_name}=false"
200
200
  block.call(eval "#{attr_name}?")
201
201
  nuke_playground
202
-
202
+
203
203
  eval "#{attr_name}=prev_val"
204
204
  end
205
-
205
+
206
206
  def test_new_test_is_disabled_when_experiments_start_enabled_is_false
207
207
  Vanity.configuration.experiments_start_enabled = false
208
208
  exp = new_ab_test :test, enable: false do
@@ -220,7 +220,7 @@ class AbTestTest < ActionController::TestCase
220
220
  end
221
221
  assert exp.enabled?
222
222
  end
223
-
223
+
224
224
  def test_complete_sets_enabled_false
225
225
  Vanity.playground.collecting = true
226
226
  exp = new_ab_test :test do
@@ -248,14 +248,14 @@ class AbTestTest < ActionController::TestCase
248
248
  metrics :coolness
249
249
  default false
250
250
  end
251
-
251
+
252
252
  exp.enabled = true
253
253
  assert exp.enabled?
254
-
254
+
255
255
  exp.enabled = false
256
256
  assert !exp.enabled?
257
257
  end
258
-
258
+
259
259
  def test_cannot_set_enabled_for_inactive
260
260
  Vanity.playground.collecting = true
261
261
  exp = new_ab_test :test do
@@ -278,19 +278,19 @@ class AbTestTest < ActionController::TestCase
278
278
  exp.enabled = false
279
279
  assert exp.enabled?
280
280
  end
281
-
281
+
282
282
  def test_enabled_persists_across_definitions
283
283
  Vanity.configuration.experiments_start_enabled = false
284
284
  Vanity.playground.collecting = true
285
- new_ab_test :test, :enable => false do
285
+ new_ab_test :test, :enable => false do
286
286
  metrics :coolness
287
287
  default false
288
288
  end
289
289
  assert !experiment(:test).enabled? #starts off false
290
-
290
+
291
291
  new_playground
292
292
  metric "Coolness"
293
-
293
+
294
294
  new_ab_test :test, :enable => false do
295
295
  metrics :coolness
296
296
  default false
@@ -298,10 +298,10 @@ class AbTestTest < ActionController::TestCase
298
298
  assert !experiment(:test).enabled? #still false
299
299
  experiment(:test).enabled = true
300
300
  assert experiment(:test).enabled? #now true
301
-
301
+
302
302
  new_playground
303
303
  metric "Coolness"
304
-
304
+
305
305
  new_ab_test :test, :enable => false do
306
306
  metrics :coolness
307
307
  default false
@@ -314,15 +314,15 @@ class AbTestTest < ActionController::TestCase
314
314
  def test_enabled_persists_across_definitions_when_starting_enabled
315
315
  Vanity.configuration.experiments_start_enabled = true
316
316
  Vanity.playground.collecting = true
317
- new_ab_test :test, :enable => false do
317
+ new_ab_test :test, :enable => false do
318
318
  metrics :coolness
319
319
  default false
320
320
  end
321
321
  assert experiment(:test).enabled? #starts off true
322
-
322
+
323
323
  new_playground
324
324
  metric "Coolness"
325
-
325
+
326
326
  new_ab_test :test, :enable => false do
327
327
  metrics :coolness
328
328
  default false
@@ -330,10 +330,10 @@ class AbTestTest < ActionController::TestCase
330
330
  assert experiment(:test).enabled? #still true
331
331
  experiment(:test).enabled = false
332
332
  assert !experiment(:test).enabled? #now false
333
-
333
+
334
334
  new_playground
335
335
  metric "Coolness"
336
-
336
+
337
337
  new_ab_test :test, :enable => false do
338
338
  metrics :coolness
339
339
  default false
@@ -342,12 +342,12 @@ class AbTestTest < ActionController::TestCase
342
342
  experiment(:test).enabled = true
343
343
  assert experiment(:test).enabled? #now true again
344
344
  end
345
-
345
+
346
346
  def test_choose_random_when_enabled
347
347
  regardless_of "Vanity.playground.collecting" do
348
348
  metric "Coolness"
349
349
 
350
- exp = new_ab_test :test do
350
+ exp = new_ab_test :test do
351
351
  metrics :coolness
352
352
  true_false
353
353
  default false
@@ -360,20 +360,20 @@ class AbTestTest < ActionController::TestCase
360
360
  assert_equal results, [true, false].to_set
361
361
  end
362
362
  end
363
-
363
+
364
364
  def test_choose_default_when_disabled
365
365
  exp = new_ab_test :test do
366
366
  metrics :coolness
367
367
  alternatives 0, 1, 2, 3, 4, 5
368
368
  default 3
369
369
  end
370
-
370
+
371
371
  exp.enabled = false
372
372
  100.times.each do
373
373
  assert_equal 3, exp.choose.value
374
374
  end
375
375
  end
376
-
376
+
377
377
  def test_choose_outcome_when_finished
378
378
  exp = new_ab_test :test do
379
379
  metrics :coolness
@@ -386,7 +386,7 @@ class AbTestTest < ActionController::TestCase
386
386
  assert_equal 5, exp.choose.value
387
387
  end
388
388
  end
389
-
389
+
390
390
  # -- Experiment metric --
391
391
 
392
392
  def test_explicit_metric
@@ -1247,7 +1247,7 @@ This experiment did not run long enough to find a clear winner.
1247
1247
  default false
1248
1248
  end
1249
1249
  e = experiment(:quick)
1250
- e.expects(:warn)
1250
+ Vanity.logger.expects(:warn)
1251
1251
  assert_nothing_raised do
1252
1252
  e.complete!
1253
1253
  end
@@ -1448,9 +1448,9 @@ This experiment did not run long enough to find a clear winner.
1448
1448
  end
1449
1449
  assert_equal results, [:b].to_set
1450
1450
  end
1451
-
1451
+
1452
1452
  # -- Reset --
1453
-
1453
+
1454
1454
  def test_reset_clears_participants
1455
1455
  new_ab_test :simple do
1456
1456
  alternatives :a, :b, :c
@@ -1462,20 +1462,20 @@ This experiment did not run long enough to find a clear winner.
1462
1462
  experiment(:simple).reset
1463
1463
  assert_equal experiment(:simple).alternatives[1].participants, 0
1464
1464
  end
1465
-
1465
+
1466
1466
  def test_clears_outcome_and_completed_at
1467
1467
  new_ab_test :simple do
1468
1468
  alternatives :a, :b, :c
1469
1469
  default :a
1470
- metrics :coolness
1471
- end
1472
- experiment(:simple).reset
1473
- assert_nil experiment(:simple).outcome
1470
+ metrics :coolness
1471
+ end
1472
+ experiment(:simple).reset
1473
+ assert_nil experiment(:simple).outcome
1474
1474
  assert_nil experiment(:simple).completed_at
1475
1475
  end
1476
-
1476
+
1477
1477
  # -- Pick Winner --
1478
-
1478
+
1479
1479
  def test_complete_with_argument_sets_outcome_and_completes
1480
1480
  new_ab_test :simple do
1481
1481
  alternatives :a, :b, :c
@@ -146,7 +146,7 @@ describe Vanity::Experiment::Base do
146
146
  e = experiment(:ab)
147
147
  e.complete_if { true }
148
148
  e.stubs(:complete!).raises(RuntimeError, "A forced error")
149
- e.expects(:warn)
149
+ Vanity.logger.expects(:warn)
150
150
  e.stubs(:identity).returns(:b)
151
151
  e.track!(:a, Time.now, 10)
152
152
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vanity
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Assaf Arkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-23 00:00:00.000000000 Z
11
+ date: 2016-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -213,7 +213,7 @@ metadata: {}
213
213
  post_install_message: To get started run vanity --help
214
214
  rdoc_options:
215
215
  - --title
216
- - Vanity 2.1.2
216
+ - Vanity 2.2.0
217
217
  - --main
218
218
  - README.md
219
219
  - --webcvs