vanity 2.0.0.beta3 → 2.0.0.beta4
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/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
|