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 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
- gem install mountain-goat
10
-
11
- #Note, you'll need to install the proper migrations (currently in the migrations folder, task coming shortly)
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
- Mountain Goat hinges around three core concepts:
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
- 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.
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
- <h2><%= metric_variant(:banner_on_store_front, :user_purchases_coffee, "Now arsenic and gluten-free") %></h2>
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
- The metric_variant function (or mv for short) takes three parameters:
57
+ <h2><%= metric_variant(:banner_on_store_front, :user_purchases_coffee, "Now arsenic and gluten-free") %></h2>
26
58
 
27
- mv(metric_name, convert_name, default)
59
+ The metric_variant function (or, mv for short) takes three parameters:
28
60
 
29
- This will automatically create a metric and conversion and populate a metric variant with the default value. Easy, eh?
61
+ mv(metric_name, convert_name, default)
30
62
 
31
- From here, you can go into the mountain-goat admin center and add new metric variants to fit your need.
63
+ This will automatically create a metric and conversion and populate a metric variant with the default value. Easy, eh?
32
64
 
33
- The other important code you'll need to implement is when a goal is achieved.
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
- def purchase #coffees_controller.rb
36
- record_conversion(:user_purchases_coffee)
37
- ...
38
- end
67
+ def purchase #coffees_controller.rb
68
+ record_conversion(:user_purchases_coffee)
69
+ ...
70
+ end
39
71
 
40
- 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.
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
- Navigate to /mg in your application to reach the mountain-goat admin center. Here, you can analyze / adjust your A/B tests.
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
- 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.
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
- ### Meta data
82
+ ### Meta data
51
83
 
52
- You can track meta-data with any conversion. E.g.
84
+ You can track meta-data with any conversion. E.g.
53
85
 
54
- rc(:user_visit, :referring_domain => request.env['HTTP_REFERER'], :user_id => session[:user_id])
86
+ rc(:user_visit, :referring_domain => request.env['HTTP_REFERER'], :user_id => session[:user_id])
55
87
 
56
- These will be stored with the rally for the conversion and can get used for complex analytics down the line. (see Converts.meta)
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
- ### Switch variants
90
+ ### Switch variants
59
91
 
60
- Instead of just serving text, you can also serve flow control in Mountain Goat, like so:
92
+ Instead of just serving text, you can also serve flow control in Mountain Goat, like so:
61
93
 
62
- sv(:user_discount, :purchase_coffee) do |variant|
63
- variant.ten_percent do
64
- discount = 0.10
65
- end
94
+ sv(:user_discount, :purchase_coffee) do |variant|
66
95
 
67
- variant.big_winner do
68
- discount = 0.90
69
- end
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
- variant.whomp_whomp do
72
- discount = 0.0
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
- 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.
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
- ### Priorities
111
+ ### Priorities
79
112
 
80
- 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
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
- my priority / sum(all priorities for this metric)
115
+ my priority / sum(all priorities for this metric)
83
116
 
84
117
  ## TODO
85
- - work on getting migrations better
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.
@@ -26,6 +26,7 @@ class MountainGoatController < ActionController::Base
26
26
 
27
27
  def verify_access
28
28
  return if session.has_key?(:mg_access) && session[:mg_access] == true
29
+ store_location
29
30
  redirect_to '/mg/login' and return
30
31
  end
31
32
 
@@ -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
  })();
@@ -1,3 +1,3 @@
1
1
  class MountainGoat
2
- VERSION = "0.0.17"
2
+ VERSION = "0.0.18"
3
3
  end
@@ -0,0 +1,9 @@
1
+ <%# locals => rally %>
2
+
3
+ <li><%= rally.convert.name %> at <%= rally.created_at.to_s %>
4
+ (
5
+ <% rally.all_metas.each do |k,v| %>
6
+ <%= k %>: <%= v %>
7
+ <% end %>
8
+ )
9
+ </li>
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5
+ <title>Untitled Document</title>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -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>
@@ -0,0 +1,5 @@
1
+ <%# locals => rallies %>
2
+
3
+ <% rallies.each do |rally| %>
4
+ <%= render :partial => 'mountain_goat_rallies/rally', :locals => { :rally => rally } %>
5
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%# locals => rally %>
2
+
3
+ <li><%= rally.convert.name %> at <%= rally.created_at.to_s %>
4
+ (
5
+ <% rally.all_metas.each do |k,v| %>
6
+ <%= k %>: <%= v %>
7
+ <% end %>
8
+ )
9
+ </li>
@@ -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
- <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
- )
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: 61
4
+ hash: 59
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 17
10
- version: 0.0.17
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