vanity 2.0.0.beta9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d7da7caf628667cd793e5a3191fa8f0975a7ae0
4
+ data.tar.gz: 9a538d9f392b717675079c8ea35cfaf8b8457733
5
+ SHA512:
6
+ metadata.gz: b8a5faf62c21f4562b5b4e17c78e340b53547e90d0a9b657c3fd8bc44b724fa813dc3a1e681e6fdf3617c9d70141819608e05f9c1221dc8ac137210d4d46dae5
7
+ data.tar.gz: c23d96c189bae198ba68c60f5ff7ba93cd0aef614b40b746a217979be6f6ebf66966217693a6c753e0e560921461711956b89712b7d5fc002037b4ac04a21ebb
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ == 2.0.0 (2015-12-14)
2
+
3
+ Extract configuration from Vanity::Playground to Vanity::Configuration (@phillbaker)
4
+ Remove `track!` and `ab_test` from the global scope, they're now available on the `Vanity` module. (@phillbaker)
5
+ Reduce test frameworks to just minitest (@phillbaker)
6
+ Replace deprecated ActiveRecord finders (@bogdan-dumitru, @leematos, @aaronjensen)
7
+ Add date to vanity_metric_values index (@aaronjensen)
8
+ Fix insecure wildcard route (@modosc)
9
+ Introduce Ruby 2.2 support. (@sebjacobs)
10
+ Added support for testing against jruby. (@Matt343)
11
+ Adding internationalization to reports (@teonimesic)
12
+ Allow Rails applications to override default views (@rsslldnphy)
13
+ Add support to reset experiments (@davidguthu)
14
+
1
15
  == 1.9.0 (2014-04-20)
2
16
 
3
17
  Include db:reset in blacklist for autoconnect. (@phillbaker)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- vanity (2.0.0.beta9)
4
+ vanity (2.0.0)
5
5
  i18n
6
6
 
7
7
  GEM
@@ -34,10 +34,9 @@ GEM
34
34
  coffee-script-source (1.9.1)
35
35
  colorator (0.1)
36
36
  crack (0.3.1)
37
- directory_watcher (1.4.1)
38
37
  execjs (2.5.2)
39
- fast-stemmer (1.0.2)
40
38
  fakefs (0.6.7)
39
+ fast-stemmer (1.0.2)
41
40
  ffi (1.9.8)
42
41
  garb (0.9.1)
43
42
  activesupport (>= 2.2.0)
data/README.rdoc CHANGED
@@ -46,8 +46,8 @@ A sample <code>config/vanity.yml</code> might look like:
46
46
  If you want to use your test environment with RSpec you will need to add an adapter to test:
47
47
 
48
48
  test:
49
- adapter: redis
50
- collecting: false
49
+ adapter: redis
50
+ collecting: false
51
51
 
52
52
  ===== MongoDB Setup
53
53
 
@@ -123,13 +123,13 @@ If the experiment uses a metric as above ("signups"), there needs to be a corres
123
123
 
124
124
  === <b>Step 4:</b> Measure conversion
125
125
 
126
- Conversions are created via the <code>track!</code> method. For example:
126
+ Conversions are created via the <code>Vanity.track!</code> method. For example:
127
127
 
128
128
  class SignupController < ApplicationController
129
129
  def signup
130
130
  @account = Account.new(params[:account])
131
131
  if @account.save
132
- track! :signups
132
+ Vanity.track!(:signups)
133
133
  redirect_to @acccount
134
134
  else
135
135
  render action: :offer
@@ -166,11 +166,17 @@ The controller should look like:
166
166
 
167
167
  If robots or spiders make up a significant portion of your sites traffic they can affect your conversion rate. Vanity can optionally add participants to the experiments using asynchronous javascript callbacks, which will keep many robots out. For those robots that do execute Javascript and are well-behaved (like Googlebot), Vanity filters out requests based on their user-agent string.
168
168
 
169
- To set this up simply do the following:
169
+ In Rails, add the following to <code>application.rb</code>:
170
+
171
+ Vanity.configure do |config|
172
+ config.use_js = true
170
173
 
171
- * Add <code>Vanity.playground.use_js!</code>
172
- * Set <code>Vanity.playground.add_participant_path = '/path/to/vanity/action'</code>, this should point to the add_participant path that is added with Vanity::Rails::Dashboard, make sure that this action is accessible by all users (ie does not require authentication).
173
- * Add <code><%= vanity_js %></code> to any page that XX an ab_test. <code>vanity_js</code> needs to be included after your call to ab_test so that it knows which version of the experiment the participant is a member of. The helper will render nothing if the there are no ab_tests running on the current page, so adding <code>vanity_js</code> to the bottom of your layouts is a good option. Keep in mind that if you call <code>use_js!</code> and don't include <code>vanity_js</code> in your view no participants will be recorded.
174
+ # Optionally configure the add_participant route that is added with Vanity::Rails::Dashboard,
175
+ # make sure that this action does not require authentication
176
+ # config.add_participant_route = '/vanity/add_participant'
177
+ end
178
+
179
+ Then add <code><%= vanity_js %></code> to any page that calls an A/B test <b>after calling <code>ab_test</code></b>. <code>vanity_js</code> needs to be included after your call to ab_test so that it knows which version of the experiment the participant is a member of. The helper will render nothing if the there are no ab_tests running on the current page, so adding <code>vanity_js</code> to the bottom of your layouts is a good option. Keep in mind that if you set <code>use_js</code> and don't include <code>vanity_js</code> in your view no participants will be recorded.
174
180
 
175
181
  == Compatibility
176
182
 
@@ -189,8 +195,6 @@ Here's what's tested and known to work:
189
195
  Persistence: Redis, Mongo, ActiveRecord
190
196
  Rails: 3.2, 4.x
191
197
 
192
- If you receive 'a warning: circular argument reference - score' this was fixed in [2.0.7 beta](https://github.com/assaf/vanity/commit/1b5bf18636caa5eae279e2aef2e24c923e63b141)
193
-
194
198
  == Testing
195
199
 
196
200
  For view tests/specs or integration testing, it's handy to set the outcome of an experiment. This may be done using the <code>chooses</code> method. For example:
@@ -59,7 +59,7 @@ Remember that we're measuring signups, so we already have this in the code:
59
59
  class SignupController < ApplicationController
60
60
  def signup
61
61
  Account.create(params[:account])
62
- track! :signup
62
+ Vanity.track!(:signup)
63
63
  end
64
64
  end
65
65
  </pre>
@@ -73,7 +73,7 @@ Vanity splits the audience randomly -- using "cookies and other mechanisms":iden
73
73
 
74
74
  !images/clear_winner.png!
75
75
 
76
- Vanity will show the conversion rate for each alternative, and how that conversion compares to the worst performing alternative. In the example above, option A has 80.6% conversion rate, 11% more than option B's 72.6% conversion rate (72.6 * 111% ~ 80.6%).
76
+ Vanity will show the conversion rate for each alternative, and how that conversion compares to the worst performing alternative. In the example above, option A has 80.6% conversion rate, 11% more than option B's 72.6% conversion rate (72.6 * 111% ~ 80.6%).
77
77
 
78
78
  (These large numbers are easily explained by the fact that this report was generated from made up data)
79
79
 
@@ -113,7 +113,7 @@ end
113
113
  The @ab_test@ method returns the value of one of the chosen alternatives, so in your views you can write:
114
114
 
115
115
  <pre>
116
- <h2>Get started for only $<%= ab_test :price_options %> a month!</h2>
116
+ <h2>Get started for only $<%= ab_test(:price_options) %> a month!</h2>
117
117
  </pre>
118
118
 
119
119
  !images/price_options.png!
@@ -122,17 +122,17 @@ If you don't given any values, Vanity will run your experiment with the values f
122
122
 
123
123
  <pre>
124
124
  def index
125
- # alternatives are names of templates
126
- render template: ab_test(:new_page)
125
+ # alternatives are names of templates
126
+ render template: Vanity.ab_test(:new_page)
127
127
  end
128
128
  </pre>
129
-
129
+
130
130
  <pre>
131
131
  <%= ab_test(:greeting) %> <%= current_user.name %>
132
132
  </pre>
133
-
133
+
134
134
  <pre>
135
- <% ab_test :features do |count| %>
135
+ <% ab_test(:features) do |count| %>
136
136
  <%= count %> features to choose from!
137
137
  <% end %>
138
138
  </pre>
@@ -156,7 +156,7 @@ Here's another example using Webrat:
156
156
 
157
157
  <pre>
158
158
  def test_price_option
159
- [19, 25, 29].each do |price|
159
+ [19, 25, 29].each do |price|
160
160
  experiment(:price_options).chooses(price)
161
161
  visit root_path
162
162
  assert_contain "Get started for only $#{price} a month!"
@@ -26,18 +26,46 @@ The available database adapters are:
26
26
  * +mongodb+ -- Available options are host, port, database (defaults to "vanity"), username and password.
27
27
  * +active_record+ -- Uses existing ActiveRecord configuration, by you can over-ride by supplying different options. To pick different underlying adapter, set +active_record_adapter+.
28
28
 
29
+ h4. Configuration Options
30
+
29
31
  Available configuration options are:
30
32
 
31
- |_. name |_. Is all about ... |_. Default |
32
- | load_path | Directory containing experiment files | experiments |
33
- | logger | This should be obvious | default/Rails |
34
- | collecting | False if you won't want data collected | true |
33
+ |_. name |_. Is all about ... |_. Default |
34
+ | add_participant_route | URL to use to add participants via JS | /vanity/add_participant |
35
+ | collecting | False if you won't want data collected| true |
36
+ | config_file | File name to use to configure vanity | vanity.yml |
37
+ | config_path | Path to the config_file | ./config/ |
38
+ | environment | What environment use for configuration| development |
39
+ | experiments_path | Directory containing experiment files | ./experiments |
40
+ | failover_on_datastore_error| Whether to pass errors to on_datastore_error | false |
41
+ | locales_path | Path to locales for translations | in the gem |
42
+ | logger | This should be obvious | default/Rails |
43
+ | on_datastore_error | A proc that handles datastore errors | logs to logger |
44
+ | request_filter | A proc that returns whether to to ignore the request for the add JS participant route | Ignore requests with a HTTP_USER_AGENT that contain a URL |
45
+ | templates_path | Path to templates for Vanity admin | the templates in the gem |
46
+ | use_js | Whether to use JS to add particpants, useful to ignore bots | false |
35
47
 
36
48
  When "running under Rails":rails.html, Vanity defaults to using the Rails logger, locates the load_path relative to Rails root, uses the @config/vanity.yml@ configuration file (if present) and turns collection on only in production mode.
37
49
 
38
- If you run a different setup, use the playground object to configure Vanity. For example:
50
+ Use the playground object to configure Vanity. For example:
39
51
 
40
52
  <pre>
41
- Vanity.playground.load_path = "exp"
42
- Vanity.playground.establish_connection "redis://db.example.com"
53
+ Vanity.configure do |config|
54
+ config.use_js = true
55
+ config.experiments_path = 'config/ab_tests'
56
+ config.add_participant_route = '/vanity/participant/new'
57
+ # ...
58
+ end
43
59
  </pre>
60
+
61
+
62
+ h4. Using metrics from Google Analytics
63
+
64
+ If you want to use Vanity with metrics from Google Analytics, you must require the @garb@ gem, and login for a new session. You'll want to do that for production, not for development if you like developing offline. For example in Rails, in the config/:
65
+
66
+ <pre>
67
+ config.after_initialize do
68
+ require "garb"
69
+ Garb::Session.login('..ga email..', '..ga pwd..', account_type: "GOOGLE")
70
+ end
71
+ </pre>
@@ -47,47 +47,9 @@ $ rake DB=mysql
47
47
  </pre>
48
48
 
49
49
 
50
- Before making a release, we run the full test suite against multiple Ruby VMs
51
- and using multiple database adapters. Doing this on your own is easier than it
52
- sounds:
50
+ Before making a release, we run the full test suite against multiple Ruby VMs and using multiple database adapters. Doing this on your own is easier than it sounds:
53
51
 
54
52
  # "Fork the project":http://github.com/assaf/vanity
55
53
  # Go to "Travis CI":http://travis-ci.org/, setup a new account if you don't already have one
56
54
  # "In your profile page":http://travis-ci.org/profile, tell Travis to build your fork
57
55
  # @git push@ your changes into your fork and "watch Travis":http://travis-ci.org/ run the tests
58
-
59
-
60
- To package Vanity as a gem and install on your machine:
61
-
62
- <pre>
63
- $ rake install
64
- </pre>
65
-
66
-
67
- h3(#doc). Documentation
68
-
69
- Documentation is written in "Textile":http://redcloth.org/textile/writing-paragraph-text/, and converted to HTML using "Jekyll":http://jekyllrb.com/.
70
-
71
- API reference is "RDoc":http://rdoc.sourceforge.net/doc/index.html, converted to HTML using "Yardoc":http://yardoc.org/.
72
-
73
- To build and view documentation:
74
-
75
- <pre>
76
- $ rake docs
77
- $ open html/index.html
78
- </pre>
79
-
80
- To clean up after yourself:
81
-
82
- <pre>
83
- $ rake clobber
84
- </pre>
85
-
86
-
87
- h3(#open). Open Issues
88
-
89
- <notextile>
90
- <table id="issues">
91
- <tbody></tbody>
92
- </table>
93
- </notextile>
@@ -24,8 +24,8 @@ Next proposed change would allow the metric to define multiple columns. Those ca
24
24
  metric :purchase do
25
25
  columns :count, :total
26
26
  end
27
- metric(:purchase).track! p.items.length. p.total
28
- metric(:purchase).track! :total=>p.total, :count=>p.items.length
27
+ metric(:purchase).track!(p.items.length. p.total)
28
+ metric(:purchase).track!(:total=>p.total, :count=>p.items.length)
29
29
  </pre>
30
30
 
31
31
  The metric's @values@ method will have to be changed to return an array of arrays, or new method introduced to keep the API backward compatible. And, of course, UI modified to display multiple series in a single graph.
data/doc/metrics.textile CHANGED
@@ -43,7 +43,7 @@ class AccountsController < ApplicationController
43
43
  def create
44
44
  @person = Person.new(params[:person])
45
45
  if @person.save
46
- track! :signup # track successful sign up
46
+ Vanity.track!(:signup) # track successful sign up
47
47
  UserSession.create person
48
48
  redirect_to root_url
49
49
  else
@@ -60,7 +60,7 @@ You can call @track!@ with a value to track. This example tracks how many items
60
60
 
61
61
  <pre>
62
62
  def checkout
63
- track! :items, @cart.items.count
63
+ Vanity.track!(:items, @cart.items.count)
64
64
  . . .
65
65
  end
66
66
  </pre>
@@ -144,8 +144,8 @@ Login to Google Analytics using either username and password, or OAuth authentic
144
144
  Rails::Initializer.run do |config|
145
145
  gems.config "vanity"
146
146
  gems.config "garb"
147
-
148
- . . .
147
+
148
+ . . .
149
149
  config.after_initialize do
150
150
  require "garb"
151
151
  ga = YAML.load_file(Rails.root + "config/ga.yml")
data/doc/rails.textile CHANGED
@@ -35,31 +35,6 @@ end
35
35
  This example assumes you have a @current_user@ controller method which will return a consistent value for each user.
36
36
  There are other ways to identify people as well, you can read more about the options in Managing Identity.
37
37
 
38
- h4. Configuring datastore
39
-
40
- If you have a @config/vanity.yml@ file, Vanity will read the configuration for the current environment. For example:
41
-
42
- <pre>
43
- staging:
44
- adapter: redis
45
- host: staging.internal
46
- production:
47
- adapter: mongo
48
- host: live.internal
49
- database: vanity
50
- </pre>
51
-
52
- h4. Using metrics from Google Analytics
53
-
54
- If you want to use Vanity with metrics from Google Analytics, you must also tell Rails to include the @garb@ gem, and login for a new session. You'll want to do that for production, not for development if you like developing offline:
55
-
56
- <pre>
57
- config.after_initialize do
58
- require "garb"
59
- Garb::Session.login('..ga email..', '..ga pwd..', account_type: "GOOGLE")
60
- end
61
- </pre>
62
-
63
38
  h4. Enabling/disable collection
64
39
 
65
40
  When collection is off, Vanity doesn't connect to the database server, so there's no need to set a database configuration for these environments.
@@ -75,7 +50,9 @@ rails g vanity:views
75
50
  You can then edit them to your heart's content. If you need to use an alternative location for your custom templates, set the configuration variable @custom_templates_path@ on @Vanity.playground@ like this:
76
51
 
77
52
  <pre>
78
- Vanity.playground.custom_templates_path = 'views/vanity'
53
+ Vanity.configure do |config|
54
+ config.templates_path = 'views/vanity'
55
+ end
79
56
  </pre>
80
57
 
81
58
  h3(#fork). Unicorn and Forking Servers
@@ -91,4 +68,5 @@ after_fork do |server, worker|
91
68
  end
92
69
  </pre>
93
70
 
94
- You'll run into this issue with other forking servers. Vanity can detect when it runs under Passenger and automatically reconnect each forked process.
71
+ You'll run into this issue with other forking servers like Passenger as well.
72
+
data/doc/site.js CHANGED
@@ -1,21 +1,4 @@
1
1
  $(function() {
2
- var issuesTable = $("table#issues");
3
- if (issuesTable.size() > 0) {
4
- $.getJSON("http://github.com/api/v2/json/issues/list/assaf/vanity/open?callback=?", function(response) {
5
- $.each(response.issues, function(i, issue) {
6
- issuesTable.append(
7
- $("<tr>").append(
8
- $("<td>").append(
9
- $("<a>").text(issue.title).attr("href", "http://github.com/assaf/vanity/issues#issue/" + issue.number)
10
- ).append(
11
- $("<span class='votes'>").text(issue.votes == 0 ? "no votes" : issue.votes == 1 ? "1 vote" : issue.votes + " votes")
12
- )
13
- )
14
- );
15
- });
16
- });
17
- }
18
-
19
2
  var statsTable = $("#sidebar ul#stats");
20
3
  if (statsTable.size() > 0) {
21
4
  $.getJSON("http://github.com/api/v2/json/repos/show/assaf/vanity?callback=?", function(response) {
@@ -8,11 +8,11 @@ gem "redis-namespace", ">= 1.1.0"
8
8
  gem "mongo"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats"
11
- gem "garb", "< 0.9.2", :require=>false
11
+ gem "garb", "< 0.9.2", :require => false
12
12
  gem "timecop", :require => false
13
13
  gem "webmock", :require => false
14
+ gem "fakefs", :require => "fakefs/safe"
14
15
  gem "mocha", "~> 1.0", :require => false
15
- gem "fakefs", :require=>"fakefs/safe"
16
16
  gem "minitest", "~>4.2.0"
17
17
  gem "rails", "3.2.22"
18
18
  gem "minitest_tu_shim", "~> 1.3.3", :platforms => :mri_22
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ..
9
9
  specs:
10
- vanity (2.0.0.beta9)
10
+ vanity (2.0.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -8,11 +8,11 @@ gem "redis-namespace", ">= 1.1.0"
8
8
  gem "mongo"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats"
11
- gem "garb", "< 0.9.2", :require=>false
11
+ gem "garb", "< 0.9.2", :require => false
12
12
  gem "timecop", :require => false
13
13
  gem "webmock", :require => false
14
+ gem "fakefs", :require => "fakefs/safe"
14
15
  gem "mocha", "~> 1.0", :require => false
15
- gem "fakefs", :require=>"fakefs/safe"
16
16
  gem "rails", "4.0.13"
17
17
  gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
18
18
  gem "passenger", "~>3.0"
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ..
9
9
  specs:
10
- vanity (2.0.0.beta9)
10
+ vanity (2.0.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -61,8 +61,8 @@ GEM
61
61
  daemon_controller (1.1.7)
62
62
  directory_watcher (1.4.1)
63
63
  erubis (2.7.0)
64
- fast-stemmer (1.0.2)
65
64
  fakefs (0.6.7)
65
+ fast-stemmer (1.0.2)
66
66
  garb (0.9.1)
67
67
  activesupport (>= 2.2.0)
68
68
  crack (>= 0.1.6)
@@ -8,11 +8,11 @@ gem "redis-namespace", ">= 1.1.0"
8
8
  gem "mongo"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats"
11
- gem "garb", "< 0.9.2", :require=>false
11
+ gem "garb", "< 0.9.2", :require => false
12
12
  gem "timecop", :require => false
13
13
  gem "webmock", :require => false
14
+ gem "fakefs", :require => "fakefs/safe"
14
15
  gem "mocha", "~> 1.0", :require => false
15
- gem "fakefs", :require=>"fakefs/safe"
16
16
  gem "rails", "4.1.9"
17
17
  gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
18
18
  gem "passenger", "~>3.0"
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: .././
9
9
  specs:
10
- vanity (2.0.0.beta9)
10
+ vanity (2.0.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -8,11 +8,11 @@ gem "redis-namespace", ">= 1.1.0"
8
8
  gem "mongo"
9
9
  gem "integration", "<= 0.1.0"
10
10
  gem "rubystats"
11
- gem "garb", "< 0.9.2", :require=>false
11
+ gem "garb", "< 0.9.2", :require => false
12
12
  gem "timecop", :require => false
13
13
  gem "webmock", :require => false
14
+ gem "fakefs", :require => "fakefs/safe"
14
15
  gem "mocha", "~> 1.0", :require => false
15
- gem "fakefs", :require=>"fakefs/safe"
16
16
  gem "rails", "4.2.0"
17
17
  gem "fastthread", :git => "git://github.com/zoltankiss/fastthread.git", :platforms => :mri_20
18
18
  gem "passenger", "~>3.0"
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: ..
9
9
  specs:
10
- vanity (2.0.0.beta9)
10
+ vanity (2.0.0)
11
11
  i18n
12
12
 
13
13
  GEM
@@ -160,7 +160,7 @@ module Vanity
160
160
  # alternative.
161
161
  def vanity_track_filter
162
162
  if request.get? && params[:_track]
163
- track! params[:_track]
163
+ Vanity.track! params[:_track]
164
164
  end
165
165
  end
166
166
 
@@ -6,14 +6,14 @@ module Vanity
6
6
  # @example From Rails controller
7
7
  # class AccountController < ApplicationController
8
8
  # def create
9
- # track! :signup
10
- # Acccount.create! params[:account]
9
+ # Vanity.track!(:signup)
10
+ # Acccount.create!(params[:account])
11
11
  # end
12
12
  # end
13
13
  # @example From ActiveRecord
14
14
  # class Posts < ActiveRecord::Base
15
15
  # after_create do |post|
16
- # track! :images if post.type == :image
16
+ # Vanity.track!(:images if post.type == :image)
17
17
  # end
18
18
  # end
19
19
  module Helpers
@@ -22,7 +22,7 @@ module Vanity
22
22
  #
23
23
  # @example A/B two alternatives for a page
24
24
  # def index
25
- # if ab_test(:new_page) # true/false test
25
+ # if Vanity.ab_test(:new_page) # true/false test
26
26
  # render action: "new_page"
27
27
  # else
28
28
  # render action: "index"
@@ -30,11 +30,12 @@ module Vanity
30
30
  # end
31
31
  # @example Similar, alternative value is page name
32
32
  # def index
33
- # render action: ab_test(:new_page)
33
+ # render action: Vanity.ab_test(:new_page)
34
34
  # end
35
35
  # @since 1.2.0
36
36
  def ab_test(name, &block)
37
- # TODO refactor with Vanity::Rails::Helpers#ab_test
37
+ # TODO refactor with Vanity::Rails::Helpers#ab_test, however that's used
38
+ # within Rails views
38
39
  request = respond_to?(:request) ? self.request : nil
39
40
  if Vanity.playground.using_js?
40
41
  value = Vanity.context.vanity_store_experiment_for_js name, Vanity.playground.experiment(name).choose(request)
@@ -44,7 +45,6 @@ module Vanity
44
45
 
45
46
  if block
46
47
  content = capture(value, &block)
47
- block_called_from_erb?(block) ? concat(content) : content
48
48
  else
49
49
  value
50
50
  end
@@ -56,9 +56,9 @@ module Vanity
56
56
  # tracked, but the user will not be added to the experiment.
57
57
  #
58
58
  # @example
59
- # track! :invitation
59
+ # Vanity.track!(:invitation)
60
60
  # @example
61
- # track! :click, { :identity=>Identity.new(env['rack.session']), :values=>[1] }
61
+ # Vanity.track!(:click, { :identity=>Identity.new(env['rack.session']), :values=>[1] })
62
62
  #
63
63
  # @param count_or_options Defaults to a count of 1. Also accepts a hash
64
64
  # of options passed (eventually) to AbTest#track!.
@@ -68,8 +68,3 @@ module Vanity
68
68
  end
69
69
  end
70
70
  end
71
-
72
- # TODO do we actually want to do this?
73
- Object.class_eval do
74
- include Vanity::Helpers
75
- end
@@ -5,11 +5,25 @@ module Vanity
5
5
  # Vanity::Configuration, for connection management, please see
6
6
  # Vanity::Connection.
7
7
  class Playground
8
+ # Returns hash of metrics (key is metric id).
9
+ #
10
+ # @see Vanity::Metric
11
+ # @since 1.1.0
12
+ # @deprecated
13
+ attr_reader :metrics
14
+
15
+ # Returns hash of experiments (key is experiment id). This creates the
16
+ # Experiment and persists it to the datastore.
17
+ #
18
+ # @see Vanity::Experiment
19
+ attr_reader :experiments
8
20
 
9
21
  # Created new Playground. Unless you need to, use the global
10
22
  # Vanity.playground.
11
23
  def initialize
12
24
  @loading = []
25
+ set_metrics
26
+ set_experiments
13
27
  end
14
28
 
15
29
  # @deprecated
@@ -136,21 +150,6 @@ module Vanity
136
150
  Vanity.load!
137
151
  end
138
152
 
139
- # Returns hash of experiments (key is experiment id). This creates the
140
- # Experiment and persists it to the datastore.
141
- #
142
- # @see Vanity::Experiment
143
- def experiments
144
- return @experiments if @experiments
145
-
146
- @experiments = {}
147
- Vanity.logger.info("Vanity: loading experiments from #{Vanity.configuration.experiments_path}")
148
- Dir[File.join(Vanity.configuration.experiments_path, "*.rb")].each do |file|
149
- Experiment::Base.load(self, @loading, file)
150
- end
151
- @experiments
152
- end
153
-
154
153
  def experiments_persisted?
155
154
  experiments.keys.all? { |id| connection.experiment_persisted?(id) }
156
155
  end
@@ -163,23 +162,6 @@ module Vanity
163
162
  metrics[id.to_sym] or raise NameError, "No metric #{id}"
164
163
  end
165
164
 
166
- # Returns hash of metrics (key is metric id).
167
- #
168
- # @see Vanity::Metric
169
- # @since 1.1.0
170
- # @deprecated
171
- def metrics
172
- unless @metrics
173
- @metrics = {}
174
- Vanity.logger.info("Vanity: loading metrics from #{Vanity.configuration.experiments_path}/metrics")
175
-
176
- Dir[File.join(Vanity.configuration.experiments_path, "metrics/*.rb")].each do |file|
177
- Metric.load(self, @loading, file)
178
- end
179
- end
180
- @metrics
181
- end
182
-
183
165
  # Tracks an action associated with a metric.
184
166
  #
185
167
  # @example
@@ -254,5 +236,27 @@ module Vanity
254
236
  def reconnect!
255
237
  Vanity.reconnect!
256
238
  end
239
+
240
+ private
241
+
242
+ def set_experiments
243
+ @experiments = {}
244
+
245
+ Vanity.logger.info("Vanity: loading experiments from #{Vanity.configuration.experiments_path}")
246
+
247
+ Dir[File.join(Vanity.configuration.experiments_path, "*.rb")].each do |file|
248
+ Experiment::Base.load(self, @loading, file)
249
+ end
250
+ end
251
+
252
+ def set_metrics
253
+ @metrics = {}
254
+
255
+ Vanity.logger.info("Vanity: loading metrics from #{Vanity.configuration.experiments_path}/metrics")
256
+
257
+ Dir[File.join(Vanity.configuration.experiments_path, "metrics/*.rb")].each do |file|
258
+ Metric.load(self, @loading, file)
259
+ end
260
+ end
257
261
  end
258
262
  end
data/lib/vanity/vanity.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  # Run time configuration and helpers
3
3
  #
4
4
  module Vanity
5
+ extend Vanity::Helpers
6
+
5
7
  # Returns the current configuration.
6
8
  #
7
9
  # @see Vanity::Configuration
@@ -1,5 +1,5 @@
1
1
  module Vanity
2
- VERSION = "2.0.0.beta9"
2
+ VERSION = "2.0.0"
3
3
 
4
4
  module Version
5
5
  version = VERSION.to_s.split(".").map { |i| i.to_i }
@@ -5,7 +5,7 @@ class AbTestController < ActionController::Base
5
5
  attr_accessor :current_user
6
6
 
7
7
  def test_render
8
- render :text=>ab_test(:simple)
8
+ render :text=>Vanity.ab_test(:simple)
9
9
  end
10
10
 
11
11
  def test_view
@@ -13,11 +13,11 @@ class AbTestController < ActionController::Base
13
13
  end
14
14
 
15
15
  def test_capture
16
- render :inline=>"<%= ab_test :simple do |value| %><%= value %><% end %>"
16
+ render :inline=>"<%= ab_test(:simple) do |value| %><%= value %><% end %>"
17
17
  end
18
18
 
19
19
  def track
20
- track! :coolness
20
+ Vanity.track!(:coolness)
21
21
  render :text=>""
22
22
  end
23
23
  end
@@ -17,13 +17,12 @@ describe Vanity::Experiment::Base do
17
17
  File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
18
18
  f.write <<-RUBY
19
19
  ab_test "Ice Cream Flavor" do
20
- metrics :happiness
21
20
  end
22
21
  ab_test "Ice Cream Flavor" do
23
- metrics :happiness
24
22
  end
25
23
  RUBY
26
24
  end
25
+ Vanity.unload!
27
26
  assert_raises NameError do
28
27
  experiment(:ice_cream_flavor)
29
28
  end
@@ -45,10 +44,10 @@ describe Vanity::Experiment::Base do
45
44
  def xmts
46
45
  "x"
47
46
  end
48
- metrics :happiness
49
47
  end
50
48
  RUBY
51
49
  end
50
+ Vanity.unload!
52
51
  assert_equal "x", experiment(:ice_cream_flavor).xmts
53
52
  end
54
53
 
@@ -56,6 +55,7 @@ describe Vanity::Experiment::Base do
56
55
  File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
57
56
  f.write "fail 'yawn!'"
58
57
  end
58
+ Vanity.unload!
59
59
  assert_raises NameError do
60
60
  experiment(:ice_cream_flavor)
61
61
  end
@@ -65,6 +65,7 @@ describe Vanity::Experiment::Base do
65
65
  File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
66
66
  f.write ""
67
67
  end
68
+ Vanity.unload!
68
69
  assert_raises NameError do
69
70
  experiment(:ice_cream_flavor)
70
71
  end
@@ -91,11 +92,10 @@ describe Vanity::Experiment::Base do
91
92
  File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
92
93
  f.write <<-RUBY
93
94
  ab_test "Ice Cream Flavor" do
94
- metrics :happiness
95
- expects(:save).at_least_once
96
95
  end
97
96
  RUBY
98
97
  end
98
+ Vanity.unload!
99
99
  Vanity.playground.experiment(:ice_cream_flavor)
100
100
  end
101
101
 
@@ -4,51 +4,27 @@ require "test_helper"
4
4
  class UseVanityController < ActionController::Base
5
5
  class TestModel
6
6
  def test_method
7
- ab_test(:pie_or_cake)
7
+ Vanity.ab_test(:pie_or_cake)
8
8
  end
9
9
  end
10
-
10
+
11
11
  attr_accessor :current_user
12
12
 
13
13
  def index
14
- render :text=>ab_test(:pie_or_cake)
14
+ render :text=>Vanity.ab_test(:pie_or_cake)
15
15
  end
16
16
 
17
17
  def js
18
- ab_test(:pie_or_cake)
18
+ Vanity.ab_test(:pie_or_cake)
19
19
  render :inline => "<%= vanity_js -%>"
20
20
  end
21
-
21
+
22
22
  def model_js
23
23
  TestModel.new.test_method
24
24
  render :inline => "<%= vanity_js -%>"
25
25
  end
26
26
  end
27
27
 
28
- # class UseVanityControllerTest < ActionController::TestCase
29
- # tests UseVanityController
30
-
31
- # def setup
32
- # super
33
- # new_ab_test :pie_or_cake do
34
- # metrics :sugar_high
35
- # end
36
-
37
- # # Class eval this instead of including in the controller to delay
38
- # # execution until the request exists in the context of the test
39
- # UseVanityController.class_eval do
40
- # use_vanity :current_user
41
- # end
42
- # end
43
-
44
- # def teardown
45
- # super
46
- # end
47
-
48
- # def test_bootstraps_metric
49
- # end
50
- # end
51
-
52
28
  class UseVanityControllerTest < ActionController::TestCase
53
29
  tests UseVanityController
54
30
 
@@ -80,7 +56,7 @@ class UseVanityControllerTest < ActionController::TestCase
80
56
  get :js
81
57
  assert_match /script.*v=pie_or_cake=.*script/m, @response.body
82
58
  end
83
-
59
+
84
60
  def test_render_model_js_for_tests
85
61
  Vanity.playground.use_js!
86
62
  get :model_js
@@ -103,6 +79,7 @@ class UseVanityControllerTest < ActionController::TestCase
103
79
  end
104
80
 
105
81
  def test_does_not_add_invalid_participant_to_experiment
82
+ Vanity.playground.use_js!
106
83
  @request.user_agent = "Googlebot/2.1 ( http://www.google.com/bot.html)"
107
84
  get :index
108
85
  assert_equal 0, experiment(:pie_or_cake).alternatives.map(&:participants).sum
data/test/helper_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
- describe Object do
3
+ describe Vanity::Helpers do
4
4
  describe "#track!" do
5
5
  it "identity option sets identity" do
6
6
  metric "Coolness"
@@ -8,7 +8,7 @@ describe Object do
8
8
  alternatives "foo", "bar"
9
9
  metrics :coolness
10
10
  end
11
- track!(:coolness, :identity=>'quux')
11
+ Vanity.track!(:coolness, :identity=>'quux')
12
12
 
13
13
  assert_equal 1, experiment(:foobar).alternatives.sum(&:conversions)
14
14
  end
@@ -19,7 +19,7 @@ describe Object do
19
19
  alternatives "foo", "bar"
20
20
  metrics :coolness
21
21
  end
22
- track!(:coolness, :identity=>'quux', :values=>[2])
22
+ Vanity.track!(:coolness, :identity=>'quux', :values=>[2])
23
23
 
24
24
  assert_equal 2, experiment(:foobar).alternatives.sum(&:conversions)
25
25
  end
@@ -219,7 +219,7 @@ describe Vanity::Metric::ActiveRecord do
219
219
  f.write <<-RUBY
220
220
  metric "Sky is limit" do
221
221
  model Sky, :conditions=>["height > 3"]
222
- Sky.after_save { |sky| track!(:sky_is_limit) if sky.height_changed? && sky.height > 3 }
222
+ Sky.after_save { |sky| Vanity.track!(:sky_is_limit) if sky.height_changed? && sky.height > 3 }
223
223
  end
224
224
  RUBY
225
225
  end
@@ -239,7 +239,7 @@ describe Vanity::Metric::ActiveRecord do
239
239
  File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
240
240
  f.write <<-RUBY
241
241
  metric "Sky is limit" do
242
- Sky.after_save { |sky| track!(:sky_is_limit) if sky.height_changed? && sky.height > 3 }
242
+ Sky.after_save { |sky| Vanity.track!(:sky_is_limit) if sky.height_changed? && sky.height > 3 }
243
243
  end
244
244
  RUBY
245
245
  end
@@ -16,10 +16,12 @@ describe "Remote metrics" do
16
16
  end
17
17
 
18
18
  it "loads from metrics files" do
19
+ Vanity.unload!
19
20
  assert Vanity.playground.metric(:sandbox)
20
21
  end
21
22
 
22
23
  it "creates remote metric from metric file" do
24
+ Vanity.unload!
23
25
  stub_request :post, /vanitydash/
24
26
  metric(:sandbox).track!
25
27
  assert_requested :post, /api\.vanitydash\.com/
@@ -7,45 +7,73 @@ describe Vanity::Playground do
7
7
  assert_equal instance, Vanity.playground
8
8
  end
9
9
 
10
- describe "#use_js!" do
11
- it "sets via use_js" do
12
- assert !Vanity.playground.using_js?
13
- Vanity.playground.use_js!
14
- assert Vanity.playground.using_js?
10
+ it "creates metrics hooks on initialization for tracking" do
11
+ File.open "tmp/experiments/metrics/coolness.rb", "w" do |f|
12
+ f.write <<-RUBY
13
+ metric "coolness" do
14
+ end
15
+ RUBY
15
16
  end
16
- end
17
17
 
18
- describe "#failover_on_datastore_error" do
19
- it "sets failover_on_datastore_error" do
20
- assert !Vanity.playground.failover_on_datastore_error?
21
- Vanity.playground.failover_on_datastore_error!
22
- assert Vanity.playground.failover_on_datastore_error?
18
+ File.open "tmp/experiments/foobar.rb", "w" do |f|
19
+ f.write <<-RUBY
20
+ ab_test :foobar do
21
+ metrics :coolness
22
+ end
23
+ RUBY
23
24
  end
25
+
26
+ # new_ab_test :foobar do
27
+ # alternatives "foo", "bar"
28
+ # identify { "abcdef" }
29
+ # metrics :coolness
30
+ # end
31
+
32
+ Vanity::Metric.any_instance.expects(:hook).once
33
+ Vanity::Playground.new
24
34
  end
25
35
 
26
- describe "#on_datastore_error" do
27
- it "has a default failover_on_datastore_error" do
28
- proc = Vanity.playground.on_datastore_error
29
- assert proc.respond_to?(:call)
30
- assert_silent do
31
- proc.call(Exception.new("datastore error"), self.class, caller[0][/`.*'/][1..-2], [1, 2, 3])
36
+ describe "deprecated settings" do
37
+ describe "#use_js!" do
38
+ it "sets via use_js" do
39
+ assert !Vanity.playground.using_js?
40
+ Vanity.playground.use_js!
41
+ assert Vanity.playground.using_js?
32
42
  end
33
43
  end
34
- end
35
44
 
36
- describe "#request_filter" do
37
- it "sets request_filter" do
38
- proc = Vanity.playground.request_filter
39
- assert proc.respond_to?(:call)
40
- assert_silent do
41
- proc.call(dummy_request)
45
+ describe "#failover_on_datastore_error" do
46
+ it "sets failover_on_datastore_error" do
47
+ assert !Vanity.playground.failover_on_datastore_error?
48
+ Vanity.playground.failover_on_datastore_error!
49
+ assert Vanity.playground.failover_on_datastore_error?
50
+ end
51
+ end
52
+
53
+ describe "#on_datastore_error" do
54
+ it "has a default failover_on_datastore_error" do
55
+ proc = Vanity.playground.on_datastore_error
56
+ assert proc.respond_to?(:call)
57
+ assert_silent do
58
+ proc.call(Exception.new("datastore error"), self.class, caller[0][/`.*'/][1..-2], [1, 2, 3])
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#request_filter" do
64
+ it "sets request_filter" do
65
+ proc = Vanity.playground.request_filter
66
+ assert proc.respond_to?(:call)
67
+ assert_silent do
68
+ proc.call(dummy_request)
69
+ end
42
70
  end
43
71
  end
44
- end
45
72
 
46
- describe "#add_participant_path" do
47
- it "sets a default add participant path" do
48
- assert_equal Vanity.playground.add_participant_path, Vanity::Configuration::DEFAULTS[:add_participant_route]
73
+ describe "#add_participant_path" do
74
+ it "sets a default add participant path" do
75
+ assert_equal Vanity.playground.add_participant_path, Vanity::Configuration::DEFAULTS[:add_participant_route]
76
+ end
49
77
  end
50
78
  end
51
79
 
metadata CHANGED
@@ -1,62 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vanity
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta9
5
- prerelease: 6
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Assaf Arkin
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-11-15 00:00:00.000000000 Z
11
+ date: 2015-12-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: i18n
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: bundler
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: 1.0.0
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: 1.0.0
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: minitest
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '4.2'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '4.2'
62
55
  description: Mirror, mirror on the wall ...
@@ -214,10 +207,11 @@ files:
214
207
  homepage: http://vanity.labnotes.org
215
208
  licenses:
216
209
  - MIT
210
+ metadata: {}
217
211
  post_install_message: To get started run vanity --help
218
212
  rdoc_options:
219
213
  - --title
220
- - Vanity 2.0.0.beta9
214
+ - Vanity 2.0.0
221
215
  - --main
222
216
  - README.rdoc
223
217
  - --webcvs
@@ -225,22 +219,20 @@ rdoc_options:
225
219
  require_paths:
226
220
  - lib
227
221
  required_ruby_version: !ruby/object:Gem::Requirement
228
- none: false
229
222
  requirements:
230
- - - ! '>='
223
+ - - '>='
231
224
  - !ruby/object:Gem::Version
232
225
  version: 1.9.3
233
226
  required_rubygems_version: !ruby/object:Gem::Requirement
234
- none: false
235
227
  requirements:
236
- - - ! '>'
228
+ - - '>='
237
229
  - !ruby/object:Gem::Version
238
- version: 1.3.1
230
+ version: '0'
239
231
  requirements: []
240
232
  rubyforge_project:
241
- rubygems_version: 1.8.23
233
+ rubygems_version: 2.2.2
242
234
  signing_key:
243
- specification_version: 3
235
+ specification_version: 4
244
236
  summary: Experience Driven Development framework for Ruby
245
237
  test_files:
246
238
  - test/adapters/redis_adapter_test.rb