vanity 2.0.0.beta3 → 2.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/bin/vanity +1 -9
- data/doc/_layouts/page.html +1 -1
- data/doc/contributing.textile +2 -2
- data/doc/index.textile +1 -1
- data/gemfiles/rails32.gemfile.lock +1 -1
- data/gemfiles/rails4.gemfile.lock +1 -1
- data/lib/vanity/adapters/active_record_adapter.rb +2 -10
- data/lib/vanity/metric/active_record.rb +17 -5
- data/lib/vanity/version.rb +1 -1
- data/test/cli_test.rb +5 -5
- data/test/dummy/config/initializers/secret_token.rb +1 -0
- data/test/metric/active_record_test.rb +11 -12
- data/test/playground_test.rb +4 -2
- data/test/test_helper.rb +2 -2
- metadata +3 -14
- data/lib/vanity/commands/upgrade.rb +0 -34
- data/test/experiments/age_and_zipcode.rb +0 -19
- data/test/experiments/metrics/cheers.rb +0 -3
- data/test/experiments/metrics/signups.rb +0 -2
- data/test/experiments/metrics/yawns.rb +0 -3
- data/test/experiments/null_abc.rb +0 -5
data/Gemfile.lock
CHANGED
data/bin/vanity
CHANGED
@@ -16,7 +16,6 @@ opts = OptionParser.new("", 24, " ") do |opts|
|
|
16
16
|
opts.banner << "Commands:\n"
|
17
17
|
opts.banner << " list List all experiments and metrics\n"
|
18
18
|
opts.banner << " report Report on all running experiments/metrics\n"
|
19
|
-
opts.banner << " upgrade Upgrade your database when deploying new release\n"
|
20
19
|
|
21
20
|
opts.separator ""
|
22
21
|
opts.separator "Reporting options:"
|
@@ -29,13 +28,9 @@ opts = OptionParser.new("", 24, " ") do |opts|
|
|
29
28
|
opts.on "--load_path PATH", "Path to experiments directory (default: #{playground.load_path})" do |path|
|
30
29
|
playground.load_path = path
|
31
30
|
end
|
32
|
-
opts.on "-d", "--database url", "Database connection URL (e.g. redis
|
31
|
+
opts.on "-d", "--database url", "Database connection URL (e.g. redis://localhost:6379)" do |conn|
|
33
32
|
playground.establish_connection conn
|
34
33
|
end
|
35
|
-
opts.on "--redis HOST:PORT:DB", "DEPRECATED: Redis server host (default: localhost:6379)" do |redis|
|
36
|
-
host, port, db = redis.split(":")
|
37
|
-
playground.establish_connection "redis:/#{host}:#{port}/#{db}"
|
38
|
-
end
|
39
34
|
opts.on_tail "-h", "--help", "Show this message" do
|
40
35
|
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
41
36
|
exit
|
@@ -60,9 +55,6 @@ ARGV.each do |cmd|
|
|
60
55
|
when "list"
|
61
56
|
require "vanity/commands/list"
|
62
57
|
Vanity::Commands.list
|
63
|
-
when "upgrade"
|
64
|
-
require "vanity/commands/upgrade"
|
65
|
-
Vanity::Commands.upgrade
|
66
58
|
else puts "No such command: #{cmd}"
|
67
59
|
end
|
68
60
|
end
|
data/doc/_layouts/page.html
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
</div>
|
16
16
|
<div id="links">
|
17
17
|
<a href="http://github.com/assaf/vanity">Source code</a> |
|
18
|
-
<a href="http://
|
18
|
+
<a href="http://stackoverflow.com/questions/tagged/vanity" title="stackoverflow vanity tag">StackOverflow Tag</a> |
|
19
19
|
<a href="http://rdoc.info/gems/vanity">API reference</a>
|
20
20
|
</div>
|
21
21
|
<div id="sidebar">
|
data/doc/contributing.textile
CHANGED
@@ -15,7 +15,7 @@ By all means.
|
|
15
15
|
|
16
16
|
h3(#contributing). How To Contribute
|
17
17
|
|
18
|
-
Pick on an "open issue":http://github.com/assaf/vanity/issues, "experimental feature":experimental.html,
|
18
|
+
Pick on an "open issue":http://github.com/assaf/vanity/issues, "experimental feature":experimental.html, or whatever you feel like contributing.
|
19
19
|
|
20
20
|
To contribute new code/changes:
|
21
21
|
# "Fork the project":http://github.com/assaf/vanity
|
@@ -68,7 +68,7 @@ h3(#doc). Documentation
|
|
68
68
|
|
69
69
|
Documentation is written in "Textile":http://redcloth.org/textile/writing-paragraph-text/, and converted to HTML using "Jekyll":http://jekyllrb.com/.
|
70
70
|
|
71
|
-
API reference is "RDoc":http://rdoc.sourceforge.net/doc/index.html, converted to HTML using "Yardoc":http://yardoc.org/.
|
71
|
+
API reference is "RDoc":http://rdoc.sourceforge.net/doc/index.html, converted to HTML using "Yardoc":http://yardoc.org/.
|
72
72
|
|
73
73
|
To build and view documentation:
|
74
74
|
|
data/doc/index.textile
CHANGED
@@ -21,7 +21,7 @@ Also:
|
|
21
21
|
* "Experiment Driven Development(Introduction to EDD and Vanity)":http://blog.labnotes.org/2009/11/19/vanity-experiment-driven-development-for-rails/
|
22
22
|
* "Get the code(Official Github repository)":http://github.com/assaf/vanity
|
23
23
|
* "API reference":api/index.html
|
24
|
-
* "
|
24
|
+
* "Ask questions on StackOverflow":http://stackoverflow.com/questions/tagged/vanity
|
25
25
|
* "Contributing to Vanity":contributing.html
|
26
26
|
|
27
27
|
h3(#intro). Introduction & setup
|
@@ -25,14 +25,6 @@ module Vanity
|
|
25
25
|
send :"find_or_create_by_#{method}", value
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
def self.rails_agnostic_find_first(conditions)
|
30
|
-
if respond_to? :where
|
31
|
-
where(conditions).first
|
32
|
-
else
|
33
|
-
find(:first, :conditions => conditions)
|
34
|
-
end
|
35
|
-
end
|
36
28
|
end
|
37
29
|
|
38
30
|
# Schema model
|
@@ -103,7 +95,7 @@ module Vanity
|
|
103
95
|
# passed then this will be passed to create if creating, or will be
|
104
96
|
# used to update the found participant.
|
105
97
|
def self.retrieve(experiment, identity, create = true, update_with = nil)
|
106
|
-
if record = VanityParticipant.
|
98
|
+
if record = VanityParticipant.where(:experiment_id=>experiment.to_s, :identity=>identity.to_s).first
|
107
99
|
record.update_attributes(update_with) if update_with
|
108
100
|
elsif create
|
109
101
|
record = VanityParticipant.create({ :experiment_id=>experiment.to_s, :identity=>identity.to_s }.merge(update_with || {}))
|
@@ -220,7 +212,7 @@ module Vanity
|
|
220
212
|
record = VanityExperiment.retrieve(experiment)
|
221
213
|
participants = VanityParticipant.where(:experiment_id => experiment.to_s, :seen => alternative).count
|
222
214
|
converted = VanityParticipant.where(:experiment_id => experiment.to_s, :converted => alternative).count
|
223
|
-
conversions = record.vanity_conversions.
|
215
|
+
conversions = record.vanity_conversions.where(:alternative => alternative).sum(:conversions)
|
224
216
|
|
225
217
|
{
|
226
218
|
:participants => participants,
|
@@ -39,15 +39,19 @@ module Vanity
|
|
39
39
|
class_or_scope = class_or_scope.constantize if class_or_scope.is_a?(String)
|
40
40
|
options = options || {}
|
41
41
|
conditions = options.delete(:conditions)
|
42
|
-
|
42
|
+
|
43
|
+
@ar_scoped = conditions ? class_or_scope.where(conditions) : class_or_scope
|
43
44
|
@ar_aggregate = AGGREGATES.find { |key| options.has_key?(key) }
|
44
45
|
@ar_column = options.delete(@ar_aggregate)
|
45
46
|
fail "Cannot use multiple aggregates in a single metric" if AGGREGATES.find { |key| options.has_key?(key) }
|
47
|
+
|
46
48
|
@ar_timestamp = options.delete(:timestamp) || :created_at
|
47
49
|
@ar_timestamp, @ar_timestamp_table = @ar_timestamp.to_s.split('.').reverse
|
48
50
|
@ar_timestamp_table ||= @ar_scoped.table_name
|
51
|
+
|
49
52
|
fail "Unrecognized options: #{options.keys * ", "}" unless options.empty?
|
50
|
-
|
53
|
+
|
54
|
+
@ar_scoped.after_create(self)
|
51
55
|
extend ActiveRecord
|
52
56
|
end
|
53
57
|
end
|
@@ -65,9 +69,16 @@ module Vanity
|
|
65
69
|
sdate = sdate + difference
|
66
70
|
edate = edate + difference
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
grouped = @ar_scoped
|
73
|
+
.where(@ar_timestamp_table => { @ar_timestamp => (sdate.to_time...(edate + 1).to_time) })
|
74
|
+
.group("date(#{@ar_scoped.quoted_table_name}.#{@ar_scoped.connection.quote_column_name(@ar_timestamp)})")
|
75
|
+
|
76
|
+
if @ar_column
|
77
|
+
grouped = grouped.send(@ar_aggregate, @ar_column)
|
78
|
+
else
|
79
|
+
grouped = grouped.count
|
80
|
+
end
|
81
|
+
|
71
82
|
grouped = Hash[grouped.map {|k,v| [k.to_date, v] }]
|
72
83
|
(sdate..edate).inject([]) { |ordered, date| ordered << (grouped[date] || 0) }
|
73
84
|
end
|
@@ -79,6 +90,7 @@ module Vanity
|
|
79
90
|
end
|
80
91
|
|
81
92
|
def last_update_at
|
93
|
+
# SELECT created_at FROM "skies" ORDER BY created_at DESC LIMIT 1
|
82
94
|
record = @ar_scoped.find(:first, :order=>"#@ar_timestamp DESC", :limit=>1, :select=>@ar_timestamp)
|
83
95
|
record && record.send(@ar_timestamp)
|
84
96
|
end
|
data/lib/vanity/version.rb
CHANGED
data/test/cli_test.rb
CHANGED
@@ -37,10 +37,10 @@ describe "bin/vanity" do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it "responds to unknown commands" do
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
assert_output("No such command: upgrade\n") do
|
41
|
+
ARGV.clear
|
42
|
+
ARGV << 'upgrade'
|
43
|
+
load "bin/vanity"
|
44
|
+
end
|
45
45
|
end
|
46
46
|
end
|
@@ -5,3 +5,4 @@
|
|
5
5
|
# Make sure the secret is at least 30 characters and all random,
|
6
6
|
# no regular words or you'll be exposed to dictionary attacks.
|
7
7
|
Dummy::Application.config.secret_token = '33ccbc9a29f3b02e87c08904505b1c9a3a1e97dd01f02e598e65ee9e7b96fff2ca4a6d0dd7c4a8d3682d8c64f84d372661e141264e70697dc576c722c72d80d0'
|
8
|
+
Dummy::Application.config.secret_key_base = 'secret' if Dummy::Application.config.respond_to?(:secret_key_base=)
|
@@ -1,23 +1,22 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Sky < ActiveRecord::Base
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
scope :high, lambda { where("height >= 4") }
|
5
|
+
end
|
6
|
+
|
7
|
+
if ENV["DB"] == "active_record"
|
8
|
+
|
9
|
+
describe Vanity::Metric::ActiveRecord do
|
10
|
+
|
11
|
+
before do
|
12
|
+
Sky.connection.create_table(:skies) do |t|
|
7
13
|
t.integer :height
|
8
14
|
t.timestamps
|
9
15
|
end
|
10
16
|
end
|
11
17
|
|
12
|
-
scope :high, lambda { { :conditions=>"height >= 4" } }
|
13
|
-
end
|
14
|
-
|
15
|
-
if ActiveRecord::Base.connected?
|
16
|
-
|
17
|
-
describe "ActiveRecord Metric" do
|
18
|
-
|
19
18
|
after do
|
20
|
-
Sky.
|
19
|
+
Sky.connection.drop_table(:skies) if Sky.connection.table_exists?(Sky.table_name)
|
21
20
|
Sky.reset_callbacks(:create)
|
22
21
|
Sky.reset_callbacks(:save)
|
23
22
|
end
|
@@ -236,7 +235,7 @@ describe "ActiveRecord Metric" do
|
|
236
235
|
assert_equal 2, times
|
237
236
|
end
|
238
237
|
|
239
|
-
it "do it
|
238
|
+
it "do it yourself" do
|
240
239
|
File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
|
241
240
|
f.write <<-RUBY
|
242
241
|
metric "Sky is limit" do
|
data/test/playground_test.rb
CHANGED
@@ -49,13 +49,15 @@ describe Vanity::Playground do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
describe "
|
53
|
-
it "reconnects with
|
52
|
+
describe "reconnect!" do
|
53
|
+
it "reconnects with the same configuration" do
|
54
54
|
Vanity.playground.establish_connection "mock:/"
|
55
55
|
Vanity.playground.reconnect!
|
56
56
|
assert_equal Vanity.playground.connection.to_s, "mock:/"
|
57
57
|
end
|
58
|
+
end
|
58
59
|
|
60
|
+
describe "autoconnect" do
|
59
61
|
it "establishes connection by default with connection" do
|
60
62
|
instance = Vanity::Playground.new(:connection=>"mock:/")
|
61
63
|
assert instance.connected?
|
data/test/test_helper.rb
CHANGED
@@ -70,7 +70,7 @@ module VanityTestHelpers
|
|
70
70
|
# or reload an experiment (saved by the previous playground).
|
71
71
|
def new_playground
|
72
72
|
Vanity.playground = Vanity::Playground.new(:logger=>$logger, :load_path=>"tmp/experiments")
|
73
|
-
Vanity.playground.establish_connection(DATABASE)
|
73
|
+
Vanity.playground.establish_connection(DATABASE) unless Vanity.playground.connected?
|
74
74
|
end
|
75
75
|
|
76
76
|
# Defines the specified metrics (one or more names). Returns metric, or array
|
@@ -107,7 +107,7 @@ module VanityTestHelpers
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def dummy_request
|
110
|
-
|
110
|
+
ActionDispatch::TestRequest.new()
|
111
111
|
end
|
112
112
|
|
113
113
|
# Defining setup/tear down in a module and including it below doesn't
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-08-
|
12
|
+
date: 2014-08-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -104,7 +104,6 @@ files:
|
|
104
104
|
- lib/vanity/backport.rb
|
105
105
|
- lib/vanity/commands/list.rb
|
106
106
|
- lib/vanity/commands/report.rb
|
107
|
-
- lib/vanity/commands/upgrade.rb
|
108
107
|
- lib/vanity/experiment/ab_test.rb
|
109
108
|
- lib/vanity/experiment/alternative.rb
|
110
109
|
- lib/vanity/experiment/base.rb
|
@@ -163,11 +162,6 @@ files:
|
|
163
162
|
- test/dummy/script/rails
|
164
163
|
- test/experiment/ab_test.rb
|
165
164
|
- test/experiment/base_test.rb
|
166
|
-
- test/experiments/age_and_zipcode.rb
|
167
|
-
- test/experiments/metrics/cheers.rb
|
168
|
-
- test/experiments/metrics/signups.rb
|
169
|
-
- test/experiments/metrics/yawns.rb
|
170
|
-
- test/experiments/null_abc.rb
|
171
165
|
- test/frameworks/rails/action_controller_test.rb
|
172
166
|
- test/frameworks/rails/action_mailer_test.rb
|
173
167
|
- test/frameworks/rails/action_view_test.rb
|
@@ -187,7 +181,7 @@ licenses:
|
|
187
181
|
post_install_message: To get started run vanity --help
|
188
182
|
rdoc_options:
|
189
183
|
- --title
|
190
|
-
- Vanity 2.0.0.
|
184
|
+
- Vanity 2.0.0.beta4
|
191
185
|
- --main
|
192
186
|
- README.rdoc
|
193
187
|
- --webcvs
|
@@ -244,11 +238,6 @@ test_files:
|
|
244
238
|
- test/dummy/script/rails
|
245
239
|
- test/experiment/ab_test.rb
|
246
240
|
- test/experiment/base_test.rb
|
247
|
-
- test/experiments/age_and_zipcode.rb
|
248
|
-
- test/experiments/metrics/cheers.rb
|
249
|
-
- test/experiments/metrics/signups.rb
|
250
|
-
- test/experiments/metrics/yawns.rb
|
251
|
-
- test/experiments/null_abc.rb
|
252
241
|
- test/frameworks/rails/action_controller_test.rb
|
253
242
|
- test/frameworks/rails/action_mailer_test.rb
|
254
243
|
- test/frameworks/rails/action_view_test.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Vanity
|
2
|
-
module Commands
|
3
|
-
class << self
|
4
|
-
# Upgrade to newer version of Vanity (this usually means doing magic in
|
5
|
-
# the database)
|
6
|
-
def upgrade
|
7
|
-
if Vanity.playground.connection.respond_to?(:redis)
|
8
|
-
redis = Vanity.playground.connection.redis
|
9
|
-
# Upgrade metrics from 1.3 to 1.4
|
10
|
-
keys = redis.keys("metrics:*")
|
11
|
-
if keys.empty?
|
12
|
-
puts "No metrics to upgrade"
|
13
|
-
else
|
14
|
-
puts "Updating #{keys.map { |name| name.split(":")[1] }.uniq.length} metrics"
|
15
|
-
keys.each do |key|
|
16
|
-
key << ":value:0" if key[/\d{4}-\d{2}-\d{2}$/]
|
17
|
-
redis.renamenx key, "vanity:#{key}"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
# Upgrade experiments from 1.3 to 1.4
|
21
|
-
keys = redis.keys("vanity:1:*")
|
22
|
-
if keys.empty?
|
23
|
-
puts "No experiments to upgrade"
|
24
|
-
else
|
25
|
-
puts "Updating #{keys.map { |name| name.split(":")[2] }.uniq.length} experiments"
|
26
|
-
keys.each do |key|
|
27
|
-
redis.renamenx key, key.gsub(":1:", ":experiments:")
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
ab_test "Age and Zipcode" do
|
2
|
-
description <<-TEXT
|
3
|
-
Testing new registration form that asks for age and zipcode. Option A presents
|
4
|
-
the existing form, and option B adds age and zipcode fields.
|
5
|
-
|
6
|
-
We know option B will convert less, but higher quality leads. If we lose less
|
7
|
-
than 20% conversions, we're going to switch to option B.
|
8
|
-
TEXT
|
9
|
-
metrics :signups
|
10
|
-
|
11
|
-
complete_if do
|
12
|
-
alternatives.all? { |alt| alt.participants > 100 }
|
13
|
-
end
|
14
|
-
outcome_is do
|
15
|
-
one_field = alternative(false)
|
16
|
-
three_fields = alternative(true)
|
17
|
-
three_fields.conversion_rate >= 0.8 * one_field.conversion_rate ? three_fields : one_field
|
18
|
-
end
|
19
|
-
end
|