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 +7 -0
- data/CHANGELOG +14 -0
- data/Gemfile.lock +2 -3
- data/README.rdoc +14 -10
- data/doc/ab_testing.textile +9 -9
- data/doc/configuring.textile +35 -7
- data/doc/contributing.textile +1 -39
- data/doc/experimental.textile +2 -2
- data/doc/metrics.textile +4 -4
- data/doc/rails.textile +5 -27
- data/doc/site.js +0 -17
- data/gemfiles/rails32.gemfile +2 -2
- data/gemfiles/rails32.gemfile.lock +1 -1
- data/gemfiles/rails4.gemfile +2 -2
- data/gemfiles/rails4.gemfile.lock +2 -2
- data/gemfiles/rails41.gemfile +2 -2
- data/gemfiles/rails41.gemfile.lock +1 -1
- data/gemfiles/rails42.gemfile +2 -2
- data/gemfiles/rails42.gemfile.lock +1 -1
- data/lib/vanity/frameworks/rails.rb +1 -1
- data/lib/vanity/helpers.rb +9 -14
- data/lib/vanity/playground.rb +36 -32
- data/lib/vanity/vanity.rb +2 -0
- data/lib/vanity/version.rb +1 -1
- data/test/experiment/ab_test.rb +3 -3
- data/test/experiment/base_test.rb +5 -5
- data/test/frameworks/rails/action_controller_test.rb +7 -30
- data/test/helper_test.rb +3 -3
- data/test/metric/active_record_test.rb +2 -2
- data/test/metric/remote_test.rb +2 -0
- data/test/playground_test.rb +56 -28
- metadata +15 -23
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
|
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
|
-
|
50
|
-
|
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!
|
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
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
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:
|
data/doc/ab_testing.textile
CHANGED
@@ -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!
|
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
|
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
|
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!"
|
data/doc/configuring.textile
CHANGED
@@ -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
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
50
|
+
Use the playground object to configure Vanity. For example:
|
39
51
|
|
40
52
|
<pre>
|
41
|
-
Vanity.
|
42
|
-
|
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>
|
data/doc/contributing.textile
CHANGED
@@ -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>
|
data/doc/experimental.textile
CHANGED
@@ -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!
|
28
|
-
metric(:purchase).track!
|
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!
|
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!
|
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.
|
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
|
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) {
|
data/gemfiles/rails32.gemfile
CHANGED
@@ -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
|
data/gemfiles/rails4.gemfile
CHANGED
@@ -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
|
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)
|
data/gemfiles/rails41.gemfile
CHANGED
@@ -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"
|
data/gemfiles/rails42.gemfile
CHANGED
@@ -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"
|
data/lib/vanity/helpers.rb
CHANGED
@@ -6,14 +6,14 @@ module Vanity
|
|
6
6
|
# @example From Rails controller
|
7
7
|
# class AccountController < ApplicationController
|
8
8
|
# def create
|
9
|
-
# track!
|
10
|
-
# Acccount.create!
|
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!
|
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!
|
59
|
+
# Vanity.track!(:invitation)
|
60
60
|
# @example
|
61
|
-
# track!
|
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
|
data/lib/vanity/playground.rb
CHANGED
@@ -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
data/lib/vanity/version.rb
CHANGED
data/test/experiment/ab_test.rb
CHANGED
@@ -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
|
16
|
+
render :inline=>"<%= ab_test(:simple) do |value| %><%= value %><% end %>"
|
17
17
|
end
|
18
18
|
|
19
19
|
def track
|
20
|
-
track!
|
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
|
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
|
data/test/metric/remote_test.rb
CHANGED
@@ -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/
|
data/test/playground_test.rb
CHANGED
@@ -7,45 +7,73 @@ describe Vanity::Playground do
|
|
7
7
|
assert_equal instance, Vanity.playground
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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 "
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
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
|
+
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
|
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:
|
230
|
+
version: '0'
|
239
231
|
requirements: []
|
240
232
|
rubyforge_project:
|
241
|
-
rubygems_version:
|
233
|
+
rubygems_version: 2.2.2
|
242
234
|
signing_key:
|
243
|
-
specification_version:
|
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
|