gabbara 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +35 -0
- data/README +14 -0
- data/Rakefile +8 -0
- data/gabbara.gemspec +23 -0
- data/lib/gabbara.rb +2 -0
- data/lib/gabbara/gabba.rb +114 -0
- data/lib/gabbara/version.rb +3 -0
- data/spec/gabba_spec.rb +80 -0
- data/spec/spec_helper.rb +4 -0
- metadata +93 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
gabbara (0.0.2)
|
5
|
+
activesupport
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (3.0.3)
|
11
|
+
addressable (2.2.2)
|
12
|
+
crack (0.1.8)
|
13
|
+
diff-lcs (1.1.2)
|
14
|
+
rack (1.2.1)
|
15
|
+
rspec (2.1.0)
|
16
|
+
rspec-core (~> 2.1.0)
|
17
|
+
rspec-expectations (~> 2.1.0)
|
18
|
+
rspec-mocks (~> 2.1.0)
|
19
|
+
rspec-core (2.1.0)
|
20
|
+
rspec-expectations (2.1.0)
|
21
|
+
diff-lcs (~> 1.1.2)
|
22
|
+
rspec-mocks (2.1.0)
|
23
|
+
webmock (1.6.1)
|
24
|
+
addressable (>= 2.2.2)
|
25
|
+
crack (>= 0.1.7)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
activesupport
|
32
|
+
gabbara!
|
33
|
+
rack
|
34
|
+
rspec
|
35
|
+
webmock
|
data/README
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
== Simple class to send custom server-side events to Google Analytics
|
2
|
+
|
3
|
+
Heavily influenced by the http://code.google.com/p/serversidegoogleanalytics
|
4
|
+
|
5
|
+
Based on deadprogrammer's gabba (https://github.com/hybridgroup/gabba)
|
6
|
+
|
7
|
+
HOW TO USE:
|
8
|
+
|
9
|
+
- Track page views
|
10
|
+
Gabbara::Gabba.new("UT-1234", "mydomain.com").page_view("something", "track/me")
|
11
|
+
|
12
|
+
- Track custom events
|
13
|
+
Gabbara::Gabba.new("UT-1234", "mydomain.com").event("Videos", "Play", "ID", "123")
|
14
|
+
|
data/Rakefile
ADDED
data/gabbara.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "gabbara/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "gabbara"
|
7
|
+
s.version = Gabbara::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Michael Reinsch", "Ron Evans"]
|
10
|
+
s.email = ["michael@mobalean.com", "ron dot evans at gmail dot com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Easy server-side tracking for Google Analytics}
|
13
|
+
s.description = %q{Easy server-side tracking for Google Analytics}
|
14
|
+
|
15
|
+
s.rubyforge_project = "gabbara"
|
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("activesupport")
|
23
|
+
end
|
data/lib/gabbara.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# yo, easy server-side tracking for Google Analytics... hey!
|
2
|
+
require "uri"
|
3
|
+
require "net/http"
|
4
|
+
require 'cgi'
|
5
|
+
require 'ipaddr'
|
6
|
+
require 'active_support/core_ext/array/extract_options'
|
7
|
+
|
8
|
+
module Gabbara
|
9
|
+
|
10
|
+
class GoogleAnalyticsSetupError < RuntimeError; end
|
11
|
+
class GoogleAnalyticsNetworkError < RuntimeError; end
|
12
|
+
|
13
|
+
class Gabba
|
14
|
+
GOOGLE_HOST = "www.google-analytics.com"
|
15
|
+
BEACON_PATH = "/__utm.gif"
|
16
|
+
USER_AGENT = "Gabbara #{VERSION} Agent"
|
17
|
+
|
18
|
+
attr_accessor :logger, :utmwv, :utmn, :utmhn, :utmcs, :utmul, :utmp, :utmac, :utmt, :utmcc, :utmr, :utmip, :user_agent
|
19
|
+
|
20
|
+
# create with:
|
21
|
+
# ga_acct, domain
|
22
|
+
# or
|
23
|
+
# ga_acct, :request => request
|
24
|
+
def initialize(ga_acct, *args)
|
25
|
+
@utmwv = "4.4sh" # GA version
|
26
|
+
@utmcs = "UTF-8" # charset
|
27
|
+
@utmul = "en-us" # language
|
28
|
+
@utmn = rand(8999999999) + 1000000000
|
29
|
+
@user_agent = Gabba::USER_AGENT
|
30
|
+
|
31
|
+
@utmac = ga_acct
|
32
|
+
opts = args.extract_options!
|
33
|
+
@utmhn = args.shift
|
34
|
+
opts.each {|key, value| self.send("#{key}=", value) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def request=(request)
|
38
|
+
@user_agent = request.env["HTTP_USER_AGENT"] || Gabba::USER_AGENT
|
39
|
+
@utmhn ||= request.env["SERVER_NAME"] || ""
|
40
|
+
@utmr = request.params['utmr'].blank? ? (request.env['HTTP_REFERER'].blank? ? "-" : request.env['HTTP_REFERER']) : request.params[:utmr]
|
41
|
+
@utmp = request.params['utmp'].blank? ? (request.env['REQUEST_URI'] || "") : request.params['utmp']
|
42
|
+
# the last octect of the IP address is removed to anonymize the user.
|
43
|
+
@utmip = IPAddr.new(request.env["REMOTE_ADDR"]).mask(24).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# parameters:
|
47
|
+
# title, page, :utmvid => visitor_id
|
48
|
+
# or
|
49
|
+
# title, :utmvid => visitor_id
|
50
|
+
# if page is obmitted, it is taken from the request
|
51
|
+
def page_view(title, *args)
|
52
|
+
check_account_params
|
53
|
+
opts = args.extract_options!
|
54
|
+
opts[:utmdt] = title
|
55
|
+
opts[:utmp] = args.shift || @utmp
|
56
|
+
hey(opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
# parameters:
|
60
|
+
# category, action, label = nil, value = nil, :utmvid => visitor_id
|
61
|
+
def event(*args)
|
62
|
+
check_account_params
|
63
|
+
opts = args.extract_options!
|
64
|
+
opts[:utmt] = 'event'
|
65
|
+
opts[:utme] = event_data(*args)
|
66
|
+
hey(opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def default_params
|
72
|
+
{ :utmwv => @utmwv,
|
73
|
+
:utmn => @utmn,
|
74
|
+
:utmhn => @utmhn,
|
75
|
+
:utmcs => @utmcs,
|
76
|
+
:utmul => @utmul,
|
77
|
+
:utmhid => rand(8999999999) + 1000000000,
|
78
|
+
:utmac => @utmac,
|
79
|
+
:utmcc => @utmcc || cookie_params,
|
80
|
+
:utmr => @utmr,
|
81
|
+
:utmp => @utmp,
|
82
|
+
:utmip => @utmip }
|
83
|
+
end
|
84
|
+
|
85
|
+
def event_data(category, action, label = nil, value = nil)
|
86
|
+
data = "5(#{category}*action" + (label ? "*#{label})" : ")")
|
87
|
+
data += "(#{value})" if value
|
88
|
+
end
|
89
|
+
|
90
|
+
# create magical cookie params used by GA for its own nefarious purposes
|
91
|
+
def cookie_params(utma1 = rand(89999999) + 10000000, utma2 = rand(1147483647) + 1000000000, today = Time.now)
|
92
|
+
"__utma=1.#{utma1}00145214523.#{utma2}.#{today.to_i}.#{today.to_i}.15;+__utmz=1.#{today.to_i}.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);"
|
93
|
+
end
|
94
|
+
|
95
|
+
# sanity check that we have needed params to even call GA
|
96
|
+
def check_account_params
|
97
|
+
raise GoogleAnalyticsSetupError, "no account" if @utmac.blank?
|
98
|
+
raise GoogleAnalyticsSetupError, "no domain" if @utmhn.blank?
|
99
|
+
end
|
100
|
+
|
101
|
+
# makes the tracking call to Google Analytics
|
102
|
+
def hey(params)
|
103
|
+
headers = {"User-Agent" => URI.escape(user_agent)}
|
104
|
+
params = default_params.merge(params).reject{|k,v| v.blank? }
|
105
|
+
logger.info("GA: #{params.inspect}") if logger
|
106
|
+
query = params.map {|k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
|
107
|
+
req = Net::HTTP::Get.new("#{BEACON_PATH}?#{query}", headers)
|
108
|
+
res = Net::HTTP.start(GOOGLE_HOST) do |http|
|
109
|
+
http.request(req)
|
110
|
+
end
|
111
|
+
raise GoogleAnalyticsNetworkError unless res.code == "200"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/gabba_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Gabbara::Gabba do
|
4
|
+
|
5
|
+
describe "parameter checking" do
|
6
|
+
it "must require GA account for page_view" do
|
7
|
+
expect {Gabbara::Gabba.new(nil, nil).page_view("thing", "thing")}.to raise_error(Gabbara::GoogleAnalyticsSetupError)
|
8
|
+
end
|
9
|
+
it "must require GA domain for page_view" do
|
10
|
+
expect {Gabbara::Gabba.new("abs", nil).page_view("thing", "thing")}.to raise_error(Gabbara::GoogleAnalyticsSetupError)
|
11
|
+
end
|
12
|
+
it "must require GA account for event" do
|
13
|
+
expect {Gabbara::Gabba.new(nil, nil).event("cat1", "act1", "lab1", "val1")}.to raise_error(Gabbara::GoogleAnalyticsSetupError)
|
14
|
+
end
|
15
|
+
it "must require GA domain for event" do
|
16
|
+
expect {Gabbara::Gabba.new("abs", nil).event("cat1", "act1", "lab1", "val1")}.to raise_error(Gabbara::GoogleAnalyticsSetupError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "when tracking page views" do
|
21
|
+
before do
|
22
|
+
stub_analytics "utmdt"=>"title", "utmp"=>"/page/path"
|
23
|
+
@gabba = Gabbara::Gabba.new("UC-123", "domain", :utmn => "1009731272", :utmcc => '')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "must do a request to google" do
|
27
|
+
@gabba.page_view("title", "/page/path", :utmhid => "6783939397")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "when tracking page views from request" do
|
32
|
+
before do
|
33
|
+
stub_analytics "DoCoMo", "utmdt"=>"title", "utmhn"=>"test.local", "utmp"=>"/test", "utmip"=>"127.0.0.0", "utmr"=>"-"
|
34
|
+
@gabba = Gabbara::Gabba.new("UC-123", :request => test_request, :utmn => "1009731272", :utmcc => '')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must to a request to google" do
|
38
|
+
@gabba.page_view("title", :utmhid => "6783939397")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when tracking page views from request with visitor_id" do
|
43
|
+
before do
|
44
|
+
stub_analytics "DoCoMo", "utmdt"=>"title", "utmhn"=>"test.local", "utmp"=>"/test", "utmip"=>"127.0.0.0", "utmr"=>"-", "utmvid" => "0x16741532543"
|
45
|
+
@gabba = Gabbara::Gabba.new("UC-123", :request => test_request, :utmn => "1009731272", :utmcc => '')
|
46
|
+
end
|
47
|
+
|
48
|
+
it "must to a request to google" do
|
49
|
+
@gabba.page_view("title", :utmhid => "6783939397", :utmvid => "0x16741532543")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "when tracking custom events" do
|
54
|
+
before do
|
55
|
+
stub_analytics "utme"=>"5(cat1*action*lab1)(val1)", "utmt"=>"event"
|
56
|
+
@gabba = Gabbara::Gabba.new("UC-123", "domain", :utmn => "1009731272", :utmcc => '')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "must do a request to google" do
|
60
|
+
@gabba.event("cat1", "act1", "lab1", "val1", :utmhid => "6783939397")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def stub_analytics(*args)
|
65
|
+
expected_params = args.extract_options!
|
66
|
+
user_agent = args.shift || "Gabbara%20#{Gabbara::VERSION}%20Agent"
|
67
|
+
expected_params = { "utmac"=>"UC-123", "utmcs"=>"UTF-8", "utmhid"=>"6783939397", "utmhn"=>"domain", "utmn"=>"1009731272", "utmul"=>"en-us", "utmwv"=>"4.4sh" }.merge(expected_params).reject{|k,v| v.blank? }
|
68
|
+
query = expected_params.map {|k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
|
69
|
+
s = stub_request(:get, "http://www.google-analytics.com:80/__utm.gif?#{query}").
|
70
|
+
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>user_agent}).
|
71
|
+
to_return(:status => 200, :body => "", :headers => {})
|
72
|
+
#puts s.request_pattern
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_request(params = {})
|
76
|
+
params = {"REMOTE_ADDR" => "127.0.0.1", "HTTP_USER_AGENT" => "DoCoMo"}.merge(params)
|
77
|
+
Rack::Request.new(Rack::MockRequest.env_for("http://test.local/utm.gif?utmp=/test", params))
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gabbara
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Reinsch
|
14
|
+
- Ron Evans
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-12-20 00:00:00 +09:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: activesupport
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Easy server-side tracking for Google Analytics
|
37
|
+
email:
|
38
|
+
- michael@mobalean.com
|
39
|
+
- ron dot evans at gmail dot com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- Gemfile
|
49
|
+
- Gemfile.lock
|
50
|
+
- README
|
51
|
+
- Rakefile
|
52
|
+
- gabbara.gemspec
|
53
|
+
- lib/gabbara.rb
|
54
|
+
- lib/gabbara/gabba.rb
|
55
|
+
- lib/gabbara/version.rb
|
56
|
+
- spec/gabba_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: ""
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project: gabbara
|
88
|
+
rubygems_version: 1.3.7
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Easy server-side tracking for Google Analytics
|
92
|
+
test_files: []
|
93
|
+
|