rack-tracker 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f0a68c680e45358ffb42303ad9556ef64d3b788
4
- data.tar.gz: 33478c535dcdebd32ce278c763384e5b41fc5a65
3
+ metadata.gz: 06a5db11fbd86405523dbc25c7be6f8b81f2149d
4
+ data.tar.gz: 900ce6c698fe6db41c3cf073bf3c523e3056a366
5
5
  SHA512:
6
- metadata.gz: 799632382d7f8c85cfe51f0e4f74784eb1a37089cd99af4bf6ad586366fd4e21f4488c90843464819d0827fd8c7adf89dd3fe615fdd3a218016d1453e29a9e6d
7
- data.tar.gz: a1488e39161fb2e081de609947e36fab6cf7f61645aa7a0e0054948ef0bf29a360e43b16b1c021869b505b37c4d92de37c6f0f55a9cccf04905ec6782dc83fb2
6
+ metadata.gz: 300d2b933c171c031439480702b5e64cf824d25fc8d4e2007d6eb2d09d9852447306b5a56621b520367b20bcbafeafc967cd0ac61f04a28faa24b0e02a680202
7
+ data.tar.gz: 4f2e384af4d3a3da6fd48f2210f11a92c37b31adb156f47cea6f104743720717f8df2a05965c2935cd5456ba59820dd8c4049f4d985b78caa572e06210d8e87d
data/.travis.yml CHANGED
@@ -3,4 +3,5 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
5
  - 2.1.2
6
+ - 2.2.1
6
7
  - jruby
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # master
2
+
3
+ # 0.4.0
4
+
5
+ * [BUGFIX] store event objects as hashes so they can be safely serialized using JSON (default since rails 4.1) #13
6
+ * added support for Google Analytics User ID feature #15
7
+ * added support for Google adwords conversion #24
8
+ * added support for Google Tag Manager feature #29
9
+ * added support for Google Analytics custom metrics and parameters #31 (thx @mnin)
10
+ * added support for Google Enhanced Ecommerce #32 (thx @mnin)
11
+
1
12
  # 0.3.0
2
13
 
3
14
  * [ENHANCEMENT] google analytics cookieDomain renamed to cookie_domain
data/README.md CHANGED
@@ -21,6 +21,7 @@ in your application. It's easy to add your own [custom handlers](#custom-handler
21
21
  but to get you started we're shipping support for the following services out of the box:
22
22
 
23
23
  * [Google Analytics](#google-analytics)
24
+ * [Google Tag Manager](#google-tag-manager)
24
25
  * [Facebook](#facebook)
25
26
  * [Visual Website Optimizer (VWO)](#visual-website-optimizer-vwo)
26
27
  * [GoSquared](#gosquared)
@@ -75,7 +76,7 @@ to inject arbitrary events into the request environment.
75
76
  ```ruby
76
77
  request.env['tracker'] = {
77
78
  'google_analytics' => [
78
- Rack::Tracker::GoogleAnalytics::Send.new(category: "Users", action: "Login", label: "Standard")
79
+ { 'class_name' => 'Send', 'category' => 'Users', 'action' => 'Login', 'label' => 'Standard' }
79
80
  ]
80
81
  }
81
82
  ```
@@ -83,12 +84,14 @@ request.env['tracker'] = {
83
84
  ### Google Analytics
84
85
 
85
86
  * `:anonymize_ip` - sets the tracker to remove the last octet from all IP addresses, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApi_gat?hl=de#_gat._anonymizeIp for details.
86
- * `:cookie_domain` - sets the domain name for the GATC cookies. Defaults to `auto`.
87
+ * `:cookie_domain` - sets the domain name for the [GATC cookies](https://developers.google.com/analytics/devguides/collection/analyticsjs/domains#implementation). If not set its the website domain, with the www. prefix removed.
88
+ * `:user_id` - defines a proc to set the [userId](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-id). Ex: `user_id: lambda { |env| env['rack.session']['user_id'] }` would return the user_id from the session.
87
89
  * `:site_speed_sample_rate` - Defines a new sample set size for Site Speed data collection, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiBasicConfiguration?hl=de#_gat.GA_Tracker_._setSiteSpeedSampleRate
88
90
  * `:adjusted_bounce_rate_timeouts` - An array of times in seconds that the tracker will use to set timeouts for adjusted bounce rate tracking. See http://analytics.blogspot.ca/2012/07/tracking-adjusted-bounce-rate-in-google.html for details.
89
91
  * `:enhanced_link_attribution` - Enables [Enhanced Link Attribution](https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#enhancedlink).
90
92
  * `:advertising` - Enables [Display Features](https://developers.google.com/analytics/devguides/collection/analyticsjs/display-features).
91
93
  * `:ecommerce` - Enables [Ecommerce Tracking](https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce).
94
+ * `:enhanced_ecommerce` - Enables [Enhanced Ecommerce Tracking](https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce)
92
95
 
93
96
  #### Events
94
97
 
@@ -108,6 +111,54 @@ It will render the following to the site source:
108
111
  ga('send', { 'hitType': 'event', 'eventCategory': 'button', 'eventAction': 'click', 'eventLabel': 'nav-buttons', 'value': 'X' })
109
112
  ```
110
113
 
114
+ #### Parameters
115
+
116
+ You can set parameters in your controller too:
117
+
118
+ ```ruby
119
+ def show
120
+ tracker do |t|
121
+ t.google_analytics :parameter, { dimension1: 'pink' }
122
+ end
123
+ end
124
+ ```
125
+
126
+ Will render this:
127
+
128
+ ```javascript
129
+ ga('set', 'dimension1', 'pink');
130
+ ```
131
+
132
+
133
+
134
+ #### Enhanced Ecommerce
135
+
136
+ You can set parameters in your controller:
137
+
138
+ ```ruby
139
+ def show
140
+ tracker do |t|
141
+ t.google_analytics :enhanced_ecommerce, {
142
+ type: 'addItem',
143
+ id: '1234',
144
+ name: 'Fluffy Pink Bunnies',
145
+ sku: 'DD23444',
146
+ category: 'Party Toys',
147
+ price: '11.99',
148
+ quantity: '1'
149
+ }
150
+ end
151
+ end
152
+ ```
153
+
154
+ Will render this:
155
+
156
+ ```javascript
157
+ ga("ec:addItem", {"id": "1234", "name": "Fluffy Pink Bunnies", "sku": "DD23444", "category": "Party Toys", "price": "11.99", "quantity": "1"});
158
+ ```
159
+
160
+
161
+
111
162
  #### Ecommerce
112
163
 
113
164
  You can even trigger ecommerce directly from within your controller:
@@ -132,11 +183,36 @@ take care of the plugin on your own.
132
183
 
133
184
  ```ruby
134
185
  config.middleware.use(Rack::Tracker) do
135
- handler :google_analytics, { tracker: 'U-XXXXX-Y', ecommerce: true}
186
+ handler :google_analytics, { tracker: 'U-XXXXX-Y', ecommerce: true }
136
187
  end
137
188
  ````
138
189
 
139
190
 
191
+ ### Google Tag Manager
192
+
193
+ Google Tag manager code snippet doesn't support any option other than the container id
194
+
195
+ ```ruby
196
+ config.middleware.use(Rack::Tracker) do
197
+ handler :google_tag_manager, { container: 'GTM-XXXXXX' }
198
+ end
199
+ ````
200
+
201
+ #### Data Layer
202
+
203
+ GTM supports a [dataLayer](https://developers.google.com/tag-manager/devguide#datalayer) for pushing events as well as variables.
204
+
205
+ To add events or variables to the dataLayer from the server side, just call the `tracker` method in your controller.
206
+
207
+ ```ruby
208
+ def show
209
+ tracker do |t|
210
+ t.google_tag_manager :push, { name: 'price', value: 'X' }
211
+ end
212
+ end
213
+ ```
214
+
215
+
140
216
  ### Facebook
141
217
 
142
218
  * `custom_audience` - adds the [Custom audience](https://developers.facebook.com/docs/reference/ads-api/custom-audience-website-faq) segmentation pixel
@@ -248,6 +324,28 @@ It will render the following to the site source:
248
324
  _gs("set", "visitor", { "age": 35, "favorite_food": "pizza" });
249
325
  ```
250
326
 
327
+ ### Criteo
328
+
329
+ [Criteo](http://www.criteo.com/) retargeting service.
330
+
331
+ ```
332
+ config.middleware.use(Rack::Tracker) do
333
+ handler :criteo, { set_account: '1234' }
334
+ end
335
+ ```
336
+
337
+ Other global criteo handler options are:
338
+ * `setCustomerId` (value can be a static or a dynamic, e.g. `lambda { |env| env['rack.session']['user_id'] }`)
339
+ * `setSiteType` (`m`, `t`, `d`)
340
+
341
+ ```
342
+ def show
343
+ tracker do |t|
344
+ t.criteo :track, { event: 'viewItem', item: 'P0001' }
345
+ end
346
+ end
347
+ ```
348
+
251
349
  ### Custom Handlers
252
350
 
253
351
  Tough we give you handlers for a few tracking services right out of the box, you might
data/lib/rack/tracker.rb CHANGED
@@ -12,6 +12,8 @@ require "rack/tracker/handler"
12
12
  require "rack/tracker/handler_delegator"
13
13
  require "rack/tracker/controller"
14
14
  require "rack/tracker/google_analytics/google_analytics"
15
+ require "rack/tracker/google_tag_manager/google_tag_manager"
16
+ require "rack/tracker/google_adwords_conversion/google_adwords_conversion"
15
17
  require "rack/tracker/facebook/facebook"
16
18
  require "rack/tracker/vwo/vwo"
17
19
  require "rack/tracker/go_squared/go_squared"
@@ -12,7 +12,7 @@ class Rack::Tracker::Facebook < Rack::Tracker::Handler
12
12
  end
13
13
 
14
14
  def self.track(name, *event)
15
- { name.to_s => [Event.new(event.last)] }
15
+ { name.to_s => [event.last.merge('class_name' => 'Event')] }
16
16
  end
17
17
 
18
18
  end
@@ -32,6 +32,6 @@ class Rack::Tracker::GoSquared < Rack::Tracker::Handler
32
32
  end
33
33
 
34
34
  def self.track(name, *event)
35
- { name.to_s => [const_get(event.first.to_s.classify).new(event.last)] }
35
+ { name.to_s => [event.last.merge('class_name' => event.first.to_s.classify)] }
36
36
  end
37
37
  end
@@ -0,0 +1,15 @@
1
+ class Rack::Tracker::GoogleAdwordsConversion < Rack::Tracker::Handler
2
+
3
+ class Conversion < OpenStruct
4
+ end
5
+
6
+ self.position = :body
7
+
8
+ def render
9
+ Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_adwords_conversion.erb') ).render(self)
10
+ end
11
+
12
+ def self.track(name, *event)
13
+ { name.to_s => [event.last.merge('class_name' => event.first.to_s.capitalize)] }
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ <% events.each do |ev| %>
2
+
3
+ <script type="text/javascript">
4
+ /* <![CDATA[ */
5
+ <% ev.to_h.each do |attr_name, attr_value| %>
6
+ var google_conversion_<%= attr_name %> = <%= attr_name == :id ? attr_value : "'#{attr_value}'" %>;
7
+ <% end %>
8
+ var google_remarketing_only = false;
9
+ /* ]]> */
10
+ </script>
11
+ <script type="text/javascript" src="//www.googleadservices.com/pagead/conversion.js"></script>
12
+ <noscript>
13
+ <div style="display:inline;">
14
+ <img height="1" width="1" style="border-style:none;" alt="" src="//www.googleadservices.com/pagead/conversion/<%= ev.id %>/?label=<%= URI.escape(ev.label) %>&amp;guid=ON&amp;script=0"/>
15
+ </div>
16
+ </noscript>
17
+
18
+ <% end %>
@@ -1,4 +1,7 @@
1
1
  class Rack::Tracker::GoogleAnalytics < Rack::Tracker::Handler
2
+
3
+ ALLOWED_TRACKER_OPTIONS = [:cookie_domain, :user_id]
4
+
2
5
  class Send < OpenStruct
3
6
  def initialize(attrs = {})
4
7
  attrs.reverse_merge!(type: 'event')
@@ -18,25 +21,51 @@ class Rack::Tracker::GoogleAnalytics < Rack::Tracker::Handler
18
21
  end
19
22
  end
20
23
 
24
+ class EnhancedEcommerce < OpenStruct
25
+ def write
26
+ ["ec:#{self.type}", self.to_h.except(:type).compact.stringify_values].to_json.gsub(/\[|\]/, '')
27
+ end
28
+ end
29
+
21
30
  class Ecommerce < OpenStruct
22
31
  def write
23
32
  ["ecommerce:#{self.type}", self.to_h.except(:type).compact.stringify_values].to_json.gsub(/\[|\]/, '')
24
33
  end
25
34
  end
26
35
 
36
+ class Parameter < OpenStruct
37
+ def write
38
+ ["set", self.to_h.to_a].flatten.map {|s| "'#{s}'" }.join(', ')
39
+ end
40
+ end
41
+
27
42
  def tracker
28
43
  options[:tracker].respond_to?(:call) ? options[:tracker].call(env) : options[:tracker]
29
44
  end
30
45
 
46
+ def tracker_options
47
+ @tracker_options ||= {}.tap do |tracker_options|
48
+ options.slice(*ALLOWED_TRACKER_OPTIONS).each do |key, value|
49
+ if option_value = value.respond_to?(:call) ? value.call(env) : value
50
+ tracker_options[key.to_s.camelize(:lower).to_sym] = option_value.to_s
51
+ end
52
+ end
53
+ end
54
+ end
55
+
31
56
  def render
32
57
  Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_analytics.erb') ).render(self)
33
58
  end
34
59
 
35
60
  def ecommerce_events
36
- events.select{|e| e.kind_of?(Ecommerce) }
61
+ events.select {|e| e.kind_of?(Ecommerce) }
62
+ end
63
+
64
+ def enhanced_ecommerce_events
65
+ events.select {|e| e.kind_of?(EnhancedEcommerce) }
37
66
  end
38
67
 
39
68
  def self.track(name, *event)
40
- { name.to_s => [const_get(event.first.to_s.capitalize).new(event.last)] }
69
+ { name.to_s => [event.last.merge('class_name' => event.first.to_s.classify)] }
41
70
  end
42
71
  end
@@ -1,47 +1,41 @@
1
1
  <script type="text/javascript">
2
-
3
2
  <% if tracker %>
4
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
5
- (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
6
- m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
7
- })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
8
-
9
- ga('create', '<%= tracker %>', <%= (options[:cookie_domain] ? {cookieDomain: options[:cookie_domain]} : {}).to_json %>);
10
-
3
+ if(typeof ga === 'undefined') {
4
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
5
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
6
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
7
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
8
+
9
+ ga('create', '<%= tracker %>', <%= tracker_options.to_json %>);
10
+ }
11
11
  <% if options[:enhanced_link_attribution] %>
12
12
  ga('require', 'linkid', 'linkid.js');
13
13
  <% end %>
14
-
15
14
  <% if options[:advertising] %>
16
15
  ga('require', 'displayfeatures');
17
16
  <% end %>
18
-
17
+ <% if options[:enhanced_ecommerce] && enhanced_ecommerce_events.any? %>
18
+ ga('require', 'ec');
19
+ <% end %>
19
20
  <% if options[:ecommerce] %>
20
21
  ga('require', 'ecommerce', 'ecommerce.js');
21
22
  <% end %>
22
-
23
23
  <% if options[:anonymize_ip] %>
24
24
  ga('set', 'anonymizeIp', true);
25
25
  <% end %>
26
-
27
26
  <% if options[:adjusted_bounce_rate_timeouts] %>
28
27
  <% options[:adjusted_bounce_rate_timeouts].each do |timeout| %>
29
28
  setTimeout(ga('send', 'event', '<%= "#{timeout.to_s}_seconds" %>', 'read'),<%= timeout*1000 %>);
30
29
  <% end %>
31
30
  <% end %>
32
-
33
31
  <% end %>
34
-
35
32
  <% events.each do |var| %>
36
33
  ga(<%= var.write() %>);
37
34
  <% end %>
38
-
39
35
  <% if options[:ecommerce] && ecommerce_events.any? %>
40
36
  ga('ecommerce:send');
41
37
  <% end %>
42
-
43
38
  <% if tracker %>
44
39
  ga('send', 'pageview');
45
40
  <% end %>
46
-
47
41
  </script>
@@ -0,0 +1,33 @@
1
+ class Rack::Tracker::GoogleTagManager < Rack::Tracker::Handler
2
+
3
+ class Push < OpenStruct
4
+
5
+ def write
6
+ "'#{event[:name]}': '#{event[:value]}'"
7
+ end
8
+
9
+ def event
10
+ attributes.stringify_values.compact
11
+ end
12
+
13
+ def attributes
14
+ to_h.slice(:name, :value)
15
+ end
16
+ end
17
+
18
+ # It is strongly recommended to put the google_tag_manager snippet only in the body tag
19
+ # https://developers.google.com/tag-manager/quickstart
20
+ self.position = :body
21
+
22
+ def container
23
+ options[:container].respond_to?(:call) ? options[:container].call(env) : options[:container]
24
+ end
25
+
26
+ def render
27
+ Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_tag_manager.erb') ).render(self)
28
+ end
29
+
30
+ def self.track(name, *event)
31
+ { name.to_s => [event.last.merge('class_name' => event.first.to_s.capitalize)] }
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ <% if container %>
2
+ <script>
3
+ dataLayer = [];
4
+ </script>
5
+
6
+ <noscript><iframe src="//www.googletagmanager.com/ns.html?id=<%= container %>"
7
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
8
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
9
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
10
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
11
+ '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
12
+ })(window,document,'script','dataLayer','<%= container %>');</script>
13
+
14
+ <script>
15
+ dataLayer.push({
16
+ <%= events.map(&:write).join(', ') %>
17
+ });
18
+ </script>
19
+ <% end %>
@@ -7,11 +7,13 @@ class Rack::Tracker::Handler
7
7
 
8
8
  def initialize(env, options = {})
9
9
  self.env = env
10
- self.options = options
10
+ self.options = options
11
+ self.position = options[:position] if options.has_key?(:position)
11
12
  end
12
13
 
13
14
  def events
14
- env.fetch('tracker', {})[self.class.to_s.demodulize.underscore] || []
15
+ events = env.fetch('tracker', {})[self.class.to_s.demodulize.underscore] || []
16
+ events.map{ |ev| "#{self.class}::#{ev['class_name']}".constantize.new(ev.except('class_name')) }
15
17
  end
16
18
 
17
19
  def render
@@ -20,6 +20,7 @@ class Rack::Tracker::HandlerDelegator
20
20
  end
21
21
 
22
22
  def write_event(event)
23
+ event.deep_stringify_keys! # for consistent hash access use strings (keys from the session are always strings anyway)
23
24
  if env.key?('tracker')
24
25
  self.env['tracker'].deep_merge!(event) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
25
26
  else
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Tracker
3
- VERSION = '0.3.0'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -1,3 +1,3 @@
1
1
  <script type="text/javascript">
2
- myAwesomeFunction("tracks", "like", "<%= track_me[:like] %>", "<%= options[:custom_key] %>");
2
+ myAwesomeFunction("tracks", "like", "<%= track_me['like'] %>", "<%= options[:custom_key] %>");
3
3
  </script>
@@ -36,11 +36,12 @@ RSpec.describe Rack::Tracker::Facebook do
36
36
  'tracker' => {
37
37
  'facebook' =>
38
38
  [
39
- Rack::Tracker::Facebook::Event.new(
40
- 'id'=> '123456789',
41
- 'value' => '23',
42
- 'currency' => 'EUR'
43
- )
39
+ {
40
+ 'id' => '123456789',
41
+ 'value' => '23',
42
+ 'currency' => 'EUR',
43
+ 'class_name' => 'Event'
44
+ }
44
45
  ]
45
46
  }
46
47
  }
@@ -14,7 +14,7 @@ RSpec.describe Rack::Tracker::GoSquared do
14
14
  def env
15
15
  {'tracker' => {
16
16
  'go_squared' => [
17
- Rack::Tracker::GoSquared::VisitorName.new(name: "John Doe")
17
+ { 'class_name' => 'VisitorName', 'name' => 'John Doe' }
18
18
  ]
19
19
  }}
20
20
  end
@@ -30,7 +30,7 @@ RSpec.describe Rack::Tracker::GoSquared do
30
30
  def env
31
31
  {'tracker' => {
32
32
  'go_squared' => [
33
- Rack::Tracker::GoSquared::VisitorInfo.new(age: 35, favorite_food: 'pizza')
33
+ { 'class_name' => 'VisitorInfo', 'age' => 35, 'favorite_food' => 'pizza' }
34
34
  ]
35
35
  }}
36
36
  end
@@ -0,0 +1,38 @@
1
+ RSpec.describe Rack::Tracker::GoogleAdwordsConversion do
2
+
3
+ def env
4
+ {
5
+ misc: 'foobar',
6
+ user_id: '123'
7
+ }
8
+ end
9
+
10
+ it 'will be placed in the body' do
11
+ expect(described_class.position).to eq(:body)
12
+ expect(described_class.new(env).position).to eq(:body)
13
+ expect(described_class.new(env, position: :body).position).to eq(:body)
14
+ end
15
+
16
+ describe "with events" do
17
+ describe "default" do
18
+ def env
19
+ {'tracker' => {
20
+ 'google_adwords_conversion' => [
21
+ { 'class_name' => 'Conversion', 'id' => 123456, 'language' => 'en', 'format' => '3', 'color' => 'ffffff', 'label' => 'Conversion Label' }
22
+ ]
23
+ }}
24
+ end
25
+
26
+ subject { described_class.new(env).render }
27
+ it 'will show events' do
28
+ expect(subject).to match(%r{var google_conversion_id = 123456;})
29
+ expect(subject).to match(%r{var google_conversion_language = 'en';})
30
+ expect(subject).to match(%r{var google_conversion_format = '3';})
31
+ expect(subject).to match(%r{var google_conversion_color = 'ffffff';})
32
+ expect(subject).to match(%r{var google_conversion_label = 'Conversion Label';})
33
+ expect(subject).to match(%r{<img.*src=\"\/\/www.googleadservices.com\/pagead\/conversion\/123456\/\?label=Conversion%20Label&amp;guid=ON&amp;script=0\"/>})
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -1,12 +1,15 @@
1
1
  RSpec.describe Rack::Tracker::GoogleAnalytics do
2
-
3
2
  def env
4
- {misc: 'foobar'}
3
+ {
4
+ misc: 'foobar',
5
+ user_id: '123'
6
+ }
5
7
  end
6
8
 
7
9
  it 'will be placed in the head' do
8
10
  expect(described_class.position).to eq(:head)
9
11
  expect(described_class.new(env).position).to eq(:head)
12
+ expect(described_class.new(env, position: :body).position).to eq(:body)
10
13
  end
11
14
 
12
15
  describe '#ecommerce_events' do
@@ -29,12 +32,70 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
29
32
  end
30
33
  end
31
34
 
35
+ describe '#enhanced_ecommerce_events' do
36
+ subject { described_class.new(env) }
37
+
38
+ describe 'with stored enhanced ecommerce events' do
39
+ before { allow(subject).to receive(:events).and_return([Rack::Tracker::GoogleAnalytics::Send.new, Rack::Tracker::GoogleAnalytics::EnhancedEcommerce.new]) }
40
+
41
+ it 'will just return the enhanced ecommerce events' do
42
+ expect(subject.enhanced_ecommerce_events).to match_array(Rack::Tracker::GoogleAnalytics::EnhancedEcommerce)
43
+ end
44
+ end
45
+
46
+ describe 'without stored enhanced ecommerce events' do
47
+ before { allow(subject).to receive(:events).and_return([Rack::Tracker::GoogleAnalytics::Send.new]) }
48
+
49
+ it 'will be empty' do
50
+ expect(subject.enhanced_ecommerce_events).to be_empty
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#tracker_options' do
56
+ before do
57
+ stub_const("#{described_class}::ALLOWED_TRACKER_OPTIONS", [:some_option])
58
+ end
59
+
60
+ context 'with an allowed option configured with a static value' do
61
+ subject { described_class.new(env, { some_option: 'value' }) }
62
+
63
+ it 'returns hash with option set' do
64
+ expect(subject.tracker_options).to eql ({ someOption: 'value' })
65
+ end
66
+ end
67
+
68
+ context 'with an allowed option configured with a block' do
69
+ subject { described_class.new(env, { some_option: lambda { |env| return env[:misc] } }) }
70
+
71
+ it 'returns hash with option set' do
72
+ expect(subject.tracker_options).to eql ({ someOption: 'foobar' })
73
+ end
74
+ end
75
+
76
+ context 'with an allowed option configured with a block returning nil' do
77
+ subject { described_class.new(env, { some_option: lambda { |env| return env[:non_existing_key] } }) }
78
+
79
+ it 'returns an empty hash' do
80
+ expect(subject.tracker_options).to eql ({})
81
+ end
82
+ end
83
+
84
+ context 'with a non allowed option' do
85
+ subject { described_class.new(env, { new_option: 'value' }) }
86
+
87
+ it 'returns an empty hash' do
88
+ expect(subject.tracker_options).to eql ({})
89
+ end
90
+ end
91
+ end
92
+
32
93
  describe "with events" do
33
94
  describe "default" do
34
95
  def env
35
96
  {'tracker' => {
36
97
  'google_analytics' => [
37
- Rack::Tracker::GoogleAnalytics::Send.new(category: "Users", action: "Login", label: "Standard")
98
+ { 'class_name' => 'Send', 'category' => 'Users', 'action' => 'Login', 'label' => 'Standard' }
38
99
  ]
39
100
  }}
40
101
  end
@@ -48,7 +109,7 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
48
109
  describe "with a event value" do
49
110
  def env
50
111
  {'tracker' => { 'google_analytics' => [
51
- Rack::Tracker::GoogleAnalytics::Send.new(category: "Users", action: "Login", label: "Standard", value: "5")
112
+ { 'class_name' => 'Send', category: "Users", action: "Login", label: "Standard", value: "5" }
52
113
  ]}}
53
114
  end
54
115
 
@@ -59,13 +120,13 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
59
120
  end
60
121
  end
61
122
 
62
- describe 'with e-commerce events' do
123
+ describe 'with ecommerce events' do
63
124
  describe "default" do
64
125
  def env
65
126
  {'tracker' => {
66
127
  'google_analytics' => [
67
- Rack::Tracker::GoogleAnalytics::Ecommerce.new({type: 'addItem', id: '1234', name: 'Fluffy Pink Bunnies', sku: 'DD23444', category: 'Party Toys', price: '11.99', quantity: '1'}),
68
- Rack::Tracker::GoogleAnalytics::Ecommerce.new({type: 'addTransaction', id: '1234', affiliation: 'Acme Clothing', revenue: 11.99, shipping: '5', tax: '1.29', currency: 'EUR'})
128
+ { 'class_name' => 'Ecommerce', 'type' => 'addItem', 'id' => '1234', 'name' => 'Fluffy Pink Bunnies', 'sku' => 'DD23444', 'category' => 'Party Toys', 'price' => '11.99', 'quantity' => '1' },
129
+ { 'class_name' => 'Ecommerce', 'type' => 'addTransaction', 'id' => '1234', 'affiliation' => 'Acme Clothing', 'revenue' => 11.99, 'shipping' => '5', 'tax' => '1.29', 'currency' => 'EUR' }
69
130
  ]
70
131
  }}
71
132
  end
@@ -83,6 +144,44 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
83
144
  end
84
145
  end
85
146
 
147
+ describe 'with enhanced ecommerce events' do
148
+ describe "default" do
149
+ def env
150
+ {'tracker' => {
151
+ 'google_analytics' => [
152
+ { 'class_name' => 'EnhancedEcommerce', 'type' => 'addProduct', 'id' => 'P12345', 'name' => 'Android Warhol T-Shirt', 'category' => 'Apparel', 'brand' => 'Google', 'variant' => 'black', 'price' => '29.20', 'coupon' => 'APPARELSALE', 'quantity' => 1 },
153
+ { 'class_name' => 'EnhancedEcommerce', 'type' => 'setAction', 'id' => 'T12345', 'affiliation' => 'Google Store - Online', 'revenue' => '37.39', 'tax' => '2.85', 'shipping' => '5.34', 'coupon' => 'SUMMER2013' }
154
+ ]
155
+ }}
156
+ end
157
+
158
+ subject { described_class.new(env, tracker: 'somebody', enhanced_ecommerce: true).render }
159
+ it "will add product" do
160
+ expect(subject).to match(%r{ga\(\"ec:addProduct\",#{{id: 'P12345', name: 'Android Warhol T-Shirt', category: 'Apparel', brand: 'Google', variant: 'black', price: '29.20', coupon: 'APPARELSALE', quantity: '1'}.to_json}})
161
+ end
162
+
163
+ it "will add action" do
164
+ expect(subject).to match(%r{ga\(\"ec:setAction\",#{{id: 'T12345', affiliation: 'Google Store - Online', revenue: '37.39', tax: '2.85', shipping: '5.34', coupon: 'SUMMER2013'}.to_json}})
165
+ end
166
+ end
167
+ end
168
+
169
+ describe 'with parameters events' do
170
+ def env
171
+ {'tracker' => {
172
+ 'google_analytics' => [
173
+ { 'class_name' => 'Parameter', 'dimension1' => 'pink' },
174
+ ]
175
+ }}
176
+ end
177
+
178
+ subject { described_class.new(env, tracker: 'somebody').render }
179
+
180
+ it "will render dimension parameter" do
181
+ expect(subject).to match(%r{ga\('set', 'dimension1', 'pink'})
182
+ end
183
+ end
184
+
86
185
  describe "with custom domain" do
87
186
  subject { described_class.new(env, tracker: 'somebody', cookie_domain: "railslabs.com").render }
88
187
 
@@ -92,6 +191,15 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
92
191
  end
93
192
  end
94
193
 
194
+ describe "with user_id tracking" do
195
+ subject { described_class.new(env, tracker: 'somebody', user_id: lambda { |env| return env[:user_id] } ).render }
196
+
197
+ it "will show asyncronous tracker with userId" do
198
+ expect(subject).to match(%r{ga\('create', 'somebody', {\"userId\":\"123\"}\)})
199
+ expect(subject).to match(%r{ga\('send', 'pageview'\)})
200
+ end
201
+ end
202
+
95
203
  describe "with enhanced_link_attribution" do
96
204
  subject { described_class.new(env, tracker: 'happy', enhanced_link_attribution: true).render }
97
205
 
@@ -108,7 +216,33 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
108
216
  end
109
217
  end
110
218
 
111
- describe "with e-commerce" do
219
+ describe "with enhanced ecommerce" do
220
+ describe "without events" do
221
+ subject { described_class.new(env, tracker: 'happy', enhanced_ecommerce: true).render }
222
+
223
+ it "will require the enhanced ecommerce plugin" do
224
+ expect(subject).to_not match(%r{ga\('require', 'ec'\)})
225
+ end
226
+ end
227
+
228
+ describe "with events" do
229
+ def env
230
+ {'tracker' => {
231
+ 'google_analytics' => [
232
+ { 'class_name' => 'EnhancedEcommerce', 'type' => 'addProduct', 'id' => 'P12345', 'name' => 'Android Warhol T-Shirt', 'category' => 'Apparel', 'brand' => 'Google', 'variant' => 'black', 'price' => '29.20', 'coupon' => 'APPARELSALE', 'quantity' => 1 },
233
+ ]
234
+ }}
235
+ end
236
+
237
+ subject { described_class.new(env, tracker: 'happy', enhanced_ecommerce: true).render }
238
+
239
+ it "will require the enhanced ecommerce plugin" do
240
+ expect(subject).to match(%r{ga\('require', 'ec'\)})
241
+ end
242
+ end
243
+ end
244
+
245
+ describe "with ecommerce" do
112
246
  subject { described_class.new(env, tracker: 'happy', ecommerce: true).render }
113
247
 
114
248
  it "will require the ecommerce plugin" do
@@ -140,5 +274,4 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
140
274
  expect(subject).to match(%r{ga\('send', 'event', '30_seconds', 'read'\)})
141
275
  end
142
276
  end
143
-
144
277
  end
@@ -0,0 +1,42 @@
1
+ RSpec.describe Rack::Tracker::GoogleTagManager do
2
+
3
+ def env
4
+ {
5
+ misc: 'foobar',
6
+ user_id: '123'
7
+ }
8
+ end
9
+
10
+ it 'will be placed in the body by default' do
11
+ expect(described_class.position).to eq(:body)
12
+ expect(described_class.new(env).position).to eq(:body)
13
+ expect(described_class.new(env, position: :head).position).to eq(:head)
14
+ end
15
+
16
+ describe "with events" do
17
+ describe "default" do
18
+ def env
19
+ {'tracker' => {
20
+ 'google_tag_manager' => [
21
+ { 'class_name' => 'Push', 'name' => 'page', 'value' => 'Cart' },
22
+ { 'class_name' => 'Push', 'name' => 'price', 'value' => 50 }
23
+ ]
24
+ }}
25
+ end
26
+
27
+ subject { described_class.new(env, container: 'somebody').render }
28
+ it "will show events" do
29
+ expect(subject).to match(%r{'page': 'Cart', 'price': '50'})
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "with dynamic tracker" do
35
+ subject { described_class.new(env, { container: lambda { |env| return env[:misc] }}).render }
36
+
37
+ it 'will call tracker lambdas to obtain tracking codes' do
38
+ expect(subject).to match(%r{\(window,document,'script','dataLayer','foobar'\)})
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,18 @@
1
+ require 'support/capybara_app_helper'
2
+
3
+ RSpec.describe "Google Adwords Conversion Integration" do
4
+ before do
5
+ setup_app(action: :google_adwords_conversion) do |tracker|
6
+ tracker.handler :google_adwords_conversion
7
+ end
8
+ visit '/'
9
+ end
10
+
11
+ subject { page }
12
+
13
+ it "embeds the script tag with tracking event from the controller action" do
14
+ expect(page.find("body")).to have_content("var google_conversion_id = 123456;\nvar google_conversion_language = 'en';\nvar google_conversion_format = '3';\nvar google_conversion_color = 'ffffff';\nvar google_conversion_label = 'Conversion Label';")
15
+ expect(page.find("body")).to have_xpath("//img[@src=\"//www.googleadservices.com/pagead/conversion/123456/?label=Conversion%20Label&guid=ON&script=0\"]")
16
+ end
17
+
18
+ end
@@ -1,6 +1,6 @@
1
1
  require 'support/capybara_app_helper'
2
2
 
3
- RSpec.describe "Facebook Integration" do
3
+ RSpec.describe "Google Analytics Integration" do
4
4
  before do
5
5
  setup_app(action: :google_analytics) do |tracker|
6
6
  tracker.handler :google_analytics, { tracker: 'U-XXX-Y' }
@@ -11,8 +11,23 @@ RSpec.describe "Facebook Integration" do
11
11
  subject { page }
12
12
 
13
13
  it "embeds the script tag with tracking event from the controller action" do
14
- expect(page).to have_content('ga("ecommerce:addItem",{"id":"1234","name":"Fluffy Pink Bunnies","sku":"DD23444","category":"Party Toys","price":"11.99","quantity":"1"})')
15
- expect(page).to have_content('ga("ecommerce:addTransaction",{"id":"1234","affiliation":"Acme Clothing","revenue":"11.99","shipping":"5","tax":"1.29"})')
16
- expect(page).to have_content('ga("send",{"hitType":"event","eventCategory":"button","eventAction":"click","eventLabel":"nav-buttons","eventValue":"X"})')
14
+ expect(page.find("head")).to have_content('ga("ecommerce:addItem",{"id":"1234","name":"Fluffy Pink Bunnies","sku":"DD23444","category":"Party Toys","price":"11.99","quantity":"1"})')
15
+ expect(page.find("head")).to have_content('ga("ecommerce:addTransaction",{"id":"1234","affiliation":"Acme Clothing","revenue":"11.99","shipping":"5","tax":"1.29"})')
16
+ expect(page.find("head")).to have_content('ga("send",{"hitType":"event","eventCategory":"button","eventAction":"click","eventLabel":"nav-buttons","eventValue":"X"})')
17
+ end
18
+
19
+ describe 'adjust tracker position via options' do
20
+ before do
21
+ setup_app(action: :google_analytics) do |tracker|
22
+ tracker.handler :google_analytics, { tracker: 'U-XXX-Y', position: :body }
23
+ end
24
+ visit '/'
25
+ end
26
+
27
+ it "will be placed in the specified tag" do
28
+ expect(page.find("head")).to_not have_content('U-XXX-Y')
29
+ expect(page.find("body")).to have_content('ga("ecommerce:addItem",{"id":"1234","name":"Fluffy Pink Bunnies","sku":"DD23444","category":"Party Toys","price":"11.99","quantity":"1"})')
30
+ end
31
+
17
32
  end
18
33
  end
@@ -0,0 +1,18 @@
1
+ require 'support/capybara_app_helper'
2
+
3
+ RSpec.describe "Google Tag Manager Integration" do
4
+ before do
5
+ setup_app(action: :google_tag_manager) do |tracker|
6
+ tracker.handler :google_tag_manager, { container: 'GTM-ABCDEF' }
7
+ end
8
+ visit '/'
9
+ end
10
+
11
+ subject { page }
12
+
13
+ it "embeds the script tag with tracking event from the controller action" do
14
+ expect(page.find("body")).to have_content('GTM-ABCDEF')
15
+ expect(page.find("body")).to have_content('\'click\': \'X\', \'price\': \'10\'')
16
+ end
17
+
18
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,7 @@ require 'rspec'
5
5
  require 'rack/test'
6
6
  require 'capybara/rspec'
7
7
  require 'rack/tracker'
8
+ require 'pry'
8
9
 
9
10
  # Requires supporting files with custom matchers and macros, etc,
10
11
  # in ./support/ and its subdirectories.
@@ -38,6 +38,21 @@ class MetalController < ActionController::Metal
38
38
  render "metal/index"
39
39
  end
40
40
 
41
+ def google_tag_manager
42
+ tracker do |t|
43
+ t.google_tag_manager :push, { name: 'click', value: 'X' }
44
+ t.google_tag_manager :push, { name: 'price', value: '10' }
45
+ end
46
+ render "metal/index"
47
+ end
48
+
49
+ def google_adwords_conversion
50
+ tracker do |t|
51
+ t.google_adwords_conversion :conversion, { id: 123456, language: 'en', format: '3', color: 'ffffff', label: 'Conversion Label' }
52
+ end
53
+ render "metal/index"
54
+ end
55
+
41
56
  def vwo
42
57
  render "metal/index"
43
58
  end
@@ -22,11 +22,11 @@ end
22
22
 
23
23
  RSpec.describe Rack::Tracker::Controller do
24
24
  describe '#tracker' do
25
- let(:send) { Rack::Tracker::GoogleAnalytics::Send.new(category: 'foo') }
26
- let(:trx) { Rack::Tracker::GoogleAnalytics::Ecommerce.new(type: 'addTransaction', some: 'thing') }
27
- let(:item_foo) { Rack::Tracker::GoogleAnalytics::Ecommerce.new(type: 'addItem', name: 'foo') }
28
- let(:item_bar) { Rack::Tracker::GoogleAnalytics::Ecommerce.new(type: 'addItem', name: 'bar') }
29
- let(:fb_event) { Rack::Tracker::Facebook::Event.new(id: '1', value: 1, currency: 'USD') }
25
+ let(:send) { { 'category' => 'foo', 'class_name' => 'Send' } }
26
+ let(:trx) { { 'type' => 'addTransaction', 'some' => 'thing', 'class_name' => 'Ecommerce' } }
27
+ let(:item_foo) { { 'type' => 'addItem', 'name' => 'foo', 'class_name' => 'Ecommerce' } }
28
+ let(:item_bar) { { 'type' => 'addItem', 'name' => 'bar', 'class_name' => 'Ecommerce' } }
29
+ let(:fb_event) { { 'id' => '1', 'value' => 1, 'currency' => 'USD', 'class_name' => 'Event' } }
30
30
  let(:controller) { TestController.new({}) }
31
31
 
32
32
  context 'controller' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Brillert
@@ -9,132 +9,132 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-19 00:00:00.000000000 Z
12
+ date: 2015-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 1.4.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 1.4.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: tilt
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ~>
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
34
  version: 1.4.1
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ~>
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: 1.4.1
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: activesupport
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: '3.0'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '3.0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: actionpack
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '3.0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '3.0'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: bundler
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - ~>
74
+ - - "~>"
75
75
  - !ruby/object:Gem::Version
76
76
  version: '1.5'
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - ~>
81
+ - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '1.5'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: rake
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - '>='
88
+ - - ">="
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - '>='
95
+ - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rspec
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ~>
102
+ - - "~>"
103
103
  - !ruby/object:Gem::Version
104
104
  version: 3.0.0
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ~>
109
+ - - "~>"
110
110
  - !ruby/object:Gem::Version
111
111
  version: 3.0.0
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: capybara
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - ~>
116
+ - - "~>"
117
117
  - !ruby/object:Gem::Version
118
118
  version: 2.4.1
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - ~>
123
+ - - "~>"
124
124
  - !ruby/object:Gem::Version
125
125
  version: 2.4.1
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: pry
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  requirements:
130
- - - '>='
130
+ - - ">="
131
131
  - !ruby/object:Gem::Version
132
132
  version: '0'
133
133
  type: :development
134
134
  prerelease: false
135
135
  version_requirements: !ruby/object:Gem::Requirement
136
136
  requirements:
137
- - - '>='
137
+ - - ">="
138
138
  - !ruby/object:Gem::Version
139
139
  version: '0'
140
140
  description: Don’t fool around with adding tracking partials to your app and concentrate
@@ -146,9 +146,9 @@ executables: []
146
146
  extensions: []
147
147
  extra_rdoc_files: []
148
148
  files:
149
- - .gitignore
150
- - .rspec
151
- - .travis.yml
149
+ - ".gitignore"
150
+ - ".rspec"
151
+ - ".travis.yml"
152
152
  - CHANGELOG.md
153
153
  - Gemfile
154
154
  - LICENSE.txt
@@ -161,8 +161,12 @@ files:
161
161
  - lib/rack/tracker/facebook/template/facebook.erb
162
162
  - lib/rack/tracker/go_squared/go_squared.rb
163
163
  - lib/rack/tracker/go_squared/template/go_squared.erb
164
+ - lib/rack/tracker/google_adwords_conversion/google_adwords_conversion.rb
165
+ - lib/rack/tracker/google_adwords_conversion/template/google_adwords_conversion.erb
164
166
  - lib/rack/tracker/google_analytics/google_analytics.rb
165
167
  - lib/rack/tracker/google_analytics/template/google_analytics.erb
168
+ - lib/rack/tracker/google_tag_manager/google_tag_manager.rb
169
+ - lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb
166
170
  - lib/rack/tracker/handler.rb
167
171
  - lib/rack/tracker/handler_delegator.rb
168
172
  - lib/rack/tracker/railtie.rb
@@ -177,11 +181,15 @@ files:
177
181
  - spec/fixtures/views/metal/index.html.erb
178
182
  - spec/handler/facebook_spec.rb
179
183
  - spec/handler/go_squared_spec.rb
184
+ - spec/handler/google_adwords_conversion_spec.rb
180
185
  - spec/handler/google_analytics_spec.rb
186
+ - spec/handler/google_tag_manager_spec.rb
181
187
  - spec/handler/vwo_spec.rb
182
188
  - spec/integration/facebook_integration_spec.rb
183
189
  - spec/integration/go_squared_integration_spec.rb
190
+ - spec/integration/google_adwords_conversion_integration_spec.rb
184
191
  - spec/integration/google_analytics_integration_spec.rb
192
+ - spec/integration/google_tag_manager_integration_spec.rb
185
193
  - spec/integration/rails_integration_spec.rb
186
194
  - spec/integration/vwo_integration_spec.rb
187
195
  - spec/spec_helper.rb
@@ -202,17 +210,17 @@ require_paths:
202
210
  - lib
203
211
  required_ruby_version: !ruby/object:Gem::Requirement
204
212
  requirements:
205
- - - '>='
213
+ - - ">="
206
214
  - !ruby/object:Gem::Version
207
215
  version: '0'
208
216
  required_rubygems_version: !ruby/object:Gem::Requirement
209
217
  requirements:
210
- - - '>='
218
+ - - ">="
211
219
  - !ruby/object:Gem::Version
212
220
  version: '0'
213
221
  requirements: []
214
222
  rubyforge_project:
215
- rubygems_version: 2.2.2
223
+ rubygems_version: 2.4.3
216
224
  signing_key:
217
225
  specification_version: 4
218
226
  summary: Tracking made easy
@@ -224,11 +232,15 @@ test_files:
224
232
  - spec/fixtures/views/metal/index.html.erb
225
233
  - spec/handler/facebook_spec.rb
226
234
  - spec/handler/go_squared_spec.rb
235
+ - spec/handler/google_adwords_conversion_spec.rb
227
236
  - spec/handler/google_analytics_spec.rb
237
+ - spec/handler/google_tag_manager_spec.rb
228
238
  - spec/handler/vwo_spec.rb
229
239
  - spec/integration/facebook_integration_spec.rb
230
240
  - spec/integration/go_squared_integration_spec.rb
241
+ - spec/integration/google_adwords_conversion_integration_spec.rb
231
242
  - spec/integration/google_analytics_integration_spec.rb
243
+ - spec/integration/google_tag_manager_integration_spec.rb
232
244
  - spec/integration/rails_integration_spec.rb
233
245
  - spec/integration/vwo_integration_spec.rb
234
246
  - spec/spec_helper.rb