gabba-gmp 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitattributes ADDED
@@ -0,0 +1,22 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+
4
+ # Custom for Visual Studio
5
+ *.cs diff=csharp
6
+ *.sln merge=union
7
+ *.csproj merge=union
8
+ *.vbproj merge=union
9
+ *.fsproj merge=union
10
+ *.dbproj merge=union
11
+
12
+ # Standard to msysgit
13
+ *.doc diff=astextplain
14
+ *.DOC diff=astextplain
15
+ *.docx diff=astextplain
16
+ *.DOCX diff=astextplain
17
+ *.dot diff=astextplain
18
+ *.DOT diff=astextplain
19
+ *.pdf diff=astextplain
20
+ *.PDF diff=astextplain
21
+ *.rtf diff=astextplain
22
+ *.RTF diff=astextplain
data/.gitignore ADDED
@@ -0,0 +1,38 @@
1
+ # Windows image file caches
2
+ Thumbs.db
3
+ ehthumbs.db
4
+
5
+ # Folder config file
6
+ Desktop.ini
7
+
8
+ # Recycle Bin used on file shares
9
+ $RECYCLE.BIN/
10
+
11
+ # Windows Installer files
12
+ *.cab
13
+ *.msi
14
+ *.msm
15
+ *.msp
16
+
17
+ # =========================
18
+ # Operating System Files
19
+ # =========================
20
+
21
+ # OSX
22
+ # =========================
23
+
24
+ .DS_Store
25
+ .AppleDouble
26
+ .LSOverride
27
+
28
+ # Icon must ends with two \r.
29
+ Icon
30
+
31
+ # Thumbnails
32
+ ._*
33
+
34
+ # Files that might appear on external disk
35
+ .Spotlight-V100
36
+ .Trashes
37
+
38
+ *.project
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gabba.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2010-2013 The Hybrid Group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+ http://opensource.org/licenses/MIT
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler"
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :spec
5
+
6
+ Bundler::GemHelper.install_tasks
7
+ RSpec::Core::RakeTask.new :spec
data/Readme.md ADDED
@@ -0,0 +1,60 @@
1
+ # Gabba-GMP
2
+
3
+
4
+
5
+ Simple class to send custom server-side events to Google Analytics via Google Measurement Protocol
6
+ https://developers.google.com/analytics/devguides/collection/protocol/v1/
7
+
8
+ Refactored from the [gabba](https://github.com/hybridgroup/gabba) project.
9
+ - Heavily influenced by the [serversidegoogleanalytics][] project.
10
+
11
+ ## Examples
12
+
13
+ ### Track page views
14
+
15
+ ```ruby
16
+ google_tracker_id = "UT-1234"
17
+ host = "#{request.host}"
18
+ cookies[:utm_visitor_uuid] = { value: "#{SecureRandom.uuid}", expires: 1.year.from_now} if !cookies[:utm_visitor_uuid].present?
19
+ visitor_id = "#{cookies[:utm_visitor_uuid]}"
20
+ client_ip = "#{request.remote_ip}"
21
+ user_agent = "#{request.env["HTTP_USER_AGENT"]}"
22
+
23
+ gabba = GabbaGMP::GabbaGMP.new(google_tracker_id, host, visitor_id, client_ip, user_agent)
24
+
25
+ gabba.page_view("page title", "page/1.html")
26
+ ```
27
+
28
+ ### Track custom events
29
+
30
+ ```ruby
31
+ gabba = GabbaGMP::GabbaGMP.new(google_tracker_id, host, visitor_id, client_ip, user_agent)
32
+
33
+ gabba.event("Videos", "Play", "ID", "123")
34
+ ```
35
+
36
+ ### Setting custom vars
37
+
38
+ ```ruby
39
+ # Index: 1 through 50
40
+ index = 1
41
+
42
+ # Scope: VISITOR, SESSION or PAGE
43
+ scope = GabbaGMP::GabbaGMP::VISITOR
44
+
45
+ # Set var
46
+ gabba.set_custom_var(index, 'Name', 'Value', scope)
47
+
48
+ # Track the event (all vars will be included)
49
+ gabba.event(...)
50
+
51
+ # Track the page view (all vars will be included)
52
+ gabba.page_view(...)
53
+ ```
54
+
55
+ ### License
56
+
57
+ Gabba is released under the [MIT License](http://opensource.org/licenses/MIT).
58
+
59
+
60
+ [serversidegoogleanalytics]: http://code.google.com/p/serversidegoogleanalytics
data/gabba-gmp.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path '../lib/gabba-gmp/version', __FILE__
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "gabba-gmp"
6
+ s.version = GabbaGMP::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Julian West"]
9
+ s.email = ["julz dot west at gmail dot com"]
10
+ s.homepage = "https://github.com/fuzzyjulz/gabba-gmp"
11
+ s.summary = %q{Google Measurement Protocol rewite of the Gabba library}
12
+ s.description = %q{Google Measurement Protocol rewite of the Gabba library}
13
+ s.license = "MIT"
14
+
15
+ s.rubyforge_project = "gabba-gmp"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'net-http-persistent', '~> 2.9'
23
+ s.add_development_dependency 'rake', '~> 10.1.0'
24
+ s.add_development_dependency 'rspec', '~> 2.14.1'
25
+ s.add_development_dependency 'webmock', '~> 1.13.0'
26
+ end
@@ -0,0 +1,8 @@
1
+ module GabbaGMP
2
+ class GabbaGMP
3
+ class Campaign
4
+ attr_accessor :name, :source, :medium, :keyword, :content
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,23 @@
1
+ module GabbaGMP
2
+ class GabbaGMP
3
+ module CustomVars
4
+ # Public: Set a custom variable to be passed along and logged by Google Analytics
5
+ # (http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html)
6
+ #
7
+ # index - Integer between 1 and 200 for this custom dimension (limit is 20 normally, but is 200 for GA Premium)
8
+ # name - String with the name of the custom dimension
9
+ # value - String with the value for the custom dimension
10
+ #
11
+ # Example:
12
+ #
13
+ # g.set_custom_var(1, 'awesomeness', 'supreme')
14
+ #
15
+ # Returns array with the custom variable data
16
+ def set_custom_var(index, name, value)
17
+ raise "Index must be between 1 and #{GabbaGMP::DIMENSION_MAX}" unless (1..GabbaGMP::DIMENSION_MAX).include?(index)
18
+
19
+ @sessionopts["dimension_#{index}".to_sym] = value
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module GabbaGMP
2
+ class GabbaGMP
3
+ module Event
4
+ # Public: Record an event in Google Analytics
5
+ # (https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide)
6
+ #
7
+ # category::
8
+ # action::
9
+ # label::
10
+ # value::
11
+ # options:: Optional. Any additional parameters to send with the page view
12
+ #
13
+ # Example:
14
+ #
15
+ # g.event("Videos", "Play", "ID", "123")
16
+ #
17
+ def event(category, action, label = nil, value = nil, options = {})
18
+ hey(event_params(category, action, label, value, options))
19
+ end
20
+
21
+ # Public: Renders event params data in the format needed for GA
22
+ # Called before actually sending the data along to GA in GabbaGMP#event
23
+ def event_params(category, action, label, value, event_options)
24
+ options = {
25
+ hit_type: "event",
26
+ event_category: category,
27
+ event_action: action
28
+ }
29
+ options[:event_label] = label if label.present?
30
+ options[:event_value] = value if value.present?
31
+ @sessionopts.merge(options).merge!(event_options)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,142 @@
1
+ # yo, easy server-side tracking for Google Analytics... hey!
2
+ require 'uri'
3
+ require 'net/http'
4
+ require 'ipaddr'
5
+ require 'cgi'
6
+ require 'net/http/persistent'
7
+
8
+ require "#{File.dirname(__FILE__)}/parameter_map"
9
+ require "#{File.dirname(__FILE__)}/campaign"
10
+ require "#{File.dirname(__FILE__)}/custom_vars"
11
+ require "#{File.dirname(__FILE__)}/event"
12
+ require "#{File.dirname(__FILE__)}/page_view"
13
+ require "#{File.dirname(__FILE__)}/version"
14
+
15
+ module GabbaGMP
16
+
17
+ class GoogleAnalyticsInvalidParameterError < RuntimeError; end
18
+ class GoogleAnalyticsRequiredParameterMissingError < RuntimeError; end
19
+ class GoogleAnalyticsParameterNotFoundError < RuntimeError; end
20
+ class NoGoogleAnalyticsAccountError < RuntimeError; end
21
+ class NoGoogleAnalyticsDomainError < RuntimeError; end
22
+ class GoogleAnalyticsNetworkError < RuntimeError; end
23
+
24
+ class GabbaGMP
25
+ GOOGLE_HOST = "www.google-analytics.com"
26
+ BEACON_PATH = "/collect"
27
+ USER_AGENT = "Gabba GMP #{VERSION} Agent"
28
+
29
+ include ParameterMap
30
+ include CustomVars
31
+ include Event
32
+ include PageView
33
+
34
+ ESCAPES = %w{ ' ! * ) }
35
+
36
+ attr_accessor :debug
37
+
38
+ # Public: Initialize Gabba Google Analytics Tracking Object.
39
+ #
40
+ # ga_acct - A String containing your Google Analytics account id.
41
+ # domain - A String containing which domain you want the tracking data to be logged from.
42
+ # visitor_uuid - a uuid to uniquely identify the user - use SecureRandom.uuid to generate
43
+ # client_ip - The IP address of the connected client
44
+ # agent - A String containing the user agent you want the tracking to appear to be coming from.
45
+ # Defaults to "Gabba 0.2 Agent" or whatever the correct version is.
46
+ # Example:
47
+ #
48
+ # g = GabbaGMP::GabbaGMP.new("UT-1234", "mydomain.com")
49
+ #
50
+ def initialize(ga_tracking_id, request, cookies, options = {})
51
+ client_id_cookie = options[:client_id_cookie_sym]
52
+ client_id_cookie = :utm_visitor_uuid if !client_id_cookie.present? or !client_id_cookie.kind_of? Symbol
53
+
54
+ if !cookies[client_id_cookie].present?
55
+ cookie_expiry = options[:client_id_cookie_expiry] ? options[:client_id_cookie_expiry] : 1.year.from_now
56
+ cookies[client_id_cookie] = { value: "#{SecureRandom.uuid}", expires: cookie_expiry}
57
+ end
58
+
59
+ @sessionopts = {protocol_version: 1,
60
+ tracking_id: ga_tracking_id,
61
+ document_host: request.host,
62
+ client_id: cookies[client_id_cookie],
63
+ user_ip_address: request.remote_ip,
64
+ user_agent: request.env["HTTP_USER_AGENT"]}
65
+
66
+ debug = false
67
+ end
68
+
69
+
70
+ # Public: Set the session's parameters. This will be added to all actions that are sent to analytics.
71
+ #
72
+ # See:: ParameterMap:GA_PARAMS
73
+ def add_options(options)
74
+ options.keys.each do |key|
75
+ raise GoogleAnalyticsParameterNotFoundError, "Parameter '#{key}'" unless GA_PARAMS[key].present?
76
+ end
77
+
78
+ @sessionopts.merge!(options)
79
+ self
80
+ end
81
+
82
+ # Public: Set the campaign details from a campaign object. You can also use your own Campaign object so long
83
+ # as they support the 5 methods (name, source, medium, keyword, content)
84
+ def campaign=(campaign)
85
+ campaign ||= Campaign.new
86
+ {}.tap do |campaign_params|
87
+ @sessionopts[:campaign_name] = campaign.name
88
+ @sessionopts[:campaign_name] ||= "(direct)"
89
+
90
+ @sessionopts[:campaign_source] = campaign.source
91
+ @sessionopts[:campaign_source] ||= "(direct)"
92
+
93
+ @sessionopts[:campaign_medium] = campaign.medium
94
+ @sessionopts[:campaign_medium] ||= "(none)"
95
+
96
+ @sessionopts[:campaign_keyword] = campaign.keyword if campaign.keyword.present?
97
+
98
+ @sessionopts[:campaign_content] = campaign.content if campaign.content.present?
99
+ end
100
+ end
101
+
102
+ # Sanity check that we have needed params to even call GA
103
+ def validate_session_parameters(params)
104
+ raise GoogleAnalyticsRequiredParameterMissingError, "Protocol version is required" unless params[:protocol_version].present?
105
+ raise GoogleAnalyticsRequiredParameterMissingError, "Tracking id is required" unless params[:tracking_id].present?
106
+ raise GoogleAnalyticsRequiredParameterMissingError, "Client id is required" unless params[:client_id].present?
107
+ raise GoogleAnalyticsRequiredParameterMissingError, "Hit type is required" unless params[:hit_type].present?
108
+
109
+ params.keys.each do |param|
110
+ raise GoogleAnalyticsInvalidParameterError, "The parameter '#{param}' is not currently recognised." unless GA_PARAMS[param].present?
111
+ end
112
+ end
113
+
114
+ # makes the tracking call to Google Analytics
115
+ def hey(params)
116
+ validate_session_parameters(params)
117
+ query = params.map {|k,v| "#{GA_PARAMS[k]}=#{URI.escape("#{v}", Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}" }.join('&')
118
+
119
+ @http ||= Net::HTTP::Persistent.new 'GabbaGMP'
120
+
121
+ Rails.logger.info "GABBA_GMP: request params: #{query}" if debug
122
+
123
+ request = Net::HTTP::Get.new("#{BEACON_PATH}?#{query}")
124
+ request["User-Agent"] = URI.escape(params[:user_agent])
125
+ request["Accept"] = "*/*"
126
+ uri = URI "http://#{GOOGLE_HOST}/#{BEACON_PATH}"
127
+ response = @http.request(uri, request)
128
+
129
+ raise GoogleAnalyticsNetworkError unless response.code == "200"
130
+ response
131
+ end
132
+
133
+ def escape(t)
134
+ return t if !t || (/\w/ !~ t.to_s)
135
+
136
+ t.to_s.gsub(/[\*'!\)]/) do |m|
137
+ "'#{ESCAPES.index(m)}"
138
+ end
139
+ end
140
+ end
141
+ end
142
+
@@ -0,0 +1,30 @@
1
+ module GabbaGMP
2
+ class GabbaGMP
3
+ module PageView
4
+ # Public: Record a page view in Google Analytics
5
+ #
6
+ # request:: String with the path for the page view
7
+ # title:: Optional. String with the page title for the page view
8
+ # options:: Optional. Any additional parameters to send with the page view
9
+ #
10
+ # Example:
11
+ #
12
+ # g.page_view(request, "page title")
13
+ #
14
+ def page_view(request, title = nil, options = {})
15
+
16
+ hey(page_view_params(title, request.fullpath, options))
17
+ end
18
+
19
+ # Public: Renders the page view params data in the format needed for GA
20
+ # Called before actually sending the data along to GA.
21
+ def page_view_params(title, doc_path, options)
22
+ @sessionopts.merge({
23
+ hit_type: "pageview",
24
+ document_title: title,
25
+ document_path: doc_path
26
+ }).merge!(options)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ module GabbaGMP
2
+ class GabbaGMP
3
+ DIMENSION_MAX = 200
4
+ module ParameterMap
5
+ GA_PARAMS = {
6
+ protocol_version: :v,
7
+ tracking_id: :tid,
8
+
9
+ user_ip_address: :uip,
10
+ client_id: :cid,
11
+ user_agent: :ua,
12
+
13
+ hit_type: :t,
14
+
15
+ document_title: :dt,
16
+ document_path: :dp,
17
+ document_referrer: :dr,
18
+ document_host: :dh,
19
+
20
+ event_category: :ec,
21
+ event_action: :ea,
22
+ event_label: :el,
23
+ event_value: :ev,
24
+
25
+ campaign_name: :cn,
26
+ campaign_source: :cs,
27
+ campaign_medium: :cm,
28
+ campaign_keyword: :ck,
29
+ campaign_content: :cc
30
+
31
+ }.merge(Hash[(1..GabbaGMP::DIMENSION_MAX).map {|index| ["dimension_#{index}".to_sym, "cd#{index}".to_sym]}])
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module GabbaGMP
2
+ unless const_defined?('VERSION')
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
data/lib/gabba-gmp.rb ADDED
@@ -0,0 +1 @@
1
+ require 'gabba-gmp/gabba_gmp'
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gabba-gmp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Julian West
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-09-08 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: net-http-persistent
16
+ requirement: &23922576 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.9'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *23922576
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &23922276 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 10.1.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *23922276
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &23922000 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.14.1
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *23922000
47
+ - !ruby/object:Gem::Dependency
48
+ name: webmock
49
+ requirement: &23921724 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.13.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *23921724
58
+ description: Google Measurement Protocol rewite of the Gabba library
59
+ email:
60
+ - julz dot west at gmail dot com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitattributes
66
+ - .gitignore
67
+ - Gemfile
68
+ - LICENSE
69
+ - Rakefile
70
+ - Readme.md
71
+ - gabba-gmp.gemspec
72
+ - lib/gabba-gmp.rb
73
+ - lib/gabba-gmp/campaign.rb
74
+ - lib/gabba-gmp/custom_vars.rb
75
+ - lib/gabba-gmp/event.rb
76
+ - lib/gabba-gmp/gabba_gmp.rb
77
+ - lib/gabba-gmp/page_view.rb
78
+ - lib/gabba-gmp/parameter_map.rb
79
+ - lib/gabba-gmp/version.rb
80
+ homepage: https://github.com/fuzzyjulz/gabba-gmp
81
+ licenses:
82
+ - MIT
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project: gabba-gmp
101
+ rubygems_version: 1.7.2
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Google Measurement Protocol rewite of the Gabba library
105
+ test_files: []