vanity 2.2.4 → 2.2.6
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|