gwo 0.1.4

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.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Made by Many
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,127 @@
1
+ NOTE: CURRENTLY THIS WORKS ONLY WITH HAML ... I HAVE TO FIX IT IN ORDER TO GET IT RUNNING WITH ERB
2
+
3
+
4
+ This is a Ruby on Rails plugin (gem) which simplifies Server-Side Dynamic Section Variations with
5
+ [Google Website Optimizer](http://www.google.com/websiteoptimizer) as described in the article
6
+ [Server-Side Dynamic Section Variations on gwotricks.com](http://www.gwotricks.com/2009/05/server-side-dynamic-section-variations.html)
7
+
8
+ == Features:
9
+ ------------
10
+
11
+ * very good Ruby on Rails integration
12
+ * very simple to use
13
+ * support for several sections that should have different variants
14
+ * support for named and numbered sections
15
+ * include part of a page in more than one variant
16
+ * support for google analytics tracking
17
+ * kill-switch
18
+ * well tested
19
+
20
+
21
+ The 'Usage' may look long - but it's fairly straightforward and shouldn't take 5 mins.
22
+
23
+ Daniel Bornkessel gwo@bornkessel.com & Alex MacCaw - alex@madebymany.co.uk (original author)
24
+
25
+ == Usage
26
+ --------
27
+
28
+ To use GWO, you need two pages:
29
+ * A test page containing the multi variant sections
30
+ * A page that signifies conversion (i.e. account creation page)
31
+
32
+ [Signup for Google Website Optimizer and](http://www.google.com/websiteoptimizer):
33
+
34
+ 1. Click create another experiment
35
+ 2. Click multivariate experiment
36
+ 3. Name it and enter the test/conversion urls (if the test will be included on multiple pages (/movies/:id), just choose one of the urls) ... actually the urls you type in don't really matter)
37
+ 4. Select 'You will install and validate the JavaScript tags'
38
+ 5. Ignore the scripts that are offered, but strip out your account id (uacct) and test id (both to be found in the Tracking Script).
39
+ They look like as follows:
40
+ var pageTracker=_gat._getTracker("UI-6882082-1");
41
+ pageTracker._trackPageview("/1662461989/test");
42
+ So, in this example the uacct is 'UA-6882082-1' and the test id is 1662461989.
43
+ 6. Leave google and prepare your source code
44
+ 7. Add the gwo_experiment tag around the code that is supposed to contain the variants (see the gwo_experiment documentation for
45
+ possible options)
46
+ 8. in the gwo_experiment you can specify one or more sections your side can contain. Each section can have several
47
+ variants. So if you have for example 2 sections with each having 3 variants you would have 6 different possible
48
+ combinations on your page.
49
+ 9. Create your gwo_sections, as in the example. The first parameter is the name of the section,
50
+ the second the name of the variant(s) in which the following code should be shown (see example code).
51
+ You can mix variants by just passing in more than one identifier. The
52
+ original variant has the reserved identifier :original (or 0 if you use numbers)
53
+ 10. The variants can either be identified by numbers (starting at 0 for the original variant) or be named (see below how to
54
+ assign the names in the google web interface).
55
+ 11. Add a gwo_conversion helper tag on your conversion page passing in your uacct and test id.
56
+ 12. In order to validate the pages in the goole web interface, start rails, surf to the pages (variant and conversion page) you
57
+ just created and save each one locally.
58
+ 13. back in the google web interface, validate your pages by using the 'offline validation' link and upload the two
59
+ pages you just saved
60
+ 14. as a next step, define the sections. If you used named identifiers in you rails source code, put the the identifiers
61
+ name as the content of the variations in the web interface (i.e. the example below would have two variants (+ the original
62
+ variant); one variation would have the CONTENT (subject & name of the variants are not important) 'minimalistic' and the other
63
+ 'with_sidebar_and_top_signup_box' (without the quotes)). If you use numbered identifiers, just create new variations and leave the
64
+ content empty.
65
+ 15. finish up and start the experiment
66
+ 16. lean back and let google collect data for you for the next few days ... go back an be shocked about the little number of
67
+ conversions you will probably get ;)
68
+
69
+
70
+ == Example
71
+ ----------
72
+ ... in haml:
73
+
74
+ = gwo_experiment("1662461989", "UA-6882082-1", :signup_box_test, :conditions => (signed_up? && country == "de")) do
75
+ = gwo_section(:signup_box_test, [:with_sidebar_and_top_signup_box, :minimalistic], :ga_tracking => true, :conditions => (signed_up? && country == "de")) do
76
+ = render :partial => 'gossib/signup'
77
+ %span I am only visible in the variants :with_sidebar_and_top_signup_box and :minimalistic
78
+
79
+ = gwo_section(:signup_box_test, [:original, :with_sidebar_and_top_signup_box], :conditions => (signed_up? && country == "de")) do
80
+ = render :partial => 'gossib/bookmark_menu'
81
+ = render :partial => 'gossip/pics', :locals => {:images => @article.images}
82
+ .box#
83
+ %span Hi hi ... I am not visible in :minimalistic
84
+
85
+ %span I am visible in every variation
86
+
87
+ = gwo_section(:signup_box_test, :original, :conditions => (signed_up? && country == "de")) do
88
+ %span I am only in the original page
89
+
90
+ ... or in erb:
91
+
92
+ <% gwo_experiment("1662461989", "UA-6882082-1", :signup_box_test, :conditions => (signed_up? && country == "de")) do %>
93
+ <% render :partial => 'gossip/article.html.haml', :object => @article %>
94
+
95
+ <% gwo_section(:signup_box_test, [:with_sidebar_and_top_signup_box, :minimalistic], :conditions => (signed_up? && country == "de")) do %>
96
+ <%= render :partial => 'gossib/signup' %>
97
+ <span> I am only visible in the variants :with_sidebar_and_top_signup_box and :minimalistic</span>
98
+ <% end %>
99
+
100
+ <% gwo_section(:signup_box_test, [:original, :with_sidebar_and_top_signup_box], :conditions => (signed_up? && country == "de")) do %>
101
+ <%= render :partial => 'gossib/bookmark_menu' %>
102
+ <%= render :partial => 'gossip/pics', :locals => {:images => @article.images} %>
103
+ <div class="box">
104
+ <span> Hi hi ... I am not visible in :minimalistic</span>
105
+ <% end %>
106
+
107
+ <span> I am visible in every variation</span>
108
+
109
+ <% gwo_section(:signup_box_test, :original, :conditions => (signed_up? && country == "de")) do %>
110
+ <span> I am only in the original page</span>
111
+ <% end %>
112
+ <% end %>
113
+
114
+
115
+ == Conversion page:
116
+ ------------------
117
+ ... haml:
118
+
119
+ = gwo_conversion('UA-23902382-1', '1909920434')
120
+
121
+ ... erb:
122
+
123
+ <%= gwo_conversion('UA-23902382-1', '1909920434') %>
124
+
125
+
126
+
127
+ Copyright (c) 2009 Made by Many, released under the MIT license
@@ -0,0 +1,235 @@
1
+ # Author:: Alex MacCaw - alex AT madebymany DOT co DOT uk (original), Daniel Bornkessel - daniel AT bornkessel DOT com
2
+ # License:: MIT
3
+ # :include:README.markdown
4
+ #
5
+ #
6
+
7
+ require 'action_view/helpers/capture_helper'
8
+ require 'action_view/helpers/tag_helper'
9
+ module GWO
10
+ module Helper
11
+
12
+ include ::ActionView::Helpers::CaptureHelper
13
+ include ::ActionView::Helpers::TagHelper
14
+
15
+ # start a gwo_experiment
16
+ #
17
+ # Params:
18
+ # * <b>id</b> the id of the experiment (in the google Tracking Script look for something like <tt>pageTracker._trackPageview("/<ID>/test");</tt> )
19
+ # * <b>uacct</b> account number (in the google Tracking Script look for something like <tt>var pageTracker=_gat._getTracker("<UACCT>");</tt> )
20
+ # * <b>sections</b> name of the section(s) your page will include; pass in one symbol/string or an array of symbols/strings here
21
+ # * <b>options</b> hash of possible options:
22
+ # * <b>:conditions</b> if set to false, the experiment won't be executed -- only the source code of the :original (or 0) variants would be shown. No JavaScript code will be produced. It serves as a kill switch for the gwo experiment. If, for example, you only want to execute an experiment for users that are not logged in, you could pass <tt>:conditions => !logged_in?</tt> here.
23
+ # * <b>:google_analytics</b> a hash for google analytics tracking: it will call the google analytics script with either the document.location or a virtual url if you provide it. At the end of the url, gwo appends information about which a/b test was executed and which section was the user had in the form of url parameters (s.th. like <tt> http://&lt;url&gt;?ab_test=&lt;id&gt;&section=&lt;section name &gt; </tt>)
24
+ # * <b>:account_number</b> the google analytics account id where the tracking should take place
25
+ # * <b>:virtual_url</b> if you want to choose a different tracking url then the document.location for tracking
26
+ # * <b>:goal_is_bounce_rate</b> if true, every click on a link on the current view is counted as a goal (NOTE: this includes external links as well)
27
+ def gwo_experiment(id, uacct, sections = [], options = {}, &block)
28
+ options = {
29
+ :conditions => true,
30
+ :goal_is_bounce_rate => false
31
+ }.update(options)
32
+
33
+ src = gwo_start(id, sections, options)
34
+ src += capture(&block) if block
35
+ src += gwo_end(id, uacct, options)
36
+
37
+ if options[:goal_is_bounce_rate]
38
+ src +=<<JS
39
+ <script type="text/javascript"><!--
40
+ function addEvent( obj, type, fn ) {
41
+ if (obj.addEventListener) {
42
+ obj.addEventListener( type, fn, false );
43
+ } else if (obj.attachEvent) {
44
+ obj["e"+type+fn] = fn;
45
+ obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
46
+ obj.attachEvent( "on"+type, obj[type+fn] );
47
+ }
48
+ }
49
+
50
+
51
+ addEvent(document, "click", function(event) {
52
+ if( event.target.nodeName === "A" ) {
53
+ #{js_logger("'bounce rate goal reached'")}
54
+ try {
55
+ var gwoPageTracker=_gat._getTracker("#{uacct}");
56
+ gwoPageTracker._trackPageview("/#{id}/goal");
57
+ }catch(err){}
58
+ }
59
+ });
60
+ #{js_logger("'set goal to bounce rate minimization'")}
61
+ //-->
62
+ </script>
63
+ JS
64
+ end
65
+
66
+ src
67
+ end
68
+
69
+
70
+ # to be included on the conversion page.
71
+ #
72
+ # Params:
73
+ # * <b>id</b> & <b>uacct</b> see gwo_experiment
74
+ # * <b>options</b>
75
+ # * :conditions as in gwo_experiment
76
+ def gwo_conversion(id, uacct, options = {})
77
+ options = {
78
+ :conditions => true
79
+ }.update(options)
80
+
81
+ return js_logger("skipping conversion snippet: a/b variation test switched off", true) if options[:conditions] == false
82
+
83
+ %{
84
+ <script type="text/javascript">
85
+ #{ js_logger("'conversion for test with id #{id} and uacct #{uacct}'") }
86
+ if(typeof(_gat)!='object')document.write('<sc'+'ript src="http'+
87
+ (document.location.protocol=='https:'?'s://ssl':'://www')+
88
+ '.google-analytics.com/ga.js"></sc'+'ript>')</script>
89
+ <script type="text/javascript">
90
+ try {
91
+ var gwoPageTracker=_gat._getTracker("#{uacct}");
92
+ gwoPageTracker._trackPageview("/#{id}/goal");
93
+ }catch(err){}</script>
94
+ }
95
+
96
+ end
97
+
98
+
99
+ # identify a section which is only visible in certain variants
100
+ #
101
+ # Params:
102
+ # * <b>section</b> name of the section
103
+ # * <b>variation_ids</b> identifiers of the variants in which this content is to be shown. Can be either a name of the variant (== the <b><i>content</i></b> of a variant in the GWO web interface) or a number. The original content has the reserved name <tt>:original</tt> or the number <tt>0</tt> respectivly. If the content should be shown in more than one variant, pass in an array of identifiers. Mixing numbered and named variant ids will result in an exception.
104
+ # * <b>options</b>
105
+ # * :conditions as in gwo_experiment
106
+ def gwo_section(section = "gwo_section", variation_ids = nil, options = {}, &block)
107
+ options = {
108
+ :conditions => true
109
+ }.update(options)
110
+
111
+ variation_ids = [*variation_ids].compact
112
+ src = ""
113
+ if is_default_section?(variation_ids)
114
+ if options[:conditions] == false
115
+ src += capture(&block)
116
+ else
117
+ conditions = (named_variations?(variation_ids) ? variation_ids.map{|x| "GWO_#{section}_name != \"#{x}\""} : variation_ids.map{|x| "GWO_#{section}_number != #{x}"}).join(" && ")
118
+
119
+ src += %{ <script>
120
+ if ( #{ conditions } ) document.write('<no' + 'script>');
121
+ </script>
122
+ #{capture(&block) if block_given?}
123
+ </noscript>
124
+ }
125
+ end
126
+ elsif options[:conditions] == true
127
+ if !variation_ids.empty?
128
+ conditions = (named_variations?(variation_ids) ? variation_ids.map{|x| "GWO_#{section}_name == \"#{x}\""} : variation_ids.map{|x| "GWO_#{section}_number == #{x}"}).join(" || ")
129
+
130
+ src += %{<script>
131
+ if ( #{ conditions } ) document.write('</noscript a="');
132
+ </script><!--">
133
+ #{capture(&block) if block_given?}
134
+ <script>document.write('<'+'!'+'-'+'-')</script>-->
135
+ }
136
+ end
137
+ else
138
+ src = js_logger("skipping snippet for #{variation_ids.join(", ")} variations: a/b variation test switched off", true)
139
+ end
140
+ src
141
+ end
142
+
143
+ private
144
+ def js_logger(text, with_js_tag = false)
145
+ return "if(typeof(console.log) == 'function') console.log(#{text});" if RAILS_ENV != "test" && RAILS_ENV != "production" && !with_js_tag
146
+ return "<script type='text/javascript'>if(typeof(console.log) == 'function') console.log(\"#{text}\");</script>" if RAILS_ENV != "test" && RAILS_ENV != "production" && with_js_tag
147
+ return ""
148
+ end
149
+
150
+ def gwo_start(id, sections = [], options = {})
151
+
152
+ return js_logger("skipping start snippet: a/b variation test switched off", true) if options[:conditions] == false
153
+
154
+
155
+ sections = [*sections].compact.empty? ? ["gwo_section"] : [*sections]
156
+ src = %{
157
+ <script type='text/javascript'>
158
+ function utmx_section(){}function utmx(){}
159
+ (function(){var k='#{id}',d=document,l=d.location,c=d.cookie;function f(n){
160
+ if(c){var i=c.indexOf(n+'=');if(i>-1){var j=c.indexOf(';',i);return c.substring(i+n.
161
+ length+1,j<0?c.length:j)}}}var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
162
+ d.write('<sc'+'ript src="'+
163
+ 'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'
164
+ +'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='
165
+ +new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+
166
+ '" type="text/javascript" charset="utf-8"></sc'+'ript>')})();
167
+ </script>
168
+ }
169
+
170
+ google_analytics_info = "";
171
+ section_definitions = "";
172
+ variable_assignments = "";
173
+
174
+ sections.each do |section|
175
+ section_definitions += "<!-- utmx section name='#{section}' -->\n"
176
+
177
+ variable_assignments += %{
178
+ var GWO_#{section}_name = utmx("variation_content", "#{section}");if( GWO_#{section}_name == undefined) GWO_#{section}_name = 'original';
179
+ var GWO_#{section}_number = utmx("variation_number", "#{section}");if( GWO_#{section}_number == undefined) GWO_#{section}_number = 0;
180
+ #{ js_logger("'variant: ' + GWO_#{section}_name") }
181
+ }
182
+ google_analytics_info += "google_analytics_info += \"&#{section}=\" + GWO_#{section}_name;" if options[:google_analytics]
183
+ end
184
+
185
+ # GOOGLE TRACKER:
186
+ if options[:google_analytics]
187
+ base_url = options[:google_analytics][:virtual_url] ? "\"#{options[:google_analytics][:virtual_url]}\"" : "document.location"
188
+ variable_assignments += %{
189
+ window.onload = function(){
190
+ var google_analytics_info = ''; #{google_analytics_info};
191
+ try{
192
+ var gwoGaPageTracker=_gat._getTracker("#{options[:google_analytics][:account_id]}");
193
+ gwoGaPageTracker._trackPageview(#{base_url} + "?ab_test=#{id}" + google_analytics_info);
194
+ }catch(err){ #{js_logger("\"error executing google analytics request\"")} }
195
+ #{js_logger("\"tracking \" + #{base_url} + \"?ab_test=#{id}\" + google_analytics_info + \" to account #{options[:google_analytics][:account_id]}\"")}
196
+ }
197
+ }
198
+ end
199
+
200
+ variable_assignments = "<script type='text/javascript'>#{variable_assignments}</script>";
201
+
202
+ "#{src}#{section_definitions}#{variable_assignments}"
203
+ end
204
+
205
+ def gwo_end(id, uacct, options)
206
+ return js_logger("skipping end snippet: a/b variation test switched off", true) if options[:conditions] == false
207
+
208
+ %{<script type="text/javascript">
209
+ if(typeof(_gat)!='object')document.write('<sc'+'ript src="http'+
210
+ (document.location.protocol=='https:'?'s://ssl':'://www')+
211
+ '.google-analytics.com/ga.js"></sc'+'ript>')</script>
212
+ <script type="text/javascript">
213
+ try {
214
+ var gwoPageTracker=_gat._getTracker("#{uacct}");
215
+ gwoPageTracker._trackPageview("/#{id}/test");
216
+ }catch(err){}</script>
217
+ }
218
+
219
+ end
220
+
221
+ def is_default_section?(variation_ids)
222
+ variation_ids.include?(:original) || variation_ids.include?(0)
223
+ end
224
+
225
+ def named_variations?(variation_ids)
226
+ raise RuntimeError.new("variation ids can only be either string, symbols or numbers") if [*variation_ids].compact.empty? # catch empty hashes and nil
227
+
228
+ return false if [1, *variation_ids].map(&:class).uniq.length == 1 # all variation_ids are FixNums
229
+ return true if ["string", :symbol, *variation_ids].map(&:class).uniq.length == 2 # all variation_ids are either string or symbol
230
+
231
+ raise RuntimeError.new("variation ids can only be either string, symbols or numbers")
232
+ end
233
+ end
234
+
235
+ end
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ ActionView::Base.send(:include, GWO::Helper)
@@ -0,0 +1,231 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'lib/gwo'
3
+
4
+ describe GWO do
5
+ include GWO::Helper
6
+
7
+ describe "google analytics stuff" do
8
+ it "should not create any google analytics stuff by default" do
9
+ gwo_start("gwo_id", "section_name").should_not =~ /google_analytics_info \+= \"&section_name=\" \+ GWO_section_name_name;/
10
+ gwo_start("gwo_id", "section_name").should_not =~ /gwoGaPageTracker\(document.location \+ \"\?ab_test=gwo_id\" \+ google_analytics_info\)/
11
+ end
12
+ it "should not create google analytics stuff if option is disabled" do
13
+ gwo_start("gwo_id", "section_name").should_not =~ /google_analytics_info \+= \"&section_name=\" \+ GWO_section_name_name;/
14
+ gwo_start("gwo_id", "section_name").should_not =~ /gwoGaPageTracker\(document.location \+ \"\?ab_test=gwo_id\" \+ google_analytics_info\)/
15
+ end
16
+
17
+ it "should create correct google analytics stuff for default urls" do
18
+ gwo_start("gwo_id", "section_name", :google_analytics => {:account_id => "123456789"}).should =~ /google_analytics_info \+= \"&section_name=\" \+ GWO_section_name_name;/
19
+ gwo_start("gwo_id", "section_name", :google_analytics => {:account_id => "123456789"}).should =~ /gwoGaPageTracker._trackPageview\(document.location \+ \"\?ab_test=gwo_id\" \+ google_analytics_info\)/
20
+ end
21
+
22
+ it "should create correct google analytics stuff for static urls" do
23
+ gwo_start("gwo_id", "section_name", :google_analytics => {:account_id => "123456789", :virtual_url => "http://example.com"}).should =~
24
+ /google_analytics_info \+= \"&section_name=\" \+ GWO_section_name_name;/
25
+ gwo_start("gwo_id", "section_name", :google_analytics => {:account_id => "123456789", :virtual_url => "http://example.com"}).should =~
26
+ /var gwoGaPageTracker=_gat._getTracker\(\"123456789\"\);/
27
+ gwo_start("gwo_id", "section_name", :google_analytics => {:account_id => "123456789", :virtual_url => "http://example.com"}).should =~
28
+ /gwoGaPageTracker._trackPageview\(\"http:\/\/example\.com\" \+ \"\?ab_test=gwo_id\" \+ google_analytics_info\)/
29
+ end
30
+
31
+ it "should create correct google analytics stuff for several sections" do
32
+ gwo_start("gwo_id", ["section_name1", "section_name2", "section_name3"], :google_analytics => {:account_id => "123456789"}).should =~ /google_analytics_info \+= \"&section_name1=\" \+ GWO_section_name1_name;/
33
+ gwo_start("gwo_id", ["section_name1", "section_name2", "section_name3"], :google_analytics => {:account_id => "123456789"}).should =~ /google_analytics_info \+= \"&section_name2=\" \+ GWO_section_name2_name;/
34
+ gwo_start("gwo_id", ["section_name1", "section_name2", "section_name3"], :google_analytics => {:account_id => "123456789"}).should =~ /google_analytics_info \+= \"&section_name3=\" \+ GWO_section_name3_name;/
35
+ gwo_start("gwo_id", ["section_name1", "section_name2", "section_name3"], :google_analytics => {:account_id => "123456789"}).should =~ /gwoGaPageTracker._trackPageview\(document.location \+ \"\?ab_test=gwo_id\" \+ google_analytics_info\)/
36
+ end
37
+
38
+ end
39
+
40
+ describe "named_variations? method" do
41
+ it "should return false if one numbered variation is passed in" do
42
+ named_variations?(1).should == false
43
+ end
44
+ it "should return false if variations are numbered" do
45
+ named_variations?([1,2,3]).should == false
46
+ end
47
+
48
+ it "should return true if one string is passed in" do
49
+ named_variations?("string").should == true
50
+ end
51
+ it "should return true if one symbol is passed in" do
52
+ named_variations?(:symbol).should == true
53
+ end
54
+ it "should return true if symbols and strings are mixed" do
55
+ named_variations?([:symbol, "string", :symbol2]).should == true
56
+ end
57
+ it "should throw an exception if numbers and strings are mixed" do
58
+ lambda {named_variations?([1, :symbol])}.should raise_error(RuntimeError)
59
+ lambda {named_variations?([1, "string"])}.should raise_error(RuntimeError)
60
+ lambda {named_variations?([1, "string", :symbol])}.should raise_error(RuntimeError)
61
+ end
62
+ it "should throw an exception if one obscure object is passed in" do
63
+ lambda {named_variations?(Hash.new)}.should raise_error(RuntimeError)
64
+ lambda {named_variations?(RuntimeError.new)}.should raise_error(RuntimeError)
65
+ end
66
+ it "should throw an exception if an array of obscure object is passed in" do
67
+ lambda {named_variations?([{}, {}])}.should raise_error(RuntimeError)
68
+ end
69
+ end
70
+
71
+ describe "gwo_start method" do
72
+ it "should produce correct output" do
73
+ gwo_start("gwo_id", "section_name").should =~ /utmx section name='section_name'/
74
+ gwo_start("gwo_id", "section_name").should =~ /utmx\(\"variation_content\", \"section_name\"\)/
75
+ gwo_start("gwo_id", "section_name").should =~ /utmx\(\"variation_number\", \"section_name\"\)/
76
+ gwo_start("gwo_id", "section_name").should =~ /k='gwo_id'/
77
+ end
78
+
79
+ it "should work with just the id parameter set" do
80
+ gwo_start("gwo_id").should =~ /k='gwo_id'/
81
+ gwo_start("gwo_id").should =~ /utmx section name='gwo_section'/
82
+ gwo_start("gwo_id").should =~ /utmx\(\"variation_content\", \"gwo_section\"\)/
83
+ gwo_start("gwo_id").should =~ /utmx\(\"variation_number\", \"gwo_section\"\)/
84
+ gwo_start("gwo_id", nil).should =~ /utmx section name='gwo_section'/
85
+ end
86
+
87
+ it "should work with one single section ... section is a symbol" do
88
+ gwo_start("gwo_id", :section_name).should =~ /utmx section name='section_name'/
89
+ gwo_start("gwo_id", :section_name).should =~ /utmx\(\"variation_content\", \"section_name\"\)/
90
+ gwo_start("gwo_id", :section_name).should =~ /utmx\(\"variation_number\", \"section_name\"\)/
91
+ gwo_start("gwo_id", :section_name).should =~ /k='gwo_id'/
92
+ end
93
+
94
+ it "should work with an array of section" do
95
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx section name='body'/
96
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx section name='content'/
97
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx section name='footer'/
98
+
99
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_content\", \"body\"\)/
100
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_content\", \"content\"\)/
101
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_content\", \"footer\"\)/
102
+
103
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_number\", \"body\"\)/
104
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_number\", \"content\"\)/
105
+ gwo_start("gwo_id", ["body",:content,"footer"]).should =~ /utmx\(\"variation_number\", \"footer\"\)/
106
+ end
107
+
108
+ it "should return nothing when conditions return false" do
109
+ gwo_start("id", [], {:conditions => false}).should == ""
110
+ gwo_start("gwo_id", ["body",:content,"footer"], :conditions => false).should == ""
111
+
112
+ gwo_start("gwo_id", ["body",:content,"footer"], {:conditions => false}).should_not =~ /utmx\(\"variation_content\", \"body\"\)/
113
+ gwo_start("gwo_id", ["body",:content,"footer"], {:conditions => false}).should_not =~ /utmx\(\"variation_content\", \"content\"\)/
114
+ gwo_start("gwo_id", ["body",:content,"footer"], {:conditions => false}).should_not =~ /utmx\(\"variation_content\", \"footer\"\)/
115
+
116
+ gwo_start("gwo_id", ["body",:content,"footer"], :conditions => false).should_not =~ /utmx\(\"variation_number\", \"body\"\)/
117
+ gwo_start("gwo_id", ["body",:content,"footer"], :conditions => false).should_not =~ /utmx\(\"variation_number\", \"content\"\)/
118
+ gwo_start("gwo_id", ["body",:content,"footer"], :conditions => false).should_not =~ /utmx\(\"variation_number\", \"footer\"\)/
119
+ end
120
+ end
121
+
122
+ describe "gwo_end method" do
123
+ it "should produce correct output" do
124
+ gwo_end("gwo_id", "gwo_uacct", :conditions => true).should =~ /getTracker\(\"gwo_uacct\"\)/
125
+ gwo_end("gwo_id", "gwo_uacct", :conditions => true).should =~ /trackPageview\(\"\/gwo_id\/test\"\)/
126
+ end
127
+
128
+ it "should return nothing if conditions are not met" do
129
+ gwo_end("gwo_id", "gwo_uacct", {:conditions => false}).should_not =~ /getTracker\(\"gwo_uacct\"\)/
130
+ gwo_end("gwo_id", "gwo_uacct", :conditions => false).should == ""
131
+ end
132
+ end
133
+
134
+ describe "gw_conversion method" do
135
+ it "should produce correct output" do
136
+ gwo_conversion("gwo_id", "gwo_uacct").should =~ /getTracker\(\"gwo_uacct\"\)/
137
+ gwo_conversion("gwo_id", "gwo_uacct").should =~ /trackPageview\(\"\/gwo_id\/goal\"\)/
138
+ end
139
+
140
+ it "should return nothing when conditions are not met" do
141
+ gwo_conversion("gwo_id", "gwo_uacct", {:conditions => false}).should == ""
142
+ end
143
+ end
144
+
145
+ describe "goal is bounce rate" do
146
+ before(:each) do
147
+ stub!(:output_buffer=).and_return "foo"
148
+ stub!(:output_buffer).and_return "foo"
149
+ end
150
+
151
+ it "should create link bindings when goal is bounce rate" do
152
+ gwo_experiment("id", "uacct", sections = [:foo, :bar], :goal_is_bounce_rate => true).should =~ /addEventListener/
153
+ end
154
+
155
+ it "should not create link bindings when goal is not bounce rate" do
156
+ gwo_experiment("id", "uacct", sections = [:foo, :bar]).should_not =~ /addEventListener/
157
+ end
158
+ end
159
+
160
+ describe "gwo_section method with named sections" do
161
+ before(:each) do
162
+ stub!(:output_buffer=).and_return "foo"
163
+ stub!(:output_buffer).and_return "foo"
164
+ end
165
+
166
+ it "should return nothing when conditions are not met and the variation is not the original" do
167
+ gwo_section("gwo_section", ["foo","bar"], {:conditions => false}).should == ""
168
+ end
169
+
170
+ it "should return original output without javascript if conditions are not met and original is the variation " do
171
+ gwo_section("gwo_section", :original, {:conditions => false}) { "this is the content" }.should == "this is the content"
172
+ end
173
+
174
+ it "should return original output with javascript if ignore is unset and original is the variation " do
175
+ gwo_section("gwo_section", :original) { "this is the content" }.should =~ /this is the content/
176
+ gwo_section("gwo_section", :original) { "this is the content" }.should =~ /( GWO_gwo_section_name != \"original\" )/
177
+ end
178
+
179
+ it "should only write one javascript block if the section is used for original and variations" do
180
+ gwo_section("section", [:original, :variation1, :variation2]) { "this is the content" }.should =~ /this is the content/
181
+ gwo_section("section", [:original, :variation1, :variation2]) { "this is the content" }.should =~ /( GWO_section_name != \"original\" && GWO_section_name != \"variation1\" && GWO_section_name != \"variation2\" )/
182
+ end
183
+
184
+ it "should write block for one variant" do
185
+ gwo_section("section",:testing) { "this is the content" }.should =~ /this is the content/
186
+ gwo_section("section",:testing) { "this is the content" }.should =~ /( GWO_section_name == \"testing\" )/
187
+ end
188
+
189
+ it "should write one block but enabled for all given variants " do
190
+ gwo_section("section",[:testing, :still_testing]) { "this is the content" }.should =~ /this is the content/
191
+ gwo_section("section",[:testing, :still_testing]) { "this is the content" }.should =~ /( GWO_section_name == \"testing\" || GWO_section_name == \"still_testing\" )/
192
+ end
193
+ end
194
+
195
+ describe "gwo_section method with numbered sections" do
196
+ before(:each) do
197
+ stub!(:output_buffer=).and_return "foo"
198
+ stub!(:output_buffer).and_return "foo"
199
+ end
200
+
201
+
202
+ it "should return nothing when conditions are not met and the variation is not the original" do
203
+ gwo_section("gwo_section", [1, 2], {:conditions => false}).should == ""
204
+ end
205
+
206
+ it "should return original output without javascript if conditions are not met and original is the variation " do
207
+ gwo_section("gwo_section", 0, {:conditions => false}) { "this is the content" }.should == "this is the content"
208
+ end
209
+
210
+ it "should return original output with javascript if ignore is unset and original is the variation " do
211
+ gwo_section("gwo_section", 0) { "this is the content" }.should =~ /this is the content/
212
+ gwo_section("gwo_section", 0) { "this is the content" }.should =~ /( GWO_gwo_section_number != 0 )/
213
+ end
214
+
215
+ it "should only write one javascript block if the section is used for original and variations" do
216
+ gwo_section("section", [0, 1, 2]) { "this is the content" }.should =~ /this is the content/
217
+ gwo_section("section", [0, 1, 2]) { "this is the content" }.should =~ /( GWO_section_number != 0 && GWO_section_number != 1 && GWO_section_number != 2 )/
218
+ end
219
+
220
+ it "should write block for one variant" do
221
+ gwo_section("section",1) { "this is the content" }.should =~ /this is the content/
222
+ gwo_section("section",1) { "this is the content" }.should =~ /( GWO_section_number == 1 )/
223
+ end
224
+
225
+ it "should write one block but enabled for all given variants " do
226
+ gwo_section("section",[1, 2]) { "this is the content" }.should =~ /this is the content/
227
+ gwo_section("section",[1, 2]) { "this is the content" }.should =~ /( GWO_section_number == 1 || GWO_section_number == 2 )/
228
+ end
229
+ end
230
+
231
+ end
@@ -0,0 +1,4 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ require 'spec'
4
+ RAILS_ENV="test"
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gwo
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 4
9
+ version: 0.1.4
10
+ platform: ruby
11
+ authors:
12
+ - Alex MacCaw
13
+ - Daniel Bornkessel
14
+ - Johannes Mentz
15
+ - Yan Minagawa
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2009-09-11 00:00:00 +02:00
21
+ default_executable:
22
+ dependencies: []
23
+
24
+ description:
25
+ email: daniel@bornkessel.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README.markdown
32
+ files:
33
+ - lib/gwo.rb
34
+ - MIT-LICENSE
35
+ - README.markdown
36
+ - spec/lib/gwo_spec.rb
37
+ - spec/spec_helper.rb
38
+ - rails/init.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/kesselborn/gwo
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --line-numbers
46
+ - --inline-source
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Plugin to easily make use of Server-Side Dynamic Section Variations with Google Web Optimizer
70
+ test_files: []
71
+