vanity 2.2.4 → 2.2.6
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.
- checksums.yaml +4 -4
- data/.travis.yml +7 -0
- data/Appraisals +7 -0
- data/CHANGELOG +7 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -7
- data/Rakefile +1 -0
- data/bin/vanity +9 -9
- data/gemfiles/rails32.gemfile.lock +2 -1
- data/gemfiles/rails41.gemfile.lock +2 -1
- data/gemfiles/rails42.gemfile.lock +2 -1
- data/gemfiles/rails42_protected_attributes.gemfile.lock +1 -1
- data/gemfiles/rails5.gemfile +33 -0
- data/gemfiles/rails5.gemfile.lock +256 -0
- data/lib/vanity/adapters/redis_adapter.rb +2 -2
- data/lib/vanity/autoconnect.rb +1 -1
- data/lib/vanity/configuration.rb +1 -1
- data/lib/vanity/experiment/ab_test.rb +13 -21
- data/lib/vanity/experiment/alternative.rb +3 -3
- data/lib/vanity/experiment/base.rb +3 -6
- data/lib/vanity/experiment/definition.rb +1 -1
- data/lib/vanity/frameworks/rails.rb +15 -29
- data/lib/vanity/helpers.rb +10 -17
- data/lib/vanity/metric/active_record.rb +1 -1
- data/lib/vanity/metric/base.rb +3 -3
- data/lib/vanity/templates.rb +1 -1
- data/lib/vanity/templates/_vanity.js.erb +1 -1
- data/lib/vanity/vanity.rb +17 -2
- data/lib/vanity/version.rb +1 -1
- data/test/dummy/app/controllers/use_vanity_controller.rb +16 -1
- data/test/experiment/ab_test.rb +9 -5
- data/test/frameworks/rails/action_controller_test.rb +12 -0
- data/test/frameworks/rails/action_view_test.rb +1 -0
- data/test/test_helper.rb +13 -3
- data/test/web/rails/dashboard_test.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63e3e69d3a1d79cb7f36548e9b7c5a2ddf626b17
|
4
|
+
data.tar.gz: 645fa9b2a710b2f0b7f631747bda160aed94c9eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1aba836ab77005465669a51695f8eb6fb01ac76841eea6cff3e5202b9c8275eb7777bf0c0dc1ff2c5f623d6e981bc161dcb8689b19f985f74a2a86bfe0c0b84e
|
7
|
+
data.tar.gz: 8e134db0be9cc68e9effd93170fa931bf03787cdc57bb438842ee5399aab8f549f33ca90c7afbe462da7d50bf3c2dacc7ab6a01bbf3af6506d7b0848df05c3ed
|
data/.travis.yml
CHANGED
@@ -24,3 +24,10 @@ gemfile:
|
|
24
24
|
- gemfiles/rails41.gemfile
|
25
25
|
- gemfiles/rails42.gemfile
|
26
26
|
- gemfiles/rails42_protected_attributes.gemfile
|
27
|
+
- gemfiles/rails5.gemfile
|
28
|
+
matrix:
|
29
|
+
exclude:
|
30
|
+
- rvm: 2.1
|
31
|
+
gemfile: gemfiles/rails5.gemfile
|
32
|
+
- rvm: jruby-19mode
|
33
|
+
gemfile: gemfiles/rails5.gemfile
|
data/Appraisals
CHANGED
@@ -29,3 +29,10 @@ appraise "rails42-protected_attributes" do
|
|
29
29
|
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
30
30
|
gem "passenger", "~>3.0"
|
31
31
|
end
|
32
|
+
|
33
|
+
appraise "rails5" do
|
34
|
+
gem "mocha", "~> 1.0", :require=>false
|
35
|
+
gem "rails", "5.0.0"
|
36
|
+
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
37
|
+
gem "passenger", "~>3.0"
|
38
|
+
end
|
data/CHANGELOG
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
== 2.2.
|
1
|
+
== 2.2.6 (2016-10-04)
|
2
|
+
* Fixes for `Vanity.ab_test()` vs. view helper `ab_test` (@phillbaker)
|
3
|
+
|
4
|
+
== 2.2.5 (2016-9-23)
|
5
|
+
* Updates for rails5 compatbility (@phillbaker)
|
6
|
+
|
7
|
+
== 2.2.4 (2016-9-21)
|
2
8
|
* Fix typo in template (@arthurxaud)
|
3
9
|
|
4
10
|
== 2.2.3 (2016-6-25)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,9 @@ Vanity is an A/B testing framework for Rails that is datastore agnostic.
|
|
19
19
|
|
20
20
|
Add to your Gemfile:
|
21
21
|
|
22
|
-
|
22
|
+
```ruby
|
23
|
+
gem "vanity"
|
24
|
+
```
|
23
25
|
|
24
26
|
(For support for older versions of Rails and Ruby 1.8, please see the [1.9.x
|
25
27
|
branch](https://github.com/assaf/vanity/tree/1-9-stable).)
|
@@ -35,8 +37,10 @@ Datastores should be configured using a `config/vanity.yml`.
|
|
35
37
|
|
36
38
|
Add to your Gemfile:
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
+
```ruby
|
41
|
+
gem "redis", ">= 2.1"
|
42
|
+
gem "redis-namespace", ">= 1.1.0"
|
43
|
+
```
|
40
44
|
|
41
45
|
By default Vanity is configured to use Redis on localhost port 6379 with
|
42
46
|
database 0.
|
@@ -62,7 +66,7 @@ test:
|
|
62
66
|
|
63
67
|
To re-use an existing redis connection, you can call `Vanity.connect!` explicitly, for example:
|
64
68
|
|
65
|
-
```
|
69
|
+
```ruby
|
66
70
|
Vanity.connect!(
|
67
71
|
adapter: :redis,
|
68
72
|
redis: $redis
|
@@ -134,7 +138,7 @@ $ rake db:migrate
|
|
134
138
|
If you're using a forking server (like Passenger or Unicorn), you should
|
135
139
|
reconnect after a new worker is created:
|
136
140
|
|
137
|
-
```
|
141
|
+
```ruby
|
138
142
|
# unicorn.rb
|
139
143
|
after_fork do |server, worker|
|
140
144
|
defined?(Vanity) && Vanity.reconnect!
|
@@ -153,7 +157,7 @@ end
|
|
153
157
|
|
154
158
|
If you're using explicit options with `Vanity.connect!`, you should call `disconnect!` first, for example:
|
155
159
|
|
156
|
-
```
|
160
|
+
```ruby
|
157
161
|
Vanity.disconnect!
|
158
162
|
Vanity.connect!(
|
159
163
|
adapter: 'redis',
|
@@ -294,8 +298,11 @@ Here's what's tested and known to work:
|
|
294
298
|
Rails: 3.2, 4.1, 4.2
|
295
299
|
Ruby 2.2
|
296
300
|
Persistence: Redis, Mongo, ActiveRecord
|
297
|
-
Rails: 3.2, 4.1, 4.2
|
301
|
+
Rails: 3.2, 4.1, 4.2, 5
|
298
302
|
Ruby 2.3
|
303
|
+
Persistence: Redis, Mongo, ActiveRecord
|
304
|
+
Rails: 3.2, 4.1, 4.2, 5
|
305
|
+
JRuby 1.9
|
299
306
|
Persistence: Redis, Mongo, ActiveRecord
|
300
307
|
Rails: 3.2, 4.1, 4.2
|
301
308
|
|
data/Rakefile
CHANGED
data/bin/vanity
CHANGED
@@ -3,7 +3,7 @@ if File.exist?("config/boot.rb") && File.exist?("config/environment.rb")
|
|
3
3
|
require "./config/environment"
|
4
4
|
else
|
5
5
|
path = File.expand_path("../lib", File.dirname(__FILE__))
|
6
|
-
$LOAD_PATH.unshift
|
6
|
+
$LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
|
7
7
|
require "vanity"
|
8
8
|
end
|
9
9
|
|
@@ -11,7 +11,7 @@ require "optparse"
|
|
11
11
|
|
12
12
|
playground = Vanity.playground
|
13
13
|
options = Struct.new(:output).new
|
14
|
-
|
14
|
+
parser = OptionParser.new("", 24, " ") do |opts|
|
15
15
|
opts.banner = "Usage: #{File.basename($0)} [options] command\n"
|
16
16
|
opts.banner << "Commands:\n"
|
17
17
|
opts.banner << " list List all experiments and metrics\n"
|
@@ -19,17 +19,17 @@ opts = OptionParser.new("", 24, " ") do |opts|
|
|
19
19
|
|
20
20
|
opts.separator ""
|
21
21
|
opts.separator "Reporting options:"
|
22
|
-
opts.on "--output FILE", "Write report to this file (default: stdout)" do |
|
23
|
-
options.output =
|
22
|
+
opts.on "--output FILE", "Write report to this file (default: stdout)" do |report_path|
|
23
|
+
options.output = report_path
|
24
24
|
end
|
25
25
|
|
26
26
|
opts.separator ""
|
27
27
|
opts.separator "Common options:"
|
28
|
-
opts.on "--load_path PATH", "Path to experiments directory (default: #{playground.load_path})" do |
|
29
|
-
playground.load_path =
|
28
|
+
opts.on "--load_path PATH", "Path to experiments directory (default: #{playground.load_path})" do |load_path|
|
29
|
+
playground.load_path = load_path
|
30
30
|
end
|
31
31
|
opts.on "-d", "--database url", "Database connection URL (e.g. redis://localhost:6379)" do |conn|
|
32
|
-
playground.establish_connection
|
32
|
+
playground.establish_connection(conn)
|
33
33
|
end
|
34
34
|
opts.on_tail "-h", "--help", "Show this message" do
|
35
35
|
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
@@ -41,9 +41,9 @@ opts = OptionParser.new("", 24, " ") do |opts|
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
parser.parse!(ARGV)
|
45
45
|
if ARGV.empty?
|
46
|
-
puts
|
46
|
+
puts parser.banner
|
47
47
|
exit
|
48
48
|
end
|
49
49
|
|
@@ -7,7 +7,7 @@ GIT
|
|
7
7
|
PATH
|
8
8
|
remote: ..
|
9
9
|
specs:
|
10
|
-
vanity (2.2.
|
10
|
+
vanity (2.2.6)
|
11
11
|
i18n
|
12
12
|
|
13
13
|
GEM
|
@@ -52,6 +52,7 @@ GEM
|
|
52
52
|
arel (3.0.3)
|
53
53
|
blankslate (2.1.2.4)
|
54
54
|
bson (4.0.2)
|
55
|
+
bson (4.0.2-java)
|
55
56
|
builder (3.0.4)
|
56
57
|
celluloid (0.16.0)
|
57
58
|
timers (~> 4.0.0)
|
@@ -7,7 +7,7 @@ GIT
|
|
7
7
|
PATH
|
8
8
|
remote: .././
|
9
9
|
specs:
|
10
|
-
vanity (2.2.
|
10
|
+
vanity (2.2.6)
|
11
11
|
i18n
|
12
12
|
|
13
13
|
GEM
|
@@ -51,6 +51,7 @@ GEM
|
|
51
51
|
arel (5.0.1.20140414130214)
|
52
52
|
blankslate (2.1.2.4)
|
53
53
|
bson (4.0.2)
|
54
|
+
bson (4.0.2-java)
|
54
55
|
builder (3.2.2)
|
55
56
|
celluloid (0.16.0)
|
56
57
|
timers (~> 4.0.0)
|
@@ -7,7 +7,7 @@ GIT
|
|
7
7
|
PATH
|
8
8
|
remote: ..
|
9
9
|
specs:
|
10
|
-
vanity (2.2.
|
10
|
+
vanity (2.2.6)
|
11
11
|
i18n
|
12
12
|
|
13
13
|
GEM
|
@@ -60,6 +60,7 @@ GEM
|
|
60
60
|
arel (6.0.0)
|
61
61
|
blankslate (2.1.2.4)
|
62
62
|
bson (4.0.2)
|
63
|
+
bson (4.0.2-java)
|
63
64
|
builder (3.2.2)
|
64
65
|
celluloid (0.16.0)
|
65
66
|
timers (~> 4.0.0)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rack"
|
6
|
+
gem "redis", ">= 2.1"
|
7
|
+
gem "redis-namespace", ">= 1.1.0"
|
8
|
+
gem "mongo", "~> 2.1"
|
9
|
+
gem "integration", "<= 0.1.0"
|
10
|
+
gem "rubystats", ">= 0.2.5"
|
11
|
+
gem "garb", "< 0.9.2", :require => false
|
12
|
+
gem "mocha", "~> 1.0", :require => false
|
13
|
+
gem "rails", "5.0.0"
|
14
|
+
gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
|
15
|
+
gem "passenger", "~>3.0"
|
16
|
+
|
17
|
+
group :development do
|
18
|
+
gem "rake"
|
19
|
+
gem "RedCloth"
|
20
|
+
gem "yard"
|
21
|
+
end
|
22
|
+
|
23
|
+
platforms :ruby do
|
24
|
+
gem "sqlite3", "~> 1.3.10"
|
25
|
+
gem "jekyll", "~> 2.5.3"
|
26
|
+
end
|
27
|
+
|
28
|
+
platforms :jruby do
|
29
|
+
gem "activerecord-jdbc-adapter"
|
30
|
+
gem "jdbc-sqlite3"
|
31
|
+
end
|
32
|
+
|
33
|
+
gemspec :development_group => :test, :path => "../"
|
@@ -0,0 +1,256 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/zoltankiss/fastthread.git
|
3
|
+
revision: cefbca3009b9c68df5e473d840462ebcc7fa1504
|
4
|
+
specs:
|
5
|
+
fastthread (1.0.7)
|
6
|
+
|
7
|
+
PATH
|
8
|
+
remote: ../
|
9
|
+
specs:
|
10
|
+
vanity (2.2.6)
|
11
|
+
i18n
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
RedCloth (4.3.0)
|
17
|
+
actioncable (5.0.0)
|
18
|
+
actionpack (= 5.0.0)
|
19
|
+
nio4r (~> 1.2)
|
20
|
+
websocket-driver (~> 0.6.1)
|
21
|
+
actionmailer (5.0.0)
|
22
|
+
actionpack (= 5.0.0)
|
23
|
+
actionview (= 5.0.0)
|
24
|
+
activejob (= 5.0.0)
|
25
|
+
mail (~> 2.5, >= 2.5.4)
|
26
|
+
rails-dom-testing (~> 2.0)
|
27
|
+
actionpack (5.0.0)
|
28
|
+
actionview (= 5.0.0)
|
29
|
+
activesupport (= 5.0.0)
|
30
|
+
rack (~> 2.0)
|
31
|
+
rack-test (~> 0.6.3)
|
32
|
+
rails-dom-testing (~> 2.0)
|
33
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
34
|
+
actionview (5.0.0)
|
35
|
+
activesupport (= 5.0.0)
|
36
|
+
builder (~> 3.1)
|
37
|
+
erubis (~> 2.7.0)
|
38
|
+
rails-dom-testing (~> 2.0)
|
39
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
40
|
+
activejob (5.0.0)
|
41
|
+
activesupport (= 5.0.0)
|
42
|
+
globalid (>= 0.3.6)
|
43
|
+
activemodel (5.0.0)
|
44
|
+
activesupport (= 5.0.0)
|
45
|
+
activerecord (5.0.0)
|
46
|
+
activemodel (= 5.0.0)
|
47
|
+
activesupport (= 5.0.0)
|
48
|
+
arel (~> 7.0)
|
49
|
+
activesupport (5.0.0)
|
50
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
51
|
+
i18n (~> 0.7)
|
52
|
+
minitest (~> 5.1)
|
53
|
+
tzinfo (~> 1.1)
|
54
|
+
addressable (2.4.0)
|
55
|
+
appraisal (1.0.3)
|
56
|
+
bundler
|
57
|
+
rake
|
58
|
+
thor (>= 0.14.0)
|
59
|
+
arel (7.0.0)
|
60
|
+
blankslate (2.1.2.4)
|
61
|
+
bson (4.1.1)
|
62
|
+
builder (3.2.2)
|
63
|
+
classifier-reborn (2.0.4)
|
64
|
+
fast-stemmer (~> 1.0)
|
65
|
+
coderay (1.1.1)
|
66
|
+
coffee-script (2.4.1)
|
67
|
+
coffee-script-source
|
68
|
+
execjs
|
69
|
+
coffee-script-source (1.10.0)
|
70
|
+
colorator (0.1)
|
71
|
+
concurrent-ruby (1.0.2)
|
72
|
+
crack (0.4.3)
|
73
|
+
safe_yaml (~> 1.0.0)
|
74
|
+
daemon_controller (1.2.0)
|
75
|
+
erubis (2.7.0)
|
76
|
+
execjs (2.6.0)
|
77
|
+
fakefs (0.8.1)
|
78
|
+
faraday (0.9.2)
|
79
|
+
multipart-post (>= 1.2, < 3)
|
80
|
+
fast-stemmer (1.0.2)
|
81
|
+
ffi (1.9.10)
|
82
|
+
garb (0.9.1)
|
83
|
+
activesupport (>= 2.2.0)
|
84
|
+
crack (>= 0.1.6)
|
85
|
+
globalid (0.3.6)
|
86
|
+
activesupport (>= 4.1.0)
|
87
|
+
hashdiff (0.3.0)
|
88
|
+
i18n (0.7.0)
|
89
|
+
integration (0.1.0)
|
90
|
+
jekyll (2.5.3)
|
91
|
+
classifier-reborn (~> 2.0)
|
92
|
+
colorator (~> 0.1)
|
93
|
+
jekyll-coffeescript (~> 1.0)
|
94
|
+
jekyll-gist (~> 1.0)
|
95
|
+
jekyll-paginate (~> 1.0)
|
96
|
+
jekyll-sass-converter (~> 1.0)
|
97
|
+
jekyll-watch (~> 1.1)
|
98
|
+
kramdown (~> 1.3)
|
99
|
+
liquid (~> 2.6.1)
|
100
|
+
mercenary (~> 0.3.3)
|
101
|
+
pygments.rb (~> 0.6.0)
|
102
|
+
redcarpet (~> 3.1)
|
103
|
+
safe_yaml (~> 1.0)
|
104
|
+
toml (~> 0.1.0)
|
105
|
+
jekyll-coffeescript (1.0.1)
|
106
|
+
coffee-script (~> 2.2)
|
107
|
+
jekyll-gist (1.4.0)
|
108
|
+
octokit (~> 4.2)
|
109
|
+
jekyll-paginate (1.1.0)
|
110
|
+
jekyll-sass-converter (1.4.0)
|
111
|
+
sass (~> 3.4)
|
112
|
+
jekyll-watch (1.4.0)
|
113
|
+
listen (~> 3.0, < 3.1)
|
114
|
+
kramdown (1.11.1)
|
115
|
+
liquid (2.6.3)
|
116
|
+
listen (3.0.7)
|
117
|
+
rb-fsevent (>= 0.9.3)
|
118
|
+
rb-inotify (>= 0.9.7)
|
119
|
+
loofah (2.0.3)
|
120
|
+
nokogiri (>= 1.5.9)
|
121
|
+
mail (2.6.4)
|
122
|
+
mime-types (>= 1.16, < 4)
|
123
|
+
mercenary (0.3.6)
|
124
|
+
metaclass (0.0.4)
|
125
|
+
method_source (0.8.2)
|
126
|
+
mime-types (3.1)
|
127
|
+
mime-types-data (~> 3.2015)
|
128
|
+
mime-types-data (3.2016.0521)
|
129
|
+
mini_portile2 (2.1.0)
|
130
|
+
minitest (5.9.0)
|
131
|
+
mocha (1.1.0)
|
132
|
+
metaclass (~> 0.0.1)
|
133
|
+
mongo (2.2.5)
|
134
|
+
bson (~> 4.0)
|
135
|
+
multipart-post (2.0.0)
|
136
|
+
nio4r (1.2.1)
|
137
|
+
nokogiri (1.6.8)
|
138
|
+
mini_portile2 (~> 2.1.0)
|
139
|
+
pkg-config (~> 1.1.7)
|
140
|
+
octokit (4.3.0)
|
141
|
+
sawyer (~> 0.7.0, >= 0.5.3)
|
142
|
+
parslet (1.5.0)
|
143
|
+
blankslate (~> 2.0)
|
144
|
+
passenger (3.0.21)
|
145
|
+
daemon_controller (>= 1.0.0)
|
146
|
+
fastthread (>= 1.0.1)
|
147
|
+
rack
|
148
|
+
rake (>= 0.8.1)
|
149
|
+
pkg-config (1.1.7)
|
150
|
+
posix-spawn (0.3.11)
|
151
|
+
pry (0.10.3)
|
152
|
+
coderay (~> 1.1.0)
|
153
|
+
method_source (~> 0.8.1)
|
154
|
+
slop (~> 3.4)
|
155
|
+
pygments.rb (0.6.3)
|
156
|
+
posix-spawn (~> 0.3.6)
|
157
|
+
yajl-ruby (~> 1.2.0)
|
158
|
+
rack (2.0.1)
|
159
|
+
rack-test (0.6.3)
|
160
|
+
rack (>= 1.0)
|
161
|
+
rails (5.0.0)
|
162
|
+
actioncable (= 5.0.0)
|
163
|
+
actionmailer (= 5.0.0)
|
164
|
+
actionpack (= 5.0.0)
|
165
|
+
actionview (= 5.0.0)
|
166
|
+
activejob (= 5.0.0)
|
167
|
+
activemodel (= 5.0.0)
|
168
|
+
activerecord (= 5.0.0)
|
169
|
+
activesupport (= 5.0.0)
|
170
|
+
bundler (>= 1.3.0, < 2.0)
|
171
|
+
railties (= 5.0.0)
|
172
|
+
sprockets-rails (>= 2.0.0)
|
173
|
+
rails-dom-testing (2.0.1)
|
174
|
+
activesupport (>= 4.2.0, < 6.0)
|
175
|
+
nokogiri (~> 1.6.0)
|
176
|
+
rails-html-sanitizer (1.0.3)
|
177
|
+
loofah (~> 2.0)
|
178
|
+
railties (5.0.0)
|
179
|
+
actionpack (= 5.0.0)
|
180
|
+
activesupport (= 5.0.0)
|
181
|
+
method_source
|
182
|
+
rake (>= 0.8.7)
|
183
|
+
thor (>= 0.18.1, < 2.0)
|
184
|
+
rake (11.2.2)
|
185
|
+
rb-fsevent (0.9.7)
|
186
|
+
rb-inotify (0.9.7)
|
187
|
+
ffi (>= 0.5.0)
|
188
|
+
redcarpet (3.3.4)
|
189
|
+
redis (3.3.0)
|
190
|
+
redis-namespace (1.5.2)
|
191
|
+
redis (~> 3.0, >= 3.0.4)
|
192
|
+
rubystats (0.2.5)
|
193
|
+
safe_yaml (1.0.4)
|
194
|
+
sass (3.4.22)
|
195
|
+
sawyer (0.7.0)
|
196
|
+
addressable (>= 2.3.5, < 2.5)
|
197
|
+
faraday (~> 0.8, < 0.10)
|
198
|
+
slop (3.6.0)
|
199
|
+
sprockets (3.6.3)
|
200
|
+
concurrent-ruby (~> 1.0)
|
201
|
+
rack (> 1, < 3)
|
202
|
+
sprockets-rails (3.1.1)
|
203
|
+
actionpack (>= 4.0)
|
204
|
+
activesupport (>= 4.0)
|
205
|
+
sprockets (>= 3.0.0)
|
206
|
+
sqlite3 (1.3.11)
|
207
|
+
thor (0.19.1)
|
208
|
+
thread_safe (0.3.5)
|
209
|
+
timecop (0.8.1)
|
210
|
+
toml (0.1.2)
|
211
|
+
parslet (~> 1.5.0)
|
212
|
+
tzinfo (1.2.2)
|
213
|
+
thread_safe (~> 0.1)
|
214
|
+
webmock (2.0.1)
|
215
|
+
addressable (>= 2.3.6)
|
216
|
+
crack (>= 0.3.2)
|
217
|
+
hashdiff
|
218
|
+
websocket-driver (0.6.4)
|
219
|
+
websocket-extensions (>= 0.1.0)
|
220
|
+
websocket-extensions (0.1.2)
|
221
|
+
yajl-ruby (1.2.1)
|
222
|
+
yard (0.8.7.6)
|
223
|
+
|
224
|
+
PLATFORMS
|
225
|
+
ruby
|
226
|
+
|
227
|
+
DEPENDENCIES
|
228
|
+
RedCloth
|
229
|
+
activerecord-jdbc-adapter
|
230
|
+
appraisal (~> 1.0.2)
|
231
|
+
bundler (>= 1.8.0)
|
232
|
+
fakefs
|
233
|
+
fastthread!
|
234
|
+
garb (< 0.9.2)
|
235
|
+
integration (<= 0.1.0)
|
236
|
+
jdbc-sqlite3
|
237
|
+
jekyll (~> 2.5.3)
|
238
|
+
minitest (>= 4.2)
|
239
|
+
mocha (~> 1.0)
|
240
|
+
mongo (~> 2.1)
|
241
|
+
passenger (~> 3.0)
|
242
|
+
pry
|
243
|
+
rack
|
244
|
+
rails (= 5.0.0)
|
245
|
+
rake
|
246
|
+
redis (>= 2.1)
|
247
|
+
redis-namespace (>= 1.1.0)
|
248
|
+
rubystats (>= 0.2.5)
|
249
|
+
sqlite3 (~> 1.3.10)
|
250
|
+
timecop
|
251
|
+
vanity!
|
252
|
+
webmock
|
253
|
+
yard
|
254
|
+
|
255
|
+
BUNDLED WITH
|
256
|
+
1.10.6
|
@@ -91,7 +91,7 @@ module Vanity
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def destroy_metric(metric)
|
94
|
-
@metrics.del
|
94
|
+
@metrics.del(*@metrics.keys("#{metric}:*"))
|
95
95
|
end
|
96
96
|
|
97
97
|
|
@@ -221,7 +221,7 @@ module Vanity
|
|
221
221
|
def destroy_experiment(experiment)
|
222
222
|
@experiments.del "#{experiment}:outcome", "#{experiment}:created_at", "#{experiment}:completed_at"
|
223
223
|
alternatives = @experiments.keys("#{experiment}:alts:*")
|
224
|
-
@experiments.del
|
224
|
+
@experiments.del(*alternatives) unless alternatives.empty?
|
225
225
|
end
|
226
226
|
|
227
227
|
protected
|
data/lib/vanity/autoconnect.rb
CHANGED
data/lib/vanity/configuration.rb
CHANGED
@@ -208,7 +208,7 @@ module Vanity
|
|
208
208
|
file_name ||= config_file
|
209
209
|
file_path = File.join(config_path, file_name)
|
210
210
|
|
211
|
-
if File.
|
211
|
+
if File.exist?(file_path)
|
212
212
|
config = YAML.load(ERB.new(File.read(file_path)).result)
|
213
213
|
config ||= {}
|
214
214
|
params_for_environment = config[environment.to_s]
|
@@ -460,7 +460,7 @@ module Vanity
|
|
460
460
|
# end
|
461
461
|
def outcome_is(&block)
|
462
462
|
raise ArgumentError, "Missing block" unless block
|
463
|
-
raise "outcome_is already called on this experiment" if @outcome_is
|
463
|
+
raise "outcome_is already called on this experiment" if defined?(@outcome_is)
|
464
464
|
@outcome_is = block
|
465
465
|
end
|
466
466
|
|
@@ -478,7 +478,7 @@ module Vanity
|
|
478
478
|
super
|
479
479
|
|
480
480
|
unless outcome
|
481
|
-
if @outcome_is
|
481
|
+
if defined?(@outcome_is)
|
482
482
|
begin
|
483
483
|
result = @outcome_is.call
|
484
484
|
outcome = result.id if Alternative === result && result.experiment == self
|
@@ -511,26 +511,18 @@ module Vanity
|
|
511
511
|
self
|
512
512
|
end
|
513
513
|
|
514
|
-
# clears all collected data for the experiment
|
515
|
-
def reset
|
516
|
-
connection.destroy_experiment(@id)
|
517
|
-
connection.set_experiment_created_at(@id, Time.now)
|
518
|
-
@outcome = @completed_at = nil
|
519
|
-
self
|
520
|
-
end
|
521
|
-
|
522
514
|
# Set up tracking for metrics and ensure that the attributes of the ab_test
|
523
515
|
# are valid (e.g. has alternatives, has a default, has metrics).
|
524
516
|
# If collecting, this method will also store this experiment into the db.
|
525
517
|
# In most cases, you call this method right after the experiment's been instantiated
|
526
518
|
# and declared.
|
527
519
|
def save
|
528
|
-
if @saved
|
520
|
+
if defined?(@saved)
|
529
521
|
Vanity.logger.warn("Experiment #{name} has already been saved")
|
530
522
|
return
|
531
523
|
end
|
532
524
|
@saved = true
|
533
|
-
true_false unless @alternatives
|
525
|
+
true_false unless defined?(@alternatives)
|
534
526
|
fail "Experiment #{name} needs at least two alternatives" unless @alternatives.size >= 2
|
535
527
|
if !@is_default_set
|
536
528
|
default(@alternatives.first)
|
@@ -542,10 +534,10 @@ module Vanity
|
|
542
534
|
@default = @alternatives.first
|
543
535
|
end
|
544
536
|
super
|
545
|
-
if @metrics.nil? || @metrics.empty?
|
537
|
+
if !defined?(@metrics) || @metrics.nil? || @metrics.empty?
|
546
538
|
Vanity.logger.warn("Please use metrics method to explicitly state which metric you are measuring against.")
|
547
|
-
|
548
|
-
@metrics = [
|
539
|
+
default_metric = @playground.metrics[id] ||= Vanity::Metric.new(@playground, name)
|
540
|
+
@metrics = [default_metric]
|
549
541
|
end
|
550
542
|
@metrics.each do |metric|
|
551
543
|
metric.hook(&method(:track!))
|
@@ -636,12 +628,12 @@ module Vanity
|
|
636
628
|
|
637
629
|
def filter_visitor?(request, identity)
|
638
630
|
@playground.request_filter.call(request) ||
|
639
|
-
(@request_filter_block && @request_filter_block.call(request, identity))
|
631
|
+
(defined?(@request_filter_block) && @request_filter_block && @request_filter_block.call(request, identity))
|
640
632
|
end
|
641
633
|
|
642
634
|
def call_on_assignment_if_available(identity, index)
|
643
635
|
# if we have an on_assignment block, call it on new assignments
|
644
|
-
if @on_assignment_block
|
636
|
+
if defined?(@on_assignment_block) && @on_assignment_block
|
645
637
|
assignment = alternatives[index]
|
646
638
|
if !connection.ab_seen @id, identity, assignment
|
647
639
|
@on_assignment_block.call(Vanity.context, identity, assignment, self)
|
@@ -651,7 +643,7 @@ module Vanity
|
|
651
643
|
|
652
644
|
def rebalance_if_necessary!
|
653
645
|
# if we are rebalancing probabilities, keep track of how long it has been since we last rebalanced
|
654
|
-
if @rebalance_frequency
|
646
|
+
if defined?(@rebalance_frequency) && @rebalance_frequency
|
655
647
|
@assignments_since_rebalancing += 1
|
656
648
|
if @assignments_since_rebalancing >= @rebalance_frequency
|
657
649
|
@assignments_since_rebalancing = 0
|
@@ -661,7 +653,7 @@ module Vanity
|
|
661
653
|
end
|
662
654
|
|
663
655
|
def has_alternative_weights?(args)
|
664
|
-
@alternatives.nil? && args.size == 1 && args[0].is_a?(Hash)
|
656
|
+
(!defined?(@alternatives) || @alternatives.nil?) && args.size == 1 && args[0].is_a?(Hash)
|
665
657
|
end
|
666
658
|
|
667
659
|
def build_alternatives_with_weights(args)
|
@@ -688,10 +680,10 @@ module Vanity
|
|
688
680
|
end
|
689
681
|
|
690
682
|
begin
|
691
|
-
|
683
|
+
avg = 50.0
|
692
684
|
# Returns array of [z-score, percentage]
|
693
685
|
norm_dist = []
|
694
|
-
(0.0..3.1).step(0.01) { |x| norm_dist << [x,
|
686
|
+
(0.0..3.1).step(0.01) { |x| norm_dist << [x, avg += 1 / Math.sqrt(2 * Math::PI) * Math::E ** (-x ** 2 / 2)] }
|
695
687
|
# We're really only interested in 90%, 95%, 99% and 99.9%.
|
696
688
|
Z_TO_PROBABILITY = [90, 95, 99, 99.9].map { |pct| [norm_dist.find { |x,a| a >= pct }.first, pct] }.reverse
|
697
689
|
end
|
@@ -25,21 +25,21 @@ module Vanity
|
|
25
25
|
|
26
26
|
# Number of participants who viewed this alternative.
|
27
27
|
def participants
|
28
|
-
load_counts unless @participants
|
28
|
+
load_counts unless defined?(@participants)
|
29
29
|
@participants
|
30
30
|
end
|
31
31
|
|
32
32
|
# Number of participants who converted on this alternative (a
|
33
33
|
# participant is counted only once).
|
34
34
|
def converted
|
35
|
-
load_counts unless @converted
|
35
|
+
load_counts unless defined?(@converted)
|
36
36
|
@converted
|
37
37
|
end
|
38
38
|
|
39
39
|
# Number of conversions for this alternative (same participant may be
|
40
40
|
# counted more than once).
|
41
41
|
def conversions
|
42
|
-
load_counts unless @conversions
|
42
|
+
load_counts unless defined?(@conversions)
|
43
43
|
@conversions
|
44
44
|
end
|
45
45
|
|
@@ -59,9 +59,6 @@ module Vanity
|
|
59
59
|
@created_at ||= connection.get_experiment_created_at(@id)
|
60
60
|
end
|
61
61
|
|
62
|
-
# Time stamp when experiment was completed.
|
63
|
-
attr_reader :completed_at
|
64
|
-
|
65
62
|
# Returns the type of this experiment as a symbol (e.g. :ab_test).
|
66
63
|
def type
|
67
64
|
self.class.type
|
@@ -109,7 +106,7 @@ module Vanity
|
|
109
106
|
# puts "Just defined: " + experiment(:simple).description
|
110
107
|
def description(text = nil)
|
111
108
|
@description = text if text
|
112
|
-
@description
|
109
|
+
@description if defined?(@description)
|
113
110
|
end
|
114
111
|
|
115
112
|
|
@@ -121,7 +118,7 @@ module Vanity
|
|
121
118
|
# end
|
122
119
|
def complete_if(&block)
|
123
120
|
raise ArgumentError, "Missing block" unless block
|
124
|
-
raise "complete_if already called on this experiment" if @complete_block
|
121
|
+
raise "complete_if already called on this experiment" if defined?(@complete_block)
|
125
122
|
@complete_block = block
|
126
123
|
end
|
127
124
|
|
@@ -188,7 +185,7 @@ module Vanity
|
|
188
185
|
# Derived classes call this after state changes that may lead to
|
189
186
|
# experiment completing.
|
190
187
|
def check_completion!
|
191
|
-
if @complete_block
|
188
|
+
if defined?(@complete_block) && @complete_block
|
192
189
|
begin
|
193
190
|
complete! if @complete_block.call
|
194
191
|
rescue => e
|
@@ -17,7 +17,7 @@ module Vanity
|
|
17
17
|
fail "Experiment #{@experiment_id} already defined in playground" if playground.experiments[@experiment_id]
|
18
18
|
klass = Experiment.const_get(type.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase })
|
19
19
|
experiment = klass.new(playground, @experiment_id, name, options)
|
20
|
-
experiment.instance_eval
|
20
|
+
experiment.instance_eval(&block)
|
21
21
|
experiment.save
|
22
22
|
playground.experiments[@experiment_id] = experiment
|
23
23
|
end
|
@@ -41,12 +41,6 @@ module Vanity
|
|
41
41
|
# use_vanity { |controller| controller.params[:project_id] }
|
42
42
|
# end
|
43
43
|
def use_vanity(method_name = nil, &block)
|
44
|
-
define_method :vanity_store_experiment_for_js do |name, alternative|
|
45
|
-
@_vanity_experiments ||= {}
|
46
|
-
@_vanity_experiments[name] ||= alternative
|
47
|
-
@_vanity_experiments[name].value
|
48
|
-
end
|
49
|
-
|
50
44
|
define_method(:vanity_identity_block) { block }
|
51
45
|
define_method(:vanity_identity_method) { method_name }
|
52
46
|
|
@@ -61,7 +55,7 @@ module Vanity
|
|
61
55
|
module Identity
|
62
56
|
def vanity_identity # :nodoc:
|
63
57
|
return vanity_identity_block.call(self) if vanity_identity_block
|
64
|
-
return @vanity_identity if @vanity_identity
|
58
|
+
return @vanity_identity if defined?(@vanity_identity) && @vanity_identity
|
65
59
|
|
66
60
|
# With user sign in, it's possible to visit not-logged in, get
|
67
61
|
# cookied and shown alternative A, then sign in and based on
|
@@ -162,20 +156,22 @@ module Vanity
|
|
162
156
|
# :null_abc experiment is chosen and the user redirected to
|
163
157
|
# http://example.com/.
|
164
158
|
def vanity_query_parameter_filter
|
165
|
-
|
166
|
-
|
159
|
+
query_params = request.query_parameters
|
160
|
+
if request.get? && query_params[:_vanity]
|
161
|
+
hashes = Array(query_params.delete(:_vanity))
|
167
162
|
Vanity.playground.experiments.each do |id, experiment|
|
168
163
|
if experiment.respond_to?(:alternatives)
|
169
164
|
experiment.alternatives.each do |alt|
|
170
|
-
if
|
171
|
-
experiment.chooses
|
165
|
+
if hashes.delete(experiment.fingerprint(alt))
|
166
|
+
experiment.chooses(alt.value)
|
172
167
|
break
|
173
168
|
end
|
174
169
|
end
|
175
170
|
end
|
176
171
|
break if hashes.empty?
|
177
172
|
end
|
178
|
-
|
173
|
+
path_parts = [url_for, query_params.to_query]
|
174
|
+
redirect_to(path_parts.join('?'))
|
179
175
|
end
|
180
176
|
end
|
181
177
|
|
@@ -224,7 +220,8 @@ module Vanity
|
|
224
220
|
# <%= count %> features to choose from!
|
225
221
|
# <% end %>
|
226
222
|
def ab_test(name, &block)
|
227
|
-
|
223
|
+
current_request = respond_to?(:request) ? self.request : nil
|
224
|
+
value = Vanity.ab_test(name, current_request)
|
228
225
|
|
229
226
|
if block
|
230
227
|
content = capture(value, &block)
|
@@ -251,7 +248,7 @@ module Vanity
|
|
251
248
|
end
|
252
249
|
|
253
250
|
def vanity_js
|
254
|
-
return if
|
251
|
+
return if Vanity.context.vanity_active_experiments.nil? || Vanity.context.vanity_active_experiments.empty?
|
255
252
|
javascript_tag do
|
256
253
|
render :file => Vanity.template("_vanity"), :formats => [:js]
|
257
254
|
end
|
@@ -291,25 +288,14 @@ module Vanity
|
|
291
288
|
# </script>
|
292
289
|
# <% end %>
|
293
290
|
def vanity_experiments
|
294
|
-
|
295
|
-
experiments = {}
|
291
|
+
edit_safe_experiments = {}
|
296
292
|
|
297
|
-
|
298
|
-
|
293
|
+
Vanity.context.vanity_active_experiments.each do |name, alternative|
|
294
|
+
edit_safe_experiments[name] = alternative.clone
|
299
295
|
end
|
300
296
|
|
301
|
-
|
302
|
-
end
|
303
|
-
|
304
|
-
protected
|
305
|
-
|
306
|
-
def setup_experiment(name)
|
307
|
-
@_vanity_experiments ||= {}
|
308
|
-
request = respond_to?(:request) ? self.request : nil
|
309
|
-
@_vanity_experiments[name] ||= Vanity.playground.experiment(name.to_sym).choose(request)
|
310
|
-
@_vanity_experiments[name].value
|
297
|
+
edit_safe_experiments
|
311
298
|
end
|
312
|
-
|
313
299
|
end
|
314
300
|
|
315
301
|
|
data/lib/vanity/helpers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Vanity
|
2
|
-
# Helper methods available on
|
2
|
+
# Helper methods available on the Vanity module.
|
3
3
|
#
|
4
4
|
# @example From ERB template
|
5
5
|
# <%= ab_test(:greeting) %> <%= current_user.name %>
|
@@ -17,7 +17,6 @@ module Vanity
|
|
17
17
|
# end
|
18
18
|
# end
|
19
19
|
module Helpers
|
20
|
-
|
21
20
|
# This method returns one of the alternative values in the named A/B test.
|
22
21
|
#
|
23
22
|
# @example A/B two alternatives for a page
|
@@ -33,21 +32,15 @@ module Vanity
|
|
33
32
|
# render action: Vanity.ab_test(:new_page)
|
34
33
|
# end
|
35
34
|
# @since 1.2.0
|
36
|
-
def ab_test(name, &block)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
value = Vanity.playground.experiment(name).choose(request).value
|
44
|
-
end
|
35
|
+
def ab_test(name, request=nil, &block)
|
36
|
+
request ||= Vanity.context.respond_to?(:request) ? Vanity.context.request : nil
|
37
|
+
|
38
|
+
alternative = Vanity.playground.experiment(name).choose(request)
|
39
|
+
Vanity.context.vanity_add_to_active_experiments(name, alternative)
|
40
|
+
|
41
|
+
Vanity.logger.warn("Deprecated: This method used to accept a block, however, calling it with a block would result in an exception. The block will be removed from the signature in an upcoming version.") if block
|
45
42
|
|
46
|
-
|
47
|
-
content = capture(value, &block)
|
48
|
-
else
|
49
|
-
value
|
50
|
-
end
|
43
|
+
alternative.value
|
51
44
|
end
|
52
45
|
|
53
46
|
# Tracks an action associated with a metric. Useful for calling from a
|
@@ -64,7 +57,7 @@ module Vanity
|
|
64
57
|
# of options passed (eventually) to AbTest#track!.
|
65
58
|
# @since 1.2.0
|
66
59
|
def track!(name, count_or_options = 1)
|
67
|
-
Vanity.playground.track!
|
60
|
+
Vanity.playground.track!(name, count_or_options)
|
68
61
|
end
|
69
62
|
end
|
70
63
|
end
|
data/lib/vanity/metric/base.rb
CHANGED
@@ -27,7 +27,7 @@ module Vanity
|
|
27
27
|
def metric(name, &block)
|
28
28
|
fail "Metric #{@metric_id} already defined in playground" if playground.metrics[@metric_id]
|
29
29
|
metric = Metric.new(playground, name.to_s, @metric_id)
|
30
|
-
metric.instance_eval
|
30
|
+
metric.instance_eval(&block)
|
31
31
|
playground.metrics[@metric_id] = metric
|
32
32
|
end
|
33
33
|
|
@@ -191,7 +191,7 @@ module Vanity
|
|
191
191
|
alias :to_s :name
|
192
192
|
|
193
193
|
# Human readable description. Use two newlines to break paragraphs.
|
194
|
-
|
194
|
+
attr_writer :description
|
195
195
|
|
196
196
|
# Sets or returns description. For example
|
197
197
|
# metric "Yawns/sec" do
|
@@ -201,7 +201,7 @@ module Vanity
|
|
201
201
|
# puts "Just defined: " + metric(:boring).description
|
202
202
|
def description(text = nil)
|
203
203
|
@description = text if text
|
204
|
-
@description
|
204
|
+
@description if defined?(@description)
|
205
205
|
end
|
206
206
|
|
207
207
|
# Given two arguments, a start date and an end date (inclusive), returns an
|
data/lib/vanity/templates.rb
CHANGED
@@ -23,7 +23,7 @@ module Vanity
|
|
23
23
|
# dotfiles in the directory.
|
24
24
|
def custom_template_path_valid?
|
25
25
|
Vanity.playground.custom_templates_path &&
|
26
|
-
File.
|
26
|
+
File.exist?(Vanity.playground.custom_templates_path) &&
|
27
27
|
!Dir[File.join(Vanity.playground.custom_templates_path, '*')].empty?
|
28
28
|
end
|
29
29
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
var httpRequest;
|
2
|
-
var params = "v=<%=
|
2
|
+
var params = "v=<%= Vanity.context.vanity_active_experiments.map{|name, alternative| "#{name}=#{alternative.id}" }.join(',') %>&authenticity_token=<%= CGI.escape(form_authenticity_token) %>";
|
3
3
|
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
|
4
4
|
httpRequest = new XMLHttpRequest();
|
5
5
|
} else if (window.ActiveXObject) { // IE
|
data/lib/vanity/vanity.rb
CHANGED
@@ -9,7 +9,7 @@ module Vanity
|
|
9
9
|
# @see Vanity::Configuration
|
10
10
|
# @since 2.0.0
|
11
11
|
def self.configuration(set_if_needed=true)
|
12
|
-
if @configuration
|
12
|
+
if defined?(@configuration) && @configuration
|
13
13
|
@configuration
|
14
14
|
elsif set_if_needed
|
15
15
|
configure!
|
@@ -53,6 +53,21 @@ module Vanity
|
|
53
53
|
# set by the set_vanity_context before filter (via Vanity::Rails#use_vanity).
|
54
54
|
def self.context=(context)
|
55
55
|
Thread.current[:vanity_context] = context
|
56
|
+
|
57
|
+
if context
|
58
|
+
context.class.send(:define_method, :vanity_add_to_active_experiments) do |name, alternative|
|
59
|
+
@_vanity_experiments ||= {}
|
60
|
+
@_vanity_experiments[name] ||= alternative
|
61
|
+
@_vanity_experiments[name].value
|
62
|
+
end
|
63
|
+
context.class.send(:alias_method, :vanity_store_experiment_for_js, :vanity_add_to_active_experiments)
|
64
|
+
|
65
|
+
context.class.send(:define_method, :vanity_active_experiments) do
|
66
|
+
@_vanity_experiments ||= {}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context
|
56
71
|
end
|
57
72
|
|
58
73
|
#
|
@@ -63,7 +78,7 @@ module Vanity
|
|
63
78
|
#
|
64
79
|
# @since 2.0.0
|
65
80
|
def self.connection(connect_if_needed=true)
|
66
|
-
if @connection
|
81
|
+
if defined?(@connection) && @connection
|
67
82
|
@connection
|
68
83
|
elsif connect_if_needed
|
69
84
|
connect!
|
data/lib/vanity/version.rb
CHANGED
@@ -8,7 +8,8 @@ class UseVanityController < ActionController::Base
|
|
8
8
|
attr_accessor :current_user
|
9
9
|
|
10
10
|
def index
|
11
|
-
|
11
|
+
text = Vanity.ab_test(:pie_or_cake)
|
12
|
+
render :plain=>text, :text=>text
|
12
13
|
end
|
13
14
|
|
14
15
|
def js
|
@@ -16,6 +17,20 @@ class UseVanityController < ActionController::Base
|
|
16
17
|
render :inline => "<%= vanity_js -%>"
|
17
18
|
end
|
18
19
|
|
20
|
+
def view_helper_ab_test_js
|
21
|
+
render :inline => <<-EOS
|
22
|
+
<% ab_test(:pie_or_cake) %>
|
23
|
+
<%= vanity_js -%>
|
24
|
+
EOS
|
25
|
+
end
|
26
|
+
|
27
|
+
def global_ab_test_js
|
28
|
+
render :inline => <<-EOS
|
29
|
+
<% Vanity.ab_test(:pie_or_cake) %>
|
30
|
+
<%= vanity_js -%>
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
|
19
34
|
def model_js
|
20
35
|
TestModel.new.test_method
|
21
36
|
render :inline => "<%= vanity_js -%>"
|
data/test/experiment/ab_test.rb
CHANGED
@@ -5,7 +5,8 @@ class AbTestController < ActionController::Base
|
|
5
5
|
attr_accessor :current_user
|
6
6
|
|
7
7
|
def test_render
|
8
|
-
|
8
|
+
text = Vanity.ab_test(:simple)
|
9
|
+
render :plain=>text, :text=>text
|
9
10
|
end
|
10
11
|
|
11
12
|
def test_view
|
@@ -18,7 +19,7 @@ class AbTestController < ActionController::Base
|
|
18
19
|
|
19
20
|
def track
|
20
21
|
Vanity.track!(:coolness)
|
21
|
-
render :text=>""
|
22
|
+
render :plain=>"", :text=>""
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -604,7 +605,7 @@ class AbTestTest < ActionController::TestCase
|
|
604
605
|
end
|
605
606
|
class <<experiment(:foobar)
|
606
607
|
def times_called
|
607
|
-
@times_called
|
608
|
+
@times_called ||= 0
|
608
609
|
end
|
609
610
|
def rebalance!
|
610
611
|
@times_called = times_called + 1
|
@@ -801,6 +802,7 @@ class AbTestTest < ActionController::TestCase
|
|
801
802
|
def test_ab_test_chooses_in_render
|
802
803
|
new_ab_test :simple do
|
803
804
|
metrics :coolness
|
805
|
+
identify { rand }
|
804
806
|
default false
|
805
807
|
end
|
806
808
|
responses = Array.new(100) do
|
@@ -814,6 +816,7 @@ class AbTestTest < ActionController::TestCase
|
|
814
816
|
def test_ab_test_chooses_view_helper
|
815
817
|
new_ab_test :simple do
|
816
818
|
metrics :coolness
|
819
|
+
identify { rand }
|
817
820
|
default false
|
818
821
|
end
|
819
822
|
responses = Array.new(100) do
|
@@ -827,6 +830,7 @@ class AbTestTest < ActionController::TestCase
|
|
827
830
|
def test_ab_test_with_capture
|
828
831
|
new_ab_test :simple do
|
829
832
|
metrics :coolness
|
833
|
+
identify { rand }
|
830
834
|
default false
|
831
835
|
end
|
832
836
|
responses = Array.new(100) do
|
@@ -883,13 +887,13 @@ class AbTestTest < ActionController::TestCase
|
|
883
887
|
default :a
|
884
888
|
metrics :coolness
|
885
889
|
end
|
886
|
-
responses = Array.new(100)
|
890
|
+
responses = Array.new(100) do |i|
|
887
891
|
@controller = nil ; setup_controller_request_and_response
|
888
892
|
experiment(:simple).chooses(:b)
|
889
893
|
experiment(:simple).chooses(nil)
|
890
894
|
get :test_render
|
891
895
|
@response.body
|
892
|
-
|
896
|
+
end
|
893
897
|
assert responses.uniq.size == 3
|
894
898
|
end
|
895
899
|
|
@@ -34,6 +34,18 @@ class UseVanityControllerTest < ActionController::TestCase
|
|
34
34
|
assert_match /script.*v=pie_or_cake=.*script/m, @response.body
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_view_helper_ab_test_js_for_tests
|
38
|
+
Vanity.playground.use_js!
|
39
|
+
get :view_helper_ab_test_js
|
40
|
+
assert_match /script.*v=pie_or_cake=.*script/m, @response.body
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_global_ab_test_js_for_tests
|
44
|
+
Vanity.playground.use_js!
|
45
|
+
get :global_ab_test_js
|
46
|
+
assert_match /script.*v=pie_or_cake=.*script/m, @response.body
|
47
|
+
end
|
48
|
+
|
37
49
|
def test_render_model_js_for_tests
|
38
50
|
Vanity.playground.use_js!
|
39
51
|
get :model_js
|
data/test/test_helper.rb
CHANGED
@@ -31,7 +31,7 @@ require "webmock/minitest"
|
|
31
31
|
require 'vanity/frameworks/rails'
|
32
32
|
Vanity::Rails.load!
|
33
33
|
|
34
|
-
if $
|
34
|
+
if $DEBUG
|
35
35
|
$logger = Logger.new(STDOUT)
|
36
36
|
$logger.level = Logger::DEBUG
|
37
37
|
else
|
@@ -119,7 +119,7 @@ module VanityTestHelpers
|
|
119
119
|
enable = options.fetch(:enable, true)
|
120
120
|
id = name.to_s.downcase.gsub(/\W/, "_").to_sym
|
121
121
|
experiment = Vanity::Experiment::AbTest.new(Vanity.playground, id, name)
|
122
|
-
experiment.instance_eval
|
122
|
+
experiment.instance_eval(&block) if block
|
123
123
|
experiment.save
|
124
124
|
# new experiments start off as disabled, enable them for testing
|
125
125
|
experiment.enabled = true if enable
|
@@ -140,7 +140,12 @@ module VanityTestHelpers
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def dummy_request
|
143
|
-
|
143
|
+
# Rails 5 compatibility
|
144
|
+
if ActionDispatch::TestRequest.respond_to?(:create)
|
145
|
+
ActionDispatch::TestRequest.create()
|
146
|
+
else
|
147
|
+
ActionDispatch::TestRequest.new()
|
148
|
+
end
|
144
149
|
end
|
145
150
|
|
146
151
|
# Defining setup/tear down in a module and including it below doesn't
|
@@ -194,6 +199,11 @@ if defined?(ActionController::TestCase)
|
|
194
199
|
end
|
195
200
|
end
|
196
201
|
|
202
|
+
if defined?(ActionDispatch::IntegrationTest)
|
203
|
+
class ActionDispatch::IntegrationTest
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
197
207
|
if ENV["DB"] == "active_record"
|
198
208
|
ActiveRecord::Base.establish_connection
|
199
209
|
ActiveRecord::Base.logger = $logger
|
@@ -116,7 +116,7 @@ class RailsDashboardTest < ActionController::TestCase
|
|
116
116
|
def test_complete_forces_confirmation
|
117
117
|
xhr :post, :complete, :e => "food", :a => 0
|
118
118
|
assert_response :success
|
119
|
-
|
119
|
+
assert @response.body =~ /#{ CGI.unescape({ :confirmed => 0 }.to_query) }/
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_complete_with_confirmation_completes
|
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.2.
|
4
|
+
version: 2.2.6
|
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-
|
11
|
+
date: 2016-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -175,6 +175,8 @@ files:
|
|
175
175
|
- gemfiles/rails42.gemfile.lock
|
176
176
|
- gemfiles/rails42_protected_attributes.gemfile
|
177
177
|
- gemfiles/rails42_protected_attributes.gemfile.lock
|
178
|
+
- gemfiles/rails5.gemfile
|
179
|
+
- gemfiles/rails5.gemfile.lock
|
178
180
|
- lib/generators/templates/vanity_migration.rb
|
179
181
|
- lib/generators/vanity/views_generator.rb
|
180
182
|
- lib/generators/vanity_generator.rb
|
@@ -284,7 +286,7 @@ metadata: {}
|
|
284
286
|
post_install_message: To get started run vanity --help
|
285
287
|
rdoc_options:
|
286
288
|
- "--title"
|
287
|
-
- Vanity 2.2.
|
289
|
+
- Vanity 2.2.6
|
288
290
|
- "--main"
|
289
291
|
- README.md
|
290
292
|
- "--webcvs"
|