mikeg-vanity 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +153 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +83 -0
- data/bin/vanity +53 -0
- data/lib/vanity.rb +38 -0
- data/lib/vanity/backport.rb +43 -0
- data/lib/vanity/commands.rb +2 -0
- data/lib/vanity/commands/list.rb +21 -0
- data/lib/vanity/commands/report.rb +60 -0
- data/lib/vanity/experiment/ab_test.rb +477 -0
- data/lib/vanity/experiment/base.rb +212 -0
- data/lib/vanity/helpers.rb +59 -0
- data/lib/vanity/metric/active_record.rb +77 -0
- data/lib/vanity/metric/base.rb +221 -0
- data/lib/vanity/metric/google_analytics.rb +70 -0
- data/lib/vanity/mock_redis.rb +76 -0
- data/lib/vanity/playground.rb +197 -0
- data/lib/vanity/rails.rb +22 -0
- data/lib/vanity/rails/dashboard.rb +24 -0
- data/lib/vanity/rails/helpers.rb +158 -0
- data/lib/vanity/rails/testing.rb +11 -0
- data/lib/vanity/templates/_ab_test.erb +26 -0
- data/lib/vanity/templates/_experiment.erb +5 -0
- data/lib/vanity/templates/_experiments.erb +7 -0
- data/lib/vanity/templates/_metric.erb +14 -0
- data/lib/vanity/templates/_metrics.erb +13 -0
- data/lib/vanity/templates/_report.erb +27 -0
- data/lib/vanity/templates/flot.min.js +1 -0
- data/lib/vanity/templates/jquery.min.js +19 -0
- data/lib/vanity/templates/vanity.css +26 -0
- data/lib/vanity/templates/vanity.js +82 -0
- data/test/ab_test_test.rb +656 -0
- data/test/experiment_test.rb +136 -0
- data/test/experiments/age_and_zipcode.rb +19 -0
- data/test/experiments/metrics/cheers.rb +3 -0
- data/test/experiments/metrics/signups.rb +2 -0
- data/test/experiments/metrics/yawns.rb +3 -0
- data/test/experiments/null_abc.rb +5 -0
- data/test/metric_test.rb +518 -0
- data/test/playground_test.rb +10 -0
- data/test/rails_test.rb +104 -0
- data/test/test_helper.rb +135 -0
- data/vanity.gemspec +18 -0
- data/vendor/redis-rb/LICENSE +20 -0
- data/vendor/redis-rb/README.markdown +36 -0
- data/vendor/redis-rb/Rakefile +62 -0
- data/vendor/redis-rb/bench.rb +44 -0
- data/vendor/redis-rb/benchmarking/suite.rb +24 -0
- data/vendor/redis-rb/benchmarking/worker.rb +71 -0
- data/vendor/redis-rb/bin/distredis +33 -0
- data/vendor/redis-rb/examples/basic.rb +16 -0
- data/vendor/redis-rb/examples/incr-decr.rb +18 -0
- data/vendor/redis-rb/examples/list.rb +26 -0
- data/vendor/redis-rb/examples/sets.rb +36 -0
- data/vendor/redis-rb/lib/dist_redis.rb +124 -0
- data/vendor/redis-rb/lib/hash_ring.rb +128 -0
- data/vendor/redis-rb/lib/pipeline.rb +21 -0
- data/vendor/redis-rb/lib/redis.rb +370 -0
- data/vendor/redis-rb/lib/redis/raketasks.rb +1 -0
- data/vendor/redis-rb/profile.rb +22 -0
- data/vendor/redis-rb/redis-rb.gemspec +30 -0
- data/vendor/redis-rb/spec/redis_spec.rb +637 -0
- data/vendor/redis-rb/spec/spec_helper.rb +4 -0
- data/vendor/redis-rb/speed.rb +16 -0
- data/vendor/redis-rb/tasks/redis.tasks.rb +140 -0
- metadata +125 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
== 1.3.0
|
2
|
+
This release adds support for Google Analytics and AdWords.
|
3
|
+
|
4
|
+
To view Google Analytics metrics from within Vanity, first make sure you are using Garb. For example, in your Gemfile:
|
5
|
+
|
6
|
+
gem "vanity", "1.3.0"
|
7
|
+
gem "garb", "0.5.0"
|
8
|
+
|
9
|
+
Next, authenticate using your account credentials. For example, in your config/environments/production.rb:
|
10
|
+
|
11
|
+
require "garb"
|
12
|
+
Garb::Session.login('..email..', '..password..', account_type: "GOOGLE") rescue nil
|
13
|
+
|
14
|
+
Last, define Vanity metrics that tap to Google Analytics metrics. For example:
|
15
|
+
|
16
|
+
metric "Acquisition: Visitors" do
|
17
|
+
description "Unique visitors on any given page, as tracked by Google Analytics"
|
18
|
+
google_analytics "UA-10087469-2", :visitors
|
19
|
+
end
|
20
|
+
|
21
|
+
* Added: Support for Google Analytics metrics, thanks to Tony Pitale's Garb and blog post: http://www.viget.com/extend/user-goal-tracking-in-rails-with-vanity-and-google-analytics/
|
22
|
+
* Added: Vanity query parameter that you can use to choose a particular alternative, e.g. to tie an advertisement banner with content of the site.
|
23
|
+
* Added: Command line "vanity list" catalogs all ongoing experiments, their alternatives (and fingerprints) and all metrics.
|
24
|
+
* Changed: Rails integration now separates use_vanity method, filters and helpers.
|
25
|
+
* Changed: Explicit vanity_context_filter and vanity_reload_filter so you can skip them, or order filters relative to them.
|
26
|
+
* Fixed: if metric cannot be loaded (e.g. offline, no db access) show error message for that metric but don't break dashboard.
|
27
|
+
* Removed: Vanity.playground.define is deprecated. Bad choice for a method name. If you need this feature, make a suggestion and let's create a better API.
|
28
|
+
|
29
|
+
== 1.2.0 (2009-12-14)
|
30
|
+
This release introduces metrics backed by ActiveRecord. Use them when your model is already tracking a metric, and you get instant historical data.
|
31
|
+
|
32
|
+
Example, track sign ups using User model:
|
33
|
+
|
34
|
+
metric "Signups" do
|
35
|
+
model Account
|
36
|
+
end
|
37
|
+
|
38
|
+
Example, track satisfaction using Survey model:
|
39
|
+
metric "Satisfaction" do
|
40
|
+
model Survey, :average=>:rating
|
41
|
+
end
|
42
|
+
|
43
|
+
Example, track only high ratings:
|
44
|
+
metric "High ratings" do
|
45
|
+
model Rating, :conditions=>["stars >= 4"]
|
46
|
+
end
|
47
|
+
|
48
|
+
There's no need to call track! on these metrics.
|
49
|
+
|
50
|
+
* Added: Metrics backed by ActiveRecord.
|
51
|
+
* Added: track! and ab_test methods now available from Object (i.e. everywhere).
|
52
|
+
* Added: Playground.load!. Now loading all metrics and experiments from Rails initializer.
|
53
|
+
* Changed: Decoupled metric name from identifier. You can now define a metric with more descriptive name, e.g. "Cheers per second (user satisfaction)" and keep their ID simple. Identifier is matched against the file name (for metrics loaded from experiments/metrics).
|
54
|
+
* Changed: Metrics no longer defined on-demand, i.e. calling playground.metric either returns existing metric or raises exception.
|
55
|
+
* Changed: Playground.experiments returns hash instead of array.
|
56
|
+
* Changed: All dates in report are UTC, since we don't know which locale to use.
|
57
|
+
* Removed: Object.experiment is deprecated, please call Vanity.playground.experiment directly.
|
58
|
+
* Fixed: Playground no longer changes logging level on supplied logger.
|
59
|
+
|
60
|
+
== 1.1.1 (2009-12-4)
|
61
|
+
* Fixed: Binding issue that shows up on 1.8.6/7.
|
62
|
+
|
63
|
+
== 1.1.0 (2009-12-4)
|
64
|
+
This release introduces metrics. Metrics are the gateway drug to better software.
|
65
|
+
|
66
|
+
It’s as simple as defining a metric:
|
67
|
+
|
68
|
+
metric "Cheers" do
|
69
|
+
description "They love us, don't they?"
|
70
|
+
end
|
71
|
+
|
72
|
+
Tracking it from your code:
|
73
|
+
|
74
|
+
track! :cheers
|
75
|
+
|
76
|
+
And watching the graph from the Dashboard.
|
77
|
+
|
78
|
+
You can (should) also use metrics with your A/B tests, for example:
|
79
|
+
|
80
|
+
ab_test "Pricing options" do
|
81
|
+
metrics :signup
|
82
|
+
alternatives 15, 25, 29
|
83
|
+
end
|
84
|
+
|
85
|
+
This new usage may become requirement in a future release.
|
86
|
+
|
87
|
+
Much thanks to Ian Sefferman for fixing issues with Ruby 1.8.7 and Rails support.
|
88
|
+
|
89
|
+
* Added: Metrics.
|
90
|
+
* Added: Use Vanity.playground.mock! when running tests and you'd rather not access a live Redis server.
|
91
|
+
* Changed: A/B tests now using metrics for tracking.
|
92
|
+
* Changed: Now throwing NameError instead of LoadError when failing to load experiment/metric. NameError can be rescued on same line.
|
93
|
+
* Changed: New, easier URL mapping for Dashboard: map.vanity "/vanity", :controller=>:vanity.
|
94
|
+
* Changed: All tests are green on Ruby 1.8.6, 1.8.7 and 1.9.1.
|
95
|
+
* Changed: Switched to redis-rb from http://github.com/ezmobius/redis-rb.
|
96
|
+
* Deprecated: Please call experiment method with experiment identifier (a symbol) and not experiment name.
|
97
|
+
|
98
|
+
== 1.0.0 (2009-11-19)
|
99
|
+
This release changes the way you define a new experiment. You can use a method suitable for the type of experiment you want to define, or call the generic define method (previously: experiment method). For example:
|
100
|
+
|
101
|
+
ab_test "My A/B test" do
|
102
|
+
alternatives :a, :b
|
103
|
+
end
|
104
|
+
|
105
|
+
The experiment method is no longer overloaded: it looks up an experiment (loading its definition if necessary), but does not define an experiment. The ab_test method is overloaded, though this may change in the future.
|
106
|
+
|
107
|
+
In addition, the ab_goal! method is now track!. This method may be used for other tests in the future.
|
108
|
+
|
109
|
+
* Added: A/B test report now showing number of participants.
|
110
|
+
* Added: AbTest.score method accepts minimum probability (default 90), and
|
111
|
+
* Removed: Experiment.reset! method. Destroy and save have the same effect.
|
112
|
+
* Changed: Playground.define now requires an experiment type, ab_test is not the default any more.
|
113
|
+
* Changed: When you run Vanity in development mode (configuration.cache_classes = false), it will reload experiments on each request. You can also Vanity.playground.reload!.
|
114
|
+
* Changed: Fancy AJAX trickery in Rails console.
|
115
|
+
* Changed: You can break long experiment descriptions into multiple paragraphs using two consecutive newlines.
|
116
|
+
* Changed: AbTest confidence becomes probability; only returns choice alternative with probability equal or higher than that.
|
117
|
+
* Changed: ab_goal! becomes track!.
|
118
|
+
* Changed: Console becomes Dashboard, which is less confusing with rails console (script/console).
|
119
|
+
|
120
|
+
== 0.3.1 (2009-11-13)
|
121
|
+
* Changed: Redis 1.0 is now vendored into Vanity. This means one less dependecy ... actually two, since Redis brings with it RSpec.
|
122
|
+
|
123
|
+
== 0.3.0 (2009-11-13)
|
124
|
+
* Added: score now includes least performing alternatives, names and values.
|
125
|
+
* Added: shiny reports.
|
126
|
+
* Added: Rails console shows current experiments status and also allows you to choose which alternative you want to see.
|
127
|
+
* Changed: letters instead of numbers for options (option 1 => option A).
|
128
|
+
* Changed: experiment.alternatives is now an immutable snapshot.
|
129
|
+
* Changed: experiment.score returns populated alternative objects instead of structs.
|
130
|
+
* Changed: experiment.chooses uses Redis to store state, better for (when we get to) browser integration.
|
131
|
+
* Changed: experiment.chooses skips recording participant or conversion.
|
132
|
+
* Changed: to MIT license.
|
133
|
+
|
134
|
+
== 0.2.2 (2009-11-12)
|
135
|
+
* Added: vanity binary, with single command for generating a report.
|
136
|
+
* Added: return alternative by value from experiment.alternative(val) method.
|
137
|
+
* Added: reset an experiment by calling reset!.
|
138
|
+
* Added: experiment alternative name (option 1, option 2, etc).
|
139
|
+
* Added: new scoring algorithm: use experiment.score instead of alternative.z_score/confidence.
|
140
|
+
* Added: experiment.conclusion for plain English results.
|
141
|
+
|
142
|
+
== 0.2.1 (2009-11-11)
|
143
|
+
* Added: z-score and confidence level for A/B test alternatives.
|
144
|
+
* Added: test auto-completion and auto-outcome (complete_it, outcome_is).
|
145
|
+
* Changed: default alternatives are now false/true, so if can't decide outcome, fall back on false.
|
146
|
+
|
147
|
+
== 0.2.0 (2009-11-10)
|
148
|
+
* Added: experiment method on object, used to define and access experiments.
|
149
|
+
* Added: playground configuration (Vanity.playground.namespace = , etc).
|
150
|
+
* Added: use_vanity now accepts block instead of symbol.
|
151
|
+
* Changed: Vanity::Helpers becomes Vanity::Rails.
|
152
|
+
* Changed: A/B test experiments alternatives now handled using Alternatives object.
|
153
|
+
* Removed: A/B test measure method no longer in use.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2009 Assaf Arkin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
Vanity is an Experiment Driven Development framework for Rails.
|
2
|
+
|
3
|
+
* All about Vanity: http://vanity.labnotes.org
|
4
|
+
* On github: http://github.com/assaf/vanity
|
5
|
+
* Vanity requires Redis 1.0 or later.
|
6
|
+
|
7
|
+
http://farm3.static.flickr.com/2540/4099665871_497f274f68_o.jpg
|
8
|
+
|
9
|
+
|
10
|
+
== A/B Testing With Rails (In 5 Easy Steps)
|
11
|
+
|
12
|
+
<b>Step 1:</b> Start using Vanity in your Rails application:
|
13
|
+
|
14
|
+
gem.config "vanity"
|
15
|
+
|
16
|
+
And:
|
17
|
+
|
18
|
+
class ApplicationController < ActionController::Base
|
19
|
+
use_vanity :current_user
|
20
|
+
end
|
21
|
+
|
22
|
+
<b>Step 2:</b> Define your first A/B test. This experiment goes in the file <code>experiments/price_options.rb</code>:
|
23
|
+
|
24
|
+
ab_test "Price options" do
|
25
|
+
description "Mirror, mirror on the wall, who's the better price of all?"
|
26
|
+
alternatives 19, 25, 29
|
27
|
+
metrics :signups
|
28
|
+
end
|
29
|
+
|
30
|
+
<b>Step 3:</b> Present the different options to your users:
|
31
|
+
|
32
|
+
<h2>Get started for only $<%= ab_test :price_options %> a month!</h2>
|
33
|
+
|
34
|
+
<b>Step 4:</b> Measure conversion:
|
35
|
+
|
36
|
+
class SignupController < ApplicationController
|
37
|
+
def signup
|
38
|
+
@account = Account.new(params[:account])
|
39
|
+
if @account.save
|
40
|
+
track! :signups
|
41
|
+
redirect_to @acccount
|
42
|
+
else
|
43
|
+
render action: :offer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
<b>Step 5:</b> Check the report:
|
49
|
+
|
50
|
+
vanity --output vanity.html
|
51
|
+
|
52
|
+
|
53
|
+
== Building From Source
|
54
|
+
|
55
|
+
To run the test suite for the first time:
|
56
|
+
|
57
|
+
$ gem install rails mocha timecop
|
58
|
+
$ rake
|
59
|
+
|
60
|
+
You can also +rake test+ if you insist on being explicit.
|
61
|
+
|
62
|
+
To build the documentation:
|
63
|
+
|
64
|
+
$ gem install yardoc jekyll
|
65
|
+
$ rake docs
|
66
|
+
$ open html/index.html
|
67
|
+
|
68
|
+
To clean up after yourself:
|
69
|
+
|
70
|
+
$ rake clobber
|
71
|
+
|
72
|
+
To package Vanity as a gem and install on your machine:
|
73
|
+
|
74
|
+
$ rake install
|
75
|
+
|
76
|
+
|
77
|
+
== Credits/License
|
78
|
+
|
79
|
+
Original code, copyright of Assaf Arkin, released under the MIT license.
|
80
|
+
|
81
|
+
Documentation available under the Creative Commons Attribution license.
|
82
|
+
|
83
|
+
For full list of credits and licenses: http://vanity.labnotes.org/credits.html.
|
data/bin/vanity
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
path = File.expand_path("../lib", File.dirname(__FILE__))
|
3
|
+
$LOAD_PATH.unshift path unless $LOAD_PATH.include?(path)
|
4
|
+
|
5
|
+
require "vanity"
|
6
|
+
require "optparse"
|
7
|
+
|
8
|
+
playground = Vanity.playground
|
9
|
+
options = Struct.new(:output).new
|
10
|
+
opts = OptionParser.new("", 24, " ") do |opts|
|
11
|
+
opts.banner = "Usage: #{File.basename($0)} [options] command\n"
|
12
|
+
opts.banner << "Commands:\n"
|
13
|
+
opts.banner << " report Report on all running experiments/metrics"
|
14
|
+
opts.banner << " list List all experiments and metrics"
|
15
|
+
|
16
|
+
opts.separator ""
|
17
|
+
opts.separator "General options:"
|
18
|
+
opts.on("--path PATH", "Path to experiments directory (default: #{playground.load_path})") { |v| playground.load_path = v }
|
19
|
+
opts.on("--output FILE", "Write report to this file (default: stdout)") { |v| options.output = v }
|
20
|
+
|
21
|
+
opts.separator ""
|
22
|
+
opts.separator "Redis options:"
|
23
|
+
opts.on("--host HOST", "Redis server host (default: #{playground.host})") { |v| playground.host = v }
|
24
|
+
opts.on("--port PORT", "Redis server port (default: #{playground.port})") { |v| playground.port = v }
|
25
|
+
opts.on("--db DB", "Redis database (default: #{playground.db})") { |v| playground.db = v }
|
26
|
+
opts.on("--password PWD", "Redis database password") { |v| playground.password = v }
|
27
|
+
opts.on("--namespace NS", "Redis namespace (default: #{playground.namespace})") { |v| playground.namespace = v }
|
28
|
+
|
29
|
+
opts.separator ""
|
30
|
+
opts.separator "Common options:"
|
31
|
+
opts.on_tail "-h", "-H", "--help", "Show this message" do
|
32
|
+
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
opts.on_tail "-v", "--version", "Show version" do
|
36
|
+
puts "Vanity #{Vanity::Version::STRING}"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.parse!(ARGV)
|
42
|
+
if ARGV.empty?
|
43
|
+
puts opts.banner
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
|
47
|
+
ARGV.each do |cmd|
|
48
|
+
case cmd
|
49
|
+
when "report"; Vanity::Commands.report options.output
|
50
|
+
when "list"; Vanity::Commands.list
|
51
|
+
else fail "No such command: #{cmd}"
|
52
|
+
end
|
53
|
+
end
|
data/lib/vanity.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "date"
|
2
|
+
require "time"
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../vendor/redis-rb/lib")
|
6
|
+
autoload :Redis, "redis"
|
7
|
+
|
8
|
+
# All the cool stuff happens in other places.
|
9
|
+
# @see Vanity::Helper
|
10
|
+
# @see Vanity::Rails
|
11
|
+
# @see Vanity::Playground
|
12
|
+
# @see Vanity::Metric
|
13
|
+
# @see Vanity::Experiment
|
14
|
+
module Vanity
|
15
|
+
# Version number.
|
16
|
+
module Version
|
17
|
+
version = Gem::Specification.load(File.expand_path("../vanity.gemspec", File.dirname(__FILE__))).version.to_s.split(".").map { |i| i.to_i }
|
18
|
+
MAJOR = version[0]
|
19
|
+
MINOR = version[1]
|
20
|
+
PATCH = version[2]
|
21
|
+
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require "vanity/backport" if RUBY_VERSION < "1.9"
|
26
|
+
# Metrics.
|
27
|
+
require "vanity/metric/base"
|
28
|
+
require "vanity/metric/active_record"
|
29
|
+
require "vanity/metric/google_analytics" if defined?(Garb)
|
30
|
+
# Experiments.
|
31
|
+
require "vanity/experiment/base"
|
32
|
+
require "vanity/experiment/ab_test"
|
33
|
+
# Playground.
|
34
|
+
require "vanity/playground"
|
35
|
+
require "vanity/helpers"
|
36
|
+
Vanity.autoload :MockRedis, "vanity/mock_redis"
|
37
|
+
Vanity.autoload :Commands, "vanity/commands"
|
38
|
+
require "vanity/rails" if defined?(Rails)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Time
|
2
|
+
unless method_defined?(:to_date)
|
3
|
+
# Backported from Ruby 1.9.
|
4
|
+
def to_date
|
5
|
+
jd = Date.__send__(:civil_to_jd, year, mon, mday, Date::ITALY)
|
6
|
+
Date.new!(Date.__send__(:jd_to_ajd, jd, 0, 0), 0, Date::ITALY)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Date
|
12
|
+
unless method_defined?(:to_date)
|
13
|
+
# Backported from Ruby 1.9.
|
14
|
+
def to_date
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
unless method_defined?(:to_time)
|
20
|
+
# Backported from Ruby 1.9.
|
21
|
+
def to_time
|
22
|
+
Time.local(year, mon, mday)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Symbol
|
28
|
+
unless method_defined?(:to_proc)
|
29
|
+
# Backported from Ruby 1.9.
|
30
|
+
def to_proc
|
31
|
+
Proc.new { |*args| args.shift.__send__(self, *args) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Array
|
37
|
+
unless method_defined?(:minmax)
|
38
|
+
# Backported from Ruby 1.9.
|
39
|
+
def minmax
|
40
|
+
[min, max]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Vanity
|
2
|
+
module Commands
|
3
|
+
class << self
|
4
|
+
# Lists all experiments and metrics.
|
5
|
+
def list
|
6
|
+
Vanity.playground.experiments.each do |id, experiment|
|
7
|
+
puts "experiment :%-.20s (%-.40s)" % [id, experiment.name]
|
8
|
+
if experiment.respond_to?(:alternatives)
|
9
|
+
experiment.alternatives.each do |alt|
|
10
|
+
hash = experiment.fingerprint(alt)
|
11
|
+
puts " %s: %-40.40s (%s)" % [alt.name, alt.value, hash]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
Vanity.playground.metrics.each do |id, metric|
|
16
|
+
puts "metric :%-.20s (%-.40s)" % [id, metric.name]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "cgi"
|
3
|
+
|
4
|
+
module Vanity
|
5
|
+
|
6
|
+
# Render method available to templates (when used by Vanity command line,
|
7
|
+
# outside Rails).
|
8
|
+
module Render
|
9
|
+
|
10
|
+
# Render the named template. Used for reporting and the dashboard.
|
11
|
+
def render(path, locals = {})
|
12
|
+
locals[:playground] = self
|
13
|
+
keys = locals.keys
|
14
|
+
struct = Struct.new(*keys)
|
15
|
+
struct.send :include, Render
|
16
|
+
locals = struct.new(*locals.values_at(*keys))
|
17
|
+
dir, base = File.split(path)
|
18
|
+
path = File.join(dir, "_#{base}")
|
19
|
+
erb = ERB.new(File.read(path), nil, '<>')
|
20
|
+
erb.filename = path
|
21
|
+
erb.result(locals.instance_eval { binding })
|
22
|
+
end
|
23
|
+
|
24
|
+
# Escape HTML.
|
25
|
+
def h(html)
|
26
|
+
CGI.escapeHTML(html)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Dumbed down from Rails' simple_format.
|
30
|
+
def simple_format(text, options={})
|
31
|
+
open = "<p #{options.map { |k,v| "#{k}=\"#{CGI.escapeHTML v}\"" }.join(" ")}>"
|
32
|
+
text = open + text.gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
|
33
|
+
gsub(/\n\n+/, "</p>\n\n#{open}"). # 2+ newline -> paragraph
|
34
|
+
gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') + # 1 newline -> br
|
35
|
+
"</p>"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Commands available when running Vanity from the command line (see bin/vanity).
|
40
|
+
module Commands
|
41
|
+
class << self
|
42
|
+
include Render
|
43
|
+
|
44
|
+
# Generate an HTML report. Outputs to the named file, or stdout with no
|
45
|
+
# arguments.
|
46
|
+
def report(output = nil)
|
47
|
+
html = render(Vanity.template("report"))
|
48
|
+
if output
|
49
|
+
File.open output, 'w' do |file|
|
50
|
+
file.write html
|
51
|
+
end
|
52
|
+
puts "New report available in #{output}"
|
53
|
+
else
|
54
|
+
$stdout.write html
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|