mountain-goat 0.0.17 → 0.0.18
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/README.md +78 -44
- data/lib/mountain-goat/controllers/mountain_goat/mountain_goat_controller.rb +1 -0
- data/lib/mountain-goat/controllers/mountain_goat/mountain_goat_rallies_controller.rb +20 -0
- data/lib/mountain-goat/metric_tracking.rb +1 -0
- data/lib/mountain-goat/public/mg.js +33 -0
- data/lib/mountain-goat/version.rb +1 -1
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp__rallies.html.erb.83814~ +9 -0
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp__rally.html.erb.62757~ +9 -0
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp_index.html.erb.1823~ +22 -0
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/_rallies.html.erb +5 -0
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/_rally.html.erb +9 -0
- data/lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/index.html.erb +5 -7
- metadata +8 -3
data/README.md
CHANGED
@@ -2,88 +2,122 @@
|
|
2
2
|
|
3
3
|
Embed a high-quality analytics platform in your application in minutes. Gain important A/B test business insights, and view the results and analytics in real time.
|
4
4
|
|
5
|
+
Add simple hooks in your code to display a/b metrics
|
6
|
+
|
7
|
+
<%= metric_variant(:homescreen_text, :user_signup, "Welcome here") %>
|
8
|
+
|
9
|
+
This creates a database entry to a/b test "homescreen_text" against a goal "user signup". Visit "http://yourdomain.com/mg" and you can add / adjust options (variants) for this text. When a user converts on this goal, you run the following code.
|
10
|
+
|
11
|
+
def create
|
12
|
+
record_conversion(:user_signup)
|
13
|
+
...
|
14
|
+
end
|
15
|
+
|
16
|
+
This will track a conversion not only for the goal, but for the variant of "homescreen_text" (and any other associated metrics) that the user was served when he came to the home-page.
|
17
|
+
|
18
|
+
The best part? The mountain-goat admin console is located on your server and you can view and analyze your data in real time.
|
19
|
+
|
20
|
+
- See which metric variants are working and not working ("Cowabunga!" did 120% better than "Enter here", but 10% worse than "Do it rockapella!")
|
21
|
+
- Visually analyze the your metric variants; change them on the fly, adding new ones.
|
22
|
+
- Watch goal conversions in real-time with live-action console (grab the popcorn and watch how your users "sign up" and "view items" and ...)
|
23
|
+
- You can do more than change text, "switch variants" let you enter arbitrary ruby code, change the control of your site ("Do my users have to sign-in before commenting? Let's test!")
|
24
|
+
- Track goals with meta data (record_conversion(:user_signup, :referrer => request.env['HTTP_REFERER']))
|
25
|
+
* Mountain goat tracks as much arbitrary meta data as you want
|
26
|
+
* You are presented with charts for each goal, broken down by meta
|
27
|
+
* See what referrers are driving goals, or which of your blog posts are drawing an audience
|
28
|
+
- Much, much more, e.g. deliver views of this data to your consumers, streamline your site, customize it by user, it's all up to you.
|
29
|
+
|
5
30
|
## Install
|
6
31
|
|
7
32
|
### Mountain Goat gem
|
8
33
|
|
9
|
-
|
10
|
-
|
11
|
-
|
34
|
+
gem install mountain-goat
|
35
|
+
|
36
|
+
### Mountain Goat configration
|
37
|
+
|
38
|
+
Next run generator to create config file and necessary database migration (optionally pass in --password=my_mg_password)
|
39
|
+
|
40
|
+
./script/generate mg
|
41
|
+
|
42
|
+
This will generate
|
43
|
+
|
44
|
+
/config/mountain-goat.yml (for storing a password to access mountain-goat)
|
45
|
+
/db/migrate/xxx_create_mountain_goat_tables.rb (necessary databae migrations to store mg data)
|
12
46
|
|
13
47
|
## Usage
|
14
48
|
|
15
|
-
|
16
|
-
|
17
|
-
*) Conversions are what you want E.g. "user purchases coffee"
|
18
|
-
*) Metrics are how you draw people to convert E.g. "a banner on the store-front"
|
19
|
-
*) Metric variants are A/B tests for metrics E.g. "free coffee" "chuck norris is inside"
|
49
|
+
Mountain Goat hinges around three core concepts:
|
20
50
|
|
21
|
-
|
51
|
+
- Conversions are what you want E.g. "user purchases coffee"
|
52
|
+
- Metrics are how you draw people to convert E.g. "a banner on the store-front"
|
53
|
+
- Metric variants are A/B tests for metrics E.g. "free coffee" "chuck norris is inside"
|
22
54
|
|
23
|
-
|
55
|
+
After you set up your database with some mountain-goat tables, the code will handle populating these tables for you. In your code, you can start A/B testing immediately.
|
24
56
|
|
25
|
-
|
57
|
+
<h2><%= metric_variant(:banner_on_store_front, :user_purchases_coffee, "Now arsenic and gluten-free") %></h2>
|
26
58
|
|
27
|
-
|
59
|
+
The metric_variant function (or, mv for short) takes three parameters:
|
28
60
|
|
29
|
-
|
61
|
+
mv(metric_name, convert_name, default)
|
30
62
|
|
31
|
-
|
63
|
+
This will automatically create a metric and conversion and populate a metric variant with the default value. Easy, eh?
|
32
64
|
|
33
|
-
|
65
|
+
From here, you can go into the mountain-goat admin center and add new metric variants to fit your need. The other important code you'll need to implement is when a goal is achieved.
|
34
66
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
67
|
+
def purchase #coffees_controller.rb
|
68
|
+
record_conversion(:user_purchases_coffee)
|
69
|
+
...
|
70
|
+
end
|
39
71
|
|
40
|
-
|
72
|
+
This will go in and record a conversion ("rally") for a user purchasing coffee. Further, it will track a hit for any metric-variants served to that user that relate to this goal. For example "Chuck Norris works here" might get a point.
|
41
73
|
|
42
74
|
## Mountain Goat admin suite
|
43
75
|
|
44
|
-
|
76
|
+
Navigate to /mg in your application to reach the mountain-goat admin center. Here, you can analyze / adjust your A/B tests.
|
45
77
|
|
46
|
-
|
78
|
+
The front page gives you a breakdown of each of your Goals, and the efficacy of each metric and metric-variant. Select a given metric to drill into its variants. Once you are in a specific metric, you'll be able to add new metric-variants and see what works best for your clients.
|
47
79
|
|
48
80
|
## Advanced Features
|
49
81
|
|
50
|
-
|
82
|
+
### Meta data
|
51
83
|
|
52
|
-
|
84
|
+
You can track meta-data with any conversion. E.g.
|
53
85
|
|
54
|
-
|
86
|
+
rc(:user_visit, :referring_domain => request.env['HTTP_REFERER'], :user_id => session[:user_id])
|
55
87
|
|
56
|
-
|
88
|
+
These will be stored with the rally for the conversion and can get used for complex analytics down the line. (see Converts.meta)
|
57
89
|
|
58
|
-
|
90
|
+
### Switch variants
|
59
91
|
|
60
|
-
|
92
|
+
Instead of just serving text, you can also serve flow control in Mountain Goat, like so:
|
61
93
|
|
62
|
-
|
63
|
-
variant.ten_percent do
|
64
|
-
discount = 0.10
|
65
|
-
end
|
94
|
+
sv(:user_discount, :purchase_coffee) do |variant|
|
66
95
|
|
67
|
-
|
68
|
-
|
69
|
-
|
96
|
+
variant.ten_percent do # "ten_percent" is the variant-name
|
97
|
+
discount = 0.10
|
98
|
+
end
|
99
|
+
|
100
|
+
variant.big_winner do
|
101
|
+
discount = 0.90
|
102
|
+
end
|
70
103
|
|
71
|
-
|
72
|
-
|
104
|
+
variant.whomp_whomp(0.5) do #reduce priority to 0.5 (default 1.0)
|
105
|
+
discount = 0.0
|
106
|
+
end
|
73
107
|
end
|
74
|
-
end
|
75
108
|
|
76
|
-
|
109
|
+
Mountain goat will automatically break those down into three cases (:ten_percent, :big_winner, :whomp_whomp) and serve them out at random to the user (with whomp_whomp half as likely to be served as the others).
|
77
110
|
|
78
|
-
|
111
|
+
### Priorities
|
79
112
|
|
80
|
-
|
113
|
+
You may want to test certain items with a lower serve rate (bold new slogans). You can assign priorities to any metric variant. The change of a given metric variant being shown is
|
81
114
|
|
82
|
-
|
115
|
+
my priority / sum(all priorities for this metric)
|
83
116
|
|
84
117
|
## TODO
|
85
|
-
-
|
118
|
+
- Better documentation (rdocs)
|
119
|
+
- Add namespacing to avoid conflicts
|
86
120
|
|
87
121
|
## Copyright
|
88
122
|
|
89
|
-
Copyright (c) 2011 Geoffrey Hayes, drawn.to. See LICENSE for details.
|
123
|
+
Copyright (c) 2011 Geoffrey Hayes, drawn.to. Contact me, Geoff, <geoff@drawn.to> with any questions / ideas / enhacements. See LICENSE for details.
|
@@ -15,4 +15,24 @@ class MountainGoatRalliesController < MountainGoatController
|
|
15
15
|
format.html { }
|
16
16
|
end
|
17
17
|
end
|
18
|
+
|
19
|
+
def new_rallies
|
20
|
+
recent_rally = params[:recent_rally].to_i
|
21
|
+
convert = Convert.find(params[:convert_id].to_i) unless params[:convert_id].blank?
|
22
|
+
|
23
|
+
if convert
|
24
|
+
@rallies = convert.rallies.find(:all, :conditions => [ 'id > ?', recent_rally ], :order => "created_at DESC" )
|
25
|
+
else
|
26
|
+
@rallies = Rally.find(:all, :conditions => [ 'id > ?', recent_rally ], :order => "created_at DESC" )
|
27
|
+
end
|
28
|
+
|
29
|
+
if @rallies.count > 0
|
30
|
+
render :json => { :success => true,
|
31
|
+
:result => render_to_string(:partial => 'mountain_goat_rallies/rallies', :locals => { :rallies => @rallies } ),
|
32
|
+
:recent_rally_id => @rallies.first.id }
|
33
|
+
else
|
34
|
+
render :json => { :success => false }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
18
38
|
end
|
@@ -17,6 +17,7 @@ module MetricTracking
|
|
17
17
|
map.resources :mountain_goat_converts, :has_many => [ :mountain_goat_metrics, :mountain_goat_rallies ]
|
18
18
|
map.resources :mountain_goat_metrics, :has_many => :mountain_goat_metric_variants
|
19
19
|
map.resources :mountain_goat_rallies
|
20
|
+
map.new_rallies '/mg/rallies/new', :controller => :mountain_goat_rallies, :action => :new_rallies
|
20
21
|
map.fresh_metrics '/fresh-metrics', :controller => :mountain_goat_metrics, :action => :fresh_metrics
|
21
22
|
map.connect '/mg/public/:file', :controller => :mountain_goat, :action => :fetch
|
22
23
|
end
|
@@ -11,5 +11,38 @@
|
|
11
11
|
$($(this).data('slider')).slideUp();
|
12
12
|
}
|
13
13
|
}).change();
|
14
|
+
|
15
|
+
if ($('.recent-rally[data-reload="true"]').size() > 0) {
|
16
|
+
setTimeout(function() { reloadRallies(); }, 3000);
|
17
|
+
}
|
18
|
+
|
19
|
+
$('.reload').click(function() { reloadRallies(); });
|
20
|
+
|
21
|
+
var reloadRallies = function() {
|
22
|
+
var rally_id = parseInt($('.recent-rally').data('rally-id'));
|
23
|
+
var convert_id = $('.recent-rally').data('convert-id');
|
24
|
+
if (rally_id) {
|
25
|
+
$.ajax({
|
26
|
+
url: '/mg/rallies/new',
|
27
|
+
data: { 'recent_rally': rally_id, 'convert_id': convert_id },
|
28
|
+
success: function(json) {
|
29
|
+
if (!json.success) {
|
30
|
+
console.log('No new events');
|
31
|
+
} else {
|
32
|
+
$('.recent-rally').data('rally-id', json.recent_rally_id);
|
33
|
+
$('.rally-list').prepend($(json.result));
|
34
|
+
|
35
|
+
$('.rally-list li:gt(100)').remove(); //only show 100 elements
|
36
|
+
}
|
37
|
+
|
38
|
+
if ($('.recent-rally[data-reload="true"]').size() > 0) {
|
39
|
+
setTimeout(function() { reloadRallies(); }, 3000);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
});
|
43
|
+
}
|
44
|
+
};
|
14
45
|
});
|
46
|
+
|
47
|
+
|
15
48
|
})();
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
<div id="container-main" class="mt-rallies">
|
4
|
+
<div class="mountain-goat-panel">
|
5
|
+
<h1>Rallies <% if @convert %>for <%=h @convert.name %><% else %>for all Goals<% end %></h1>
|
6
|
+
|
7
|
+
<% if @rallies.count > 0 %>
|
8
|
+
<ul>
|
9
|
+
<% @rallies.each do |rally| %>
|
10
|
+
<li><%= rally.convert.name %> at <%= rally.created_at.to_s %></li>
|
11
|
+
(
|
12
|
+
<% rally.all_metas.each do |k,v| %>
|
13
|
+
<%= k %>: <%= v %>
|
14
|
+
<% end %>
|
15
|
+
)
|
16
|
+
<% end %>
|
17
|
+
</ul>
|
18
|
+
<% else %>
|
19
|
+
<h2>No rallies for yet this goal.</h2>
|
20
|
+
<% end %>
|
21
|
+
</div>
|
22
|
+
</div>
|
@@ -4,15 +4,13 @@
|
|
4
4
|
<div class="mountain-goat-panel">
|
5
5
|
<h1>Rallies <% if @convert %>for <%=h @convert.name %><% else %>for all Goals<% end %></h1>
|
6
6
|
|
7
|
+
<div class="recent-rally" data-reload="true" data-rally-id="<%= @rallies.first.id %>" data-convert-id="<%= @convert ? @convert.id : '' %>"></div>
|
8
|
+
<a href="javascript:void(0)" class="reload">Reload</a>
|
9
|
+
|
7
10
|
<% if @rallies.count > 0 %>
|
8
|
-
<ul>
|
11
|
+
<ul class="rally-list">
|
9
12
|
<% @rallies.each do |rally| %>
|
10
|
-
|
11
|
-
(
|
12
|
-
<% rally.all_metas.each do |k,v| %>
|
13
|
-
<%= k %>: <%= v %>
|
14
|
-
<% end %>
|
15
|
-
)
|
13
|
+
<%= render 'rally', :rally => rally %>
|
16
14
|
<% end %>
|
17
15
|
</ul>
|
18
16
|
<% else %>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mountain-goat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 59
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 18
|
10
|
+
version: 0.0.18
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Geoffrey Hayes
|
@@ -118,6 +118,11 @@ files:
|
|
118
118
|
- lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/index.html.erb
|
119
119
|
- lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/new.html.erb
|
120
120
|
- lib/mountain-goat/views/mountain_goat/mountain_goat_metrics/show.html.erb
|
121
|
+
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp__rallies.html.erb.83814~
|
122
|
+
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp__rally.html.erb.62757~
|
123
|
+
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/.tmp_index.html.erb.1823~
|
124
|
+
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/_rallies.html.erb
|
125
|
+
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/_rally.html.erb
|
121
126
|
- lib/mountain-goat/views/mountain_goat/mountain_goat_rallies/index.html.erb
|
122
127
|
- mountain-goat.gemspec
|
123
128
|
- test/fixtures/ci_metas.yml
|