vanity 2.0.1 → 2.1.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/Appraisals +6 -6
- data/CHANGELOG +9 -3
- data/Gemfile.lock +1 -1
- data/README.md +299 -0
- data/doc/configuring.textile +8 -1
- data/doc/identity.textile +2 -0
- data/doc/metrics.textile +10 -0
- data/gemfiles/rails32.gemfile.lock +1 -1
- data/gemfiles/rails41.gemfile.lock +1 -1
- data/gemfiles/rails42.gemfile.lock +1 -1
- data/gemfiles/{rails4.gemfile → rails42_protected_attributes.gemfile} +2 -2
- data/gemfiles/rails42_protected_attributes.gemfile.lock +209 -0
- data/lib/generators/templates/vanity_migration.rb +1 -0
- data/lib/vanity/adapters/abstract_adapter.rb +11 -0
- data/lib/vanity/adapters/active_record_adapter.rb +15 -1
- data/lib/vanity/adapters/mock_adapter.rb +14 -0
- data/lib/vanity/adapters/mongodb_adapter.rb +14 -0
- data/lib/vanity/adapters/redis_adapter.rb +15 -0
- data/lib/vanity/configuration.rb +43 -11
- data/lib/vanity/experiment/ab_test.rb +145 -15
- data/lib/vanity/experiment/alternative.rb +4 -0
- data/lib/vanity/frameworks/rails.rb +69 -31
- data/lib/vanity/locales/vanity.en.yml +9 -0
- data/lib/vanity/locales/vanity.pt-BR.yml +4 -0
- data/lib/vanity/metric/active_record.rb +9 -1
- data/lib/vanity/templates/_ab_test.erb +9 -2
- data/lib/vanity/templates/_experiment.erb +21 -1
- data/lib/vanity/templates/vanity.css +11 -3
- data/lib/vanity/templates/vanity.js +35 -6
- data/lib/vanity/version.rb +1 -1
- data/test/commands/report_test.rb +1 -0
- data/test/dummy/config/application.rb +1 -0
- data/test/experiment/ab_test.rb +414 -0
- data/test/experiment/base_test.rb +16 -10
- data/test/frameworks/rails/action_controller_test.rb +14 -6
- data/test/frameworks/rails/action_mailer_test.rb +8 -6
- data/test/frameworks/rails/action_view_test.rb +1 -0
- data/test/helper_test.rb +2 -0
- data/test/metric/active_record_test.rb +56 -0
- data/test/playground_test.rb +3 -0
- data/test/test_helper.rb +28 -2
- data/test/web/rails/dashboard_test.rb +2 -0
- data/vanity.gemspec +2 -2
- metadata +8 -8
- data/README.rdoc +0 -231
- data/gemfiles/rails4.gemfile.lock +0 -179
@@ -49,6 +49,8 @@ module Vanity
|
|
49
49
|
@ar_timestamp, @ar_timestamp_table = @ar_timestamp.to_s.split('.').reverse
|
50
50
|
@ar_timestamp_table ||= @ar_scoped.table_name
|
51
51
|
|
52
|
+
@ar_identity_block = options.delete(:identity)
|
53
|
+
|
52
54
|
fail "Unrecognized options: #{options.keys * ", "}" unless options.empty?
|
53
55
|
|
54
56
|
@ar_scoped.after_create(self)
|
@@ -99,7 +101,13 @@ module Vanity
|
|
99
101
|
def after_create(record)
|
100
102
|
return unless @playground.collecting?
|
101
103
|
count = @ar_column ? (record.send(@ar_column) || 0) : 1
|
102
|
-
|
104
|
+
|
105
|
+
identity = Vanity.context.vanity_identity rescue nil
|
106
|
+
identity ||= if @ar_identity_block
|
107
|
+
@ar_identity_block.call(record)
|
108
|
+
end
|
109
|
+
|
110
|
+
call_hooks record.send(@ar_timestamp), identity, [count] if count > 0 && @ar_scoped.exists?(record.id)
|
103
111
|
end
|
104
112
|
end
|
105
113
|
end
|
@@ -2,10 +2,17 @@
|
|
2
2
|
<table>
|
3
3
|
<caption>
|
4
4
|
<%= experiment.conclusion(score).join(" ") %>
|
5
|
+
<% if experiment.active? && !experiment.enabled? %>
|
6
|
+
<div class='disabled_info'><%=I18n.t('vanity.experiment_has_been_disabled', name: experiment.default.name)%></div>
|
7
|
+
<% end %>
|
5
8
|
</caption>
|
6
9
|
<% score.alts.each do |alt| %>
|
7
10
|
<tr class="<%= "choice" if score.choice == alt %>">
|
8
|
-
<td class="option"><%= alt.name.gsub(/^o/, "O")
|
11
|
+
<td class="option"><%= alt.name.gsub(/^o/, "O") %>:
|
12
|
+
<% if alt.default? %>
|
13
|
+
<div class='default'><%=I18n.t('vanity.default')%></div>
|
14
|
+
<% end %>
|
15
|
+
</td>
|
9
16
|
<td class="value"><code><%=vanity_h alt.value.to_s %></code></td>
|
10
17
|
<td class="value"><%= I18n.t 'vanity.participants', :count=>alt.participants %></td>
|
11
18
|
<td class="value"><%= I18n.t 'vanity.converted', :count=>alt.converted %></td>
|
@@ -14,7 +21,7 @@
|
|
14
21
|
<%= I18n.t('vanity.best_alternative', :probabilty=>alt.probability.to_i) if score.method == :bayes_score %>
|
15
22
|
<%= I18n.t('vanity.better_alternative_than', :probability=>alt.difference.to_i, :alternative=>score.least.name) if alt.difference && alt.difference >= 1 %>
|
16
23
|
</td>
|
17
|
-
<% if experiment.active? && respond_to?(:url_for) %>
|
24
|
+
<% if experiment.enabled? && experiment.active? && respond_to?(:url_for) %>
|
18
25
|
<td class="action">
|
19
26
|
<small>
|
20
27
|
<% if experiment.showing?(alt) %>
|
@@ -1,4 +1,24 @@
|
|
1
|
-
|
1
|
+
<% if experiment.active? %>
|
2
|
+
<% status = experiment.enabled? ? 'status_enabled' : 'status_disabled' %>
|
3
|
+
<% else %>
|
4
|
+
<% status = 'status_completed' %>
|
5
|
+
<% end %>
|
6
|
+
<div class="inner <%= status %>">
|
7
|
+
<h3>
|
8
|
+
<%=vanity_h experiment.name %><span class="type">(<%= experiment.class.friendly_name %>)</span>
|
9
|
+
<% if experiment.type == 'ab_test' && experiment.active? && experiment.playground.collecting? %>
|
10
|
+
<span class='enabled-links'>
|
11
|
+
<% action = experiment.enabled? ? :disable : :enable %>
|
12
|
+
|
13
|
+
<% if experiment.enabled? %> <%= I18n.t( 'vanity.enabled' ) %> | <% end %>
|
14
|
+
<a title='<%=I18n.t( action, scope: 'vanity.act_on_this_experiment' )%>' href='#'
|
15
|
+
data-id='<%= experiment.id %>' data-url='<%= url_for(:action=>action, :e => experiment.id) %>'>
|
16
|
+
<%= action %></a>
|
17
|
+
<% if !experiment.enabled? %> | <%= I18n.t( 'vanity.disabled' ) %> <% end %>
|
18
|
+
|
19
|
+
</span>
|
20
|
+
<% end %>
|
21
|
+
</h3>
|
2
22
|
<%= experiment.description.to_s.split(/\n\s*\n/).map { |para| vanity_html_safe(%{<p class="description">#{vanity_h para}</p>}) }.join.html_safe %>
|
3
23
|
<% if flash.notice %>
|
4
24
|
<p>
|
@@ -7,14 +7,22 @@
|
|
7
7
|
.vanity .experiments { list-style: none; margin: 0; padding: 0 }
|
8
8
|
.vanity .experiment { margin: 1em 0 2em 0; border-bottom: 1px solid #ddd }
|
9
9
|
.vanity .experiment .type { margin-left: .3em; color: #bbb; font-size: .8em; font-weight: normal }
|
10
|
+
.vanity .experiment .inner {padding: 1em}
|
11
|
+
.vanity .experiment .status_completed { background: #EEF }
|
12
|
+
.vanity .experiment .status_enabled { background: #EFE }
|
13
|
+
.vanity .experiment .status_disabled { background: #FEE }
|
14
|
+
.vanity .experiment .enabled-links { float: right; font-weight: normal }
|
10
15
|
|
11
16
|
.vanity .ab_test table { border-collapse: collapse; table-layout: fixed; width: 100%; border-bottom: 1px solid #ccc; margin: 1em 0 0 0 }
|
12
17
|
.vanity .ab_test td { padding: .5em; border-top: 1px solid #ccc; width: 2em; overflow: hidden }
|
13
18
|
.vanity .ab_test .choice td { font-weight: bold; background: #f0f0f8 }
|
14
19
|
.vanity .ab_test caption { caption-side: bottom; padding: .5em; background: transparent; text-align: left }
|
15
|
-
.vanity .ab_test
|
16
|
-
.vanity .ab_test td.
|
17
|
-
.vanity .ab_test td.
|
20
|
+
.vanity .ab_test caption .disabled_info { padding-top: .5em }
|
21
|
+
.vanity .ab_test td.option { width: 5em; white-space: nowrap; overflow: hidden }
|
22
|
+
.vanity .ab_test td.option .default { font-size: 75% }
|
23
|
+
.vanity .ab_test td.value { width: 8em; white-space: nowrap; overflow: hidden }
|
24
|
+
.vanity .ab_test td.action { width: 6em; overflow: hidden; text-align: right }
|
25
|
+
.vanity .ab_test button.reset { float: right }
|
18
26
|
|
19
27
|
.vanity .metrics { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid #ddd }
|
20
28
|
.vanity .metric { margin: 2em 0 }
|
@@ -70,13 +70,42 @@ $(function() {
|
|
70
70
|
});
|
71
71
|
});
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
function post_on_click(sel) {
|
74
|
+
$(sel).live("click", function() {
|
75
|
+
var link = $(this);
|
76
|
+
$.ajax({
|
77
|
+
data: 'authenticity_token=' + encodeURIComponent(document.auth_token),
|
78
|
+
success: function(request){ $('#experiment_' + link.attr("data-id")).html(request) },
|
79
|
+
url: link.attr("data-url"), type: 'post'
|
80
|
+
});
|
81
|
+
return false;
|
79
82
|
});
|
83
|
+
}
|
84
|
+
|
85
|
+
post_on_click(".experiment.ab_test a.button.chooses");
|
86
|
+
post_on_click(".experiment.ab_test .enabled-links a");
|
87
|
+
|
88
|
+
$(".experiment button.reset").live("click", function() {
|
89
|
+
if (confirm('Are you sure you want to reset the experiment? This will clear all collected data so far and restart the experiment from scratch. This cannot be undone.')){
|
90
|
+
var link = $(this);
|
91
|
+
$.ajax({
|
92
|
+
data: 'authenticity_token=' + encodeURIComponent(document.auth_token),
|
93
|
+
success: function(request){ $('#experiment_' + link.attr("data-id")).html(request) },
|
94
|
+
url: link.attr("data-url"), type: 'post'
|
95
|
+
});
|
96
|
+
}
|
97
|
+
return false;
|
98
|
+
});
|
99
|
+
|
100
|
+
$(".experiment button.finish").live("click", function() {
|
101
|
+
var link = $(this);
|
102
|
+
if (confirm('Are you sure you want to complete the experiment and set ' + link.attr("alt-name") + ' as the outcome?')){
|
103
|
+
$.ajax({
|
104
|
+
data: 'authenticity_token=' + encodeURIComponent(document.auth_token),
|
105
|
+
success: function(request){ $('#experiment_' + link.attr("data-id")).html(request) },
|
106
|
+
url: link.attr("data-url"), type: 'post'
|
107
|
+
});
|
108
|
+
}
|
80
109
|
return false;
|
81
110
|
});
|
82
111
|
|
data/lib/vanity/version.rb
CHANGED
@@ -40,6 +40,7 @@ module Dummy
|
|
40
40
|
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
|
41
41
|
# parameters by using an attr_accessible or attr_protected declaration.
|
42
42
|
config.active_record.whitelist_attributes = true if ActiveRecord::Base.respond_to?(:whitelist_attributes=)
|
43
|
+
config.active_record.mass_assignment_sanitizer = :strict if defined?(ProtectedAttributes)
|
43
44
|
|
44
45
|
# Configure the default encoding used in templates for Ruby 1.9.
|
45
46
|
config.encoding = "utf-8"
|