├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── Rakefile ├── Readme.md ├── gabba.gemspec ├── lib ├── gabba.rb └── gabba │ ├── custom_vars.rb │ ├── event.rb │ ├── gabba.rb │ ├── item.rb │ ├── page_view.rb │ ├── transaction.rb │ └── version.rb └── spec ├── lib ├── custom_var_spec.rb ├── event_spec.rb ├── gabba_spec.rb ├── item_spec.rb ├── page_view_spec.rb ├── transaction_spec.rb └── yo_gabba_gabba_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/* 2 | *.gem 3 | .bundle 4 | Guardfile 5 | Gemfile.lock 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | script: "bundle exec rspec" 3 | rvm: 4 | - 1.9.2 5 | - 1.9.3 6 | - 2.0.0 7 | - jruby-18mode 8 | - jruby-19mode 9 | - rbx-18mode 10 | - rbx-19mode 11 | - ree 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in gabba.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 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 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Gabba 2 | 3 | [![Build Status](https://travis-ci.org/hybridgroup/gabba.png)](https://travis-ci.org/hybridgroup/gabba) 4 | 5 | Simple class to send custom server-side events to Google Analytics 6 | 7 | Heavily influenced by the [serversidegoogleanalytics][] project. 8 | 9 | ## Examples 10 | 11 | ### Track page views 12 | 13 | ```ruby 14 | Gabba::Gabba.new("UT-1234", "mydomain.com").page_view("something", "track/me") 15 | ``` 16 | 17 | ### Track custom events 18 | 19 | ```ruby 20 | Gabba::Gabba.new("UT-1234", "mydomain.com").event("Videos", "Play", "ID", "123", true) 21 | ``` 22 | 23 | ### Works with existing client-side Google Analytics cookies 24 | 25 | ```ruby 26 | gabba = Gabba::Gabba.new("UT-1234", "mydomain.com") 27 | 28 | # grab the __utma and (optionally) __utmz unique identifiers 29 | gabba.identify_user(cookies[:__utma], cookies[:__utmz]) 30 | 31 | # trigger actions as normal 32 | gabba.page_view("something", "track/me") 33 | ``` 34 | 35 | ### Setting custom vars 36 | 37 | ```ruby 38 | # Index: 1 through 50 39 | index = 1 40 | 41 | # Scope: VISITOR, SESSION or PAGE 42 | scope = Gabba::Gabba::VISITOR 43 | 44 | # Set var 45 | gabba.set_custom_var(index, 'Name', 'Value', scope) 46 | 47 | # Track the event (all vars will be included) 48 | gabba.event(...) 49 | 50 | # Track the page view (all vars will be included) 51 | gabba.page_view(...) 52 | ``` 53 | 54 | ### Removing custom vars 55 | 56 | ```ruby 57 | # Index: 1 through 50 58 | index = 1 59 | 60 | # Delete var with this index 61 | gabba.delete_custom_var index 62 | ``` 63 | 64 | ### Track ecommerce transactions 65 | 66 | ```ruby 67 | g = Gabba::Gabba.new("UT-6666", "myawesomeshop.net") 68 | g.transaction("123456789", "1000.00", 'Acme Clothing', '1.29', '5.00', 'Los Angeles', 'California', 'USA') 69 | ``` 70 | 71 | ### License 72 | 73 | Gabba is released under the [MIT License](http://opensource.org/licenses/MIT). 74 | 75 | 76 | [serversidegoogleanalytics]: http://code.google.com/p/serversidegoogleanalytics 77 | -------------------------------------------------------------------------------- /gabba.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path '../lib/gabba/version', __FILE__ 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "gabba" 6 | s.version = Gabba::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.authors = ["Ron Evans"] 9 | s.email = ["ron dot evans at gmail dot com"] 10 | s.homepage = "https://github.com/hybridgroup/gabba" 11 | s.summary = %q{Easy server-side tracking for Google Analytics} 12 | s.description = %q{Easy server-side tracking for Google Analytics} 13 | s.license = "MIT" 14 | 15 | s.rubyforge_project = "gabba" 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 27 | -------------------------------------------------------------------------------- /lib/gabba.rb: -------------------------------------------------------------------------------- 1 | require 'gabba/gabba' 2 | -------------------------------------------------------------------------------- /lib/gabba/custom_vars.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | class Gabba 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 50 for this custom variable (limit is 5 normally, but is 50 for GA Premium) 8 | # name - String with the name of the custom variable 9 | # value - String with the value for teh custom variable 10 | # scope - Integer with custom variable scope must be 1 (VISITOR), 2 (SESSION) or 3 (PAGE) 11 | # 12 | # Example: 13 | # 14 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 15 | # g.set_custom_var(1, 'awesomeness', 'supreme', Gabba::VISITOR) 16 | # # => ['awesomeness', 'supreme', 1] 17 | # 18 | # Returns array with the custom variable data 19 | def set_custom_var(index, name, value, scope) 20 | raise "Index must be between 1 and 50" unless (1..50).include?(index) 21 | raise "Scope must be 1 (VISITOR), 2 (SESSION) or 3 (PAGE)" unless (1..3).include?(scope) 22 | 23 | @custom_vars[index] = [ name, value, scope ] 24 | end 25 | 26 | # Public: Delete a previously set custom variable so if is not passed along and logged by Google Analytics 27 | # (http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html) 28 | # 29 | # index - Integer between 1 and 5 for this custom variable 30 | # 31 | # Example: 32 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 33 | # g.delete_custom_var(1) 34 | # 35 | def delete_custom_var(index) 36 | raise "Index must be between 1 and 5" unless (1..5).include?(index) 37 | 38 | @custom_vars.delete_at(index) 39 | end 40 | 41 | # Public: Renders the custom variable data in the format needed for GA 42 | # (http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html) 43 | # Called before actually sending the data along to GA. 44 | def custom_var_data 45 | names = [] 46 | values = [] 47 | scopes = [] 48 | 49 | idx = 1 50 | @custom_vars.each_with_index do |(n, v, s), i| 51 | next if !n || !v || (/\w/ !~ n) || (/\w/ !~ v) 52 | prefix = "#{i}!" if idx != i 53 | names << "#{prefix}#{escape(n)}" 54 | values << "#{prefix}#{escape(v)}" 55 | scopes << "#{prefix}#{escape(s)}" 56 | idx = i + 1 57 | end 58 | 59 | names.empty? ? "" : "8(#{names.join('*')})9(#{values.join('*')})11(#{scopes.join('*')})" 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/gabba/event.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | class Gabba 3 | module Event 4 | # Public: Record an event in Google Analytics 5 | # (http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEventTracking.html) 6 | # 7 | # category - 8 | # action - 9 | # label - 10 | # value - 11 | # utmni - 12 | # utmhid - 13 | # 14 | # Example: 15 | # 16 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 17 | # g.event("Videos", "Play", "ID", "123", true) 18 | # 19 | def event(category, action, label = nil, value = nil, utmni = false, utmhid = random_id) 20 | check_account_params 21 | hey(event_params(category, action, label, value, utmni, utmhid)) 22 | end 23 | 24 | # Public: Renders event params data in the format needed for GA 25 | # Called before actually sending the data along to GA in Gabba#event 26 | def event_params(category, action, label = nil, value = nil, utmni = false, utmhid = false) 27 | raise ArgumentError.new("utmni must be a boolean") if (utmni.class != TrueClass && utmni.class != FalseClass) 28 | { 29 | :utmwv => @utmwv, 30 | :utmn => @utmn, 31 | :utmhn => @utmhn, 32 | :utmni => (1 if utmni), # 1 for non interactive event, excluded from bounce calcs 33 | :utmt => 'event', 34 | :utme => "#{event_data(category, action, label, value)}#{custom_var_data}", 35 | :utmcs => @utmcs, 36 | :utmul => @utmul, 37 | :utmhid => utmhid, 38 | :utmac => @utmac, 39 | :utmcc => @utmcc || cookie_params, 40 | :utmr => @utmr, 41 | :utmip => @utmip, 42 | :utme => self.custom_var_data 43 | } 44 | end 45 | 46 | # Public: Renders event individual param data in the format needed for GA 47 | # Called before actually sending the data along to GA in Gabba#event 48 | def event_data(category, action, label = nil, value = nil) 49 | data = "5(#{category}*#{action}" + (label ? "*#{label})" : ")") 50 | data += "(#{value})" if value 51 | data 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/gabba/gabba.rb: -------------------------------------------------------------------------------- 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__)}/custom_vars" 9 | require "#{File.dirname(__FILE__)}/event" 10 | require "#{File.dirname(__FILE__)}/item" 11 | require "#{File.dirname(__FILE__)}/page_view" 12 | require "#{File.dirname(__FILE__)}/transaction" 13 | require "#{File.dirname(__FILE__)}/version" 14 | 15 | module Gabba 16 | 17 | class NoGoogleAnalyticsAccountError < RuntimeError; end 18 | class NoGoogleAnalyticsDomainError < RuntimeError; end 19 | class GoogleAnalyticsNetworkError < RuntimeError; end 20 | 21 | class Gabba 22 | GOOGLE_HOST = "www.google-analytics.com" 23 | BEACON_PATH = "/__utm.gif" 24 | USER_AGENT = "Gabba #{VERSION} Agent" 25 | 26 | # Custom var levels 27 | VISITOR = 1 28 | SESSION = 2 29 | PAGE = 3 30 | 31 | include CustomVars 32 | include Event 33 | include Item 34 | include PageView 35 | include Transaction 36 | 37 | ESCAPES = %w{ ' ! * ) } 38 | 39 | attr_accessor :utmwv, :utmn, :utmhn, :utmcs, :utmul, :utmdt, :utmp, :utmac, :utmt, :utmcc, :user_agent, :utma, :utmz, :utmr, :utmip 40 | 41 | # Public: Initialize Gabba Google Analytics Tracking Object. 42 | # 43 | # ga_acct - A String containing your Google Analytics account id. 44 | # domain - A String containing which domain you want the tracking data to be logged from. 45 | # agent - A String containing the user agent you want the tracking to appear to be coming from. 46 | # Defaults to "Gabba 0.2 Agent" or whatever the corrent version is. 47 | # 48 | # Example: 49 | # 50 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 51 | # 52 | def initialize(ga_acct, domain, agent = Gabba::USER_AGENT) 53 | @utmwv = "4.4sh" # GA version 54 | @utmcs = "UTF-8" # charset 55 | @utmul = "en-us" # language 56 | 57 | @utmn = random_id 58 | @utmhid = random_id 59 | 60 | @utmac = ga_acct 61 | @utmhn = domain 62 | @user_agent = (agent && agent.length > 0) ? agent : Gabba::USER_AGENT 63 | 64 | @custom_vars = [] 65 | end 66 | 67 | # Public: provide the user's __utma and __utmz attributes from analytics cookie, allowing 68 | # better tracking of user flows 69 | # 70 | # Called before page_view etc 71 | # 72 | # Examples: 73 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 74 | # g.identify_user(cookies[:__utma], cookies[:__utmz]) 75 | # g.page_view("something", "track/me") 76 | # 77 | def identify_user(utma, utmz=nil) 78 | @utma = utma 79 | @utmz = utmz 80 | self 81 | end 82 | 83 | # Public: provide the utmr attribute, allowing for referral tracking 84 | # 85 | # Called before page_view etc 86 | # 87 | # Examples: 88 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 89 | # g.referer(request.env['HTTP_REFERER']) 90 | # g.page_view("something", "track/me") 91 | # 92 | def referer(utmr) 93 | @utmr = utmr 94 | self 95 | end 96 | 97 | # Public: provide the utmip attribute, allowing for IP address tracking 98 | # 99 | # Called before page_view etc 100 | # 101 | # Examples: 102 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 103 | # g.ip(request.env["REMOTE_ADDR"]) 104 | # g.page_view("something", "track/me") 105 | # 106 | def ip(utmip) 107 | @utmip = ::IPAddr.new(utmip).mask(24).to_s 108 | self 109 | end 110 | 111 | # create magical cookie params used by GA for its own nefarious purposes 112 | def cookie_params(utma1 = random_id, utma2 = rand(1147483647) + 1000000000, today = Time.now) 113 | @utma ||= "1.#{utma1}00145214523.#{utma2}.#{today.to_i}.#{today.to_i}.15" 114 | @utmz ||= "1.#{today.to_i}.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" 115 | "__utma=#{@utma};+__utmz=#{@utmz};" 116 | end 117 | 118 | # sanity check that we have needed params to even call GA 119 | def check_account_params 120 | raise NoGoogleAnalyticsAccountError unless @utmac 121 | raise NoGoogleAnalyticsDomainError unless @utmhn 122 | end 123 | 124 | # makes the tracking call to Google Analytics 125 | def hey(params) 126 | query = params.map {|k,v| "#{k}=#{URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}" }.join('&') 127 | 128 | @http ||= Net::HTTP::Persistent.new 'Gabba' 129 | 130 | request = Net::HTTP::Get.new("#{BEACON_PATH}?#{query}") 131 | request["User-Agent"] = URI.escape(user_agent) 132 | request["Accept"] = "*/*" 133 | uri = URI "http://#{GOOGLE_HOST}/#{BEACON_PATH}" 134 | response = @http.request(uri, request) 135 | 136 | raise GoogleAnalyticsNetworkError unless response.code == "200" 137 | response 138 | end 139 | 140 | def random_id 141 | rand 8999999999 + 1000000000 142 | end 143 | 144 | def escape(t) 145 | return t if !t || (/\w/ !~ t.to_s) 146 | 147 | t.to_s.gsub(/[\*'!\)]/) do |m| 148 | "'#{ESCAPES.index(m)}" 149 | end 150 | end 151 | end 152 | end 153 | 154 | # Allow for Yo::Gabba::Gabba 155 | module Yo ; Gabba = ::Gabba ; end 156 | -------------------------------------------------------------------------------- /lib/gabba/item.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | class Gabba 3 | module Item 4 | # Public: Track an item purchased in an ecommerce transaction to Google Analytics. 5 | # (http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEcommerce.html#_gat.GA_Tracker_._addItem) 6 | def add_item(order_id, item_sku, price, quantity, name = nil, category = nil, utmhid = random_id) 7 | check_account_params 8 | hey(item_params(order_id, item_sku, name, category, price, quantity, utmhid)) 9 | end 10 | 11 | # Public: Renders item purchase params data in the format needed for GA 12 | # Called before actually sending the data along to GA in Gabba#add_item 13 | def item_params(order_id, item_sku, name, category, price, quantity, utmhid) 14 | # '1234', // utmtid URL-encoded order ID - required 15 | # 'DD44', // utmipc SKU/code - required 16 | # 'T-Shirt', // utmipn product name 17 | # 'Green Medium', // utmiva category or variation 18 | # '11.99', // utmipr unit price - required 19 | # '1' // utmiqt quantity - required 20 | { 21 | :utmwv => @utmwv, 22 | :utmn => @utmn, 23 | :utmhn => @utmhn, 24 | :utmt => 'item', 25 | :utmcs => @utmcs, 26 | :utmul => @utmul, 27 | :utmhid => utmhid, 28 | :utmac => @utmac, 29 | :utmcc => @utmcc || cookie_params, 30 | :utmtid => order_id, 31 | :utmipc => item_sku, 32 | :utmipn => name, 33 | :utmiva => category, 34 | :utmipr => price, 35 | :utmiqt => quantity, 36 | :utmr => @utmr, 37 | :utmip => @utmip, 38 | :utme => self.custom_var_data 39 | } 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/gabba/page_view.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | class Gabba 3 | module PageView 4 | # Public: Record a page view in Google Analytics 5 | # 6 | # title - String with the page title for thr page view 7 | # page - String with the path for the page view 8 | # utmhid - String with the unique visitor id, defaults to a new random value 9 | # 10 | # Example: 11 | # 12 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 13 | # g.page_view("something", "track/me") 14 | # 15 | def page_view(title, page, utmhid = random_id) 16 | check_account_params 17 | hey(page_view_params(title, page, utmhid)) 18 | end 19 | 20 | # Public: Renders the page view params data in the format needed for GA 21 | # Called before actually sending the data along to GA. 22 | def page_view_params(title, page, utmhid = random_id) 23 | options = { 24 | :utmwv => @utmwv, 25 | :utmn => @utmn, 26 | :utmhn => @utmhn, 27 | :utmcs => @utmcs, 28 | :utmul => @utmul, 29 | :utmdt => title, 30 | :utmhid => utmhid, 31 | :utmp => page, 32 | :utmac => @utmac, 33 | :utmcc => @utmcc || cookie_params, 34 | :utmr => @utmr, 35 | :utmip => @utmip, 36 | :utme => self.custom_var_data 37 | } 38 | 39 | # Add custom vars if present 40 | cvd = custom_var_data 41 | options[:utme] = cvd if /\w/ =~ cvd 42 | 43 | options 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/gabba/transaction.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | class Gabba 3 | module Transaction 4 | # Public: Track an entire ecommerce transaction to Google Analytics in one call. 5 | # (http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEcommerce.html#_gat.GA_Tracker_._trackTrans) 6 | # 7 | # order_id - URL-encoded order ID (required). Maps to utmtid 8 | # total - Order total (required). Maps to utmtto 9 | # store_name - Affiliation or store name (default: nil). Maps to utmtst 10 | # tax - Sales tax (default: nil). Maps to utmttx 11 | # shipping - Shipping (default: nil). Maps to utmtsp 12 | # city - City (default: nil). Maps to utmtci 13 | # region - State or Provance (default: nil). Maps to utmtrg 14 | # country - Country (default: nil). Maps to utmtco 15 | # utmhid - String with the unique visitor id (default: random_id) 16 | # 17 | # Examples: 18 | # 19 | # g = Gabba::Gabba.new("UT-1234", "mydomain.com") 20 | # g.transaction("123456789", "1000.00") 21 | # 22 | # g = Gabba::Gabba.new("UT-6666", "myawesomeshop.net") 23 | # g.transaction("123456789", "1000.00", 'Acme Clothing', '1.29', '5.00', 'Los Angeles', 'California', 'USA') 24 | # 25 | def transaction(order_id, total, store_name = nil, tax = nil, shipping = nil, city = nil, region = nil, country = nil, utmhid = random_id) 26 | check_account_params 27 | hey(transaction_params(order_id, total, store_name, tax, shipping, city, region, country, utmhid)) 28 | end 29 | 30 | # Public: Renders transaction params data in the format needed for GA 31 | # Called before actually sending the data along to GA in Gabba#transaction 32 | def transaction_params(order_id, total, store_name, tax, shipping, city, region, country, utmhid) 33 | { 34 | :utmwv => @utmwv, 35 | :utmn => @utmn, 36 | :utmhn => @utmhn, 37 | :utmt => 'tran', 38 | :utmcs => @utmcs, 39 | :utmul => @utmul, 40 | :utmhid => utmhid, 41 | :utmac => @utmac, 42 | :utmcc => @utmcc || cookie_params, 43 | :utmtid => order_id, 44 | :utmtst => store_name, 45 | :utmtto => total, 46 | :utmttx => tax, 47 | :utmtsp => shipping, 48 | :utmtci => city, 49 | :utmtrg => region, 50 | :utmtco => country, 51 | :utmr => @utmr, 52 | :utmip => @utmip, 53 | :utme => self.custom_var_data 54 | } 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/gabba/version.rb: -------------------------------------------------------------------------------- 1 | module Gabba 2 | unless const_defined?('VERSION') 3 | VERSION = "1.0.1" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/lib/custom_var_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Gabba::Gabba do 4 | describe "#set_custom_var/#custom_var_data" do 5 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 6 | 7 | before do 8 | gabba.utmn = '1009731272' 9 | gabba.utmcc = '' 10 | end 11 | 12 | it "can return data for a valid custom variable" do 13 | gabba.set_custom_var 1, 'A (B*\'!)', 'Yes', Gabba::Gabba::SESSION 14 | expect(gabba.custom_var_data).to eq "8(A (B'2'0'1'3)9(Yes)11(2)" 15 | end 16 | 17 | it "can return data for several valid custom variables" do 18 | gabba.set_custom_var 1, 'A', 'Yes', Gabba::Gabba::SESSION 19 | gabba.set_custom_var 2, 'B', 'No', Gabba::Gabba::VISITOR 20 | expect(gabba.custom_var_data).to eq "8(A*B)9(Yes*No)11(2*1)" 21 | end 22 | 23 | it "defaults to an empty string" do 24 | expect(gabba.custom_var_data).to eq "" 25 | end 26 | 27 | it "doesn't return data for a variable with an empty value" do 28 | gabba.set_custom_var 1, 'A', 'Yes', Gabba::Gabba::SESSION 29 | gabba.set_custom_var 2, 'B', '', Gabba::Gabba::VISITOR 30 | gabba.set_custom_var 3, 'C', ' ', Gabba::Gabba::VISITOR 31 | gabba.set_custom_var 4, 'D', nil, Gabba::Gabba::VISITOR 32 | expect(gabba.custom_var_data).to eq "8(A)9(Yes)11(2)" 33 | end 34 | 35 | it "includes indices of the variables if non-sequential" do 36 | gabba.set_custom_var 2, 'A', 'Y', Gabba::Gabba::SESSION 37 | gabba.set_custom_var 4, 'D', 'N', Gabba::Gabba::VISITOR 38 | expect(gabba.custom_var_data).to eq "8(2!A*4!D)9(2!Y*4!N)11(2!2*4!1)" 39 | end 40 | 41 | it "raises an error if index is outside the 1-50 (incl) range" do 42 | expect{gabba.set_custom_var(0, 'A', 'B', 1)}.to raise_error(RuntimeError) 43 | expect{gabba.set_custom_var(51, 'A', 'B', 1)}.to raise_error(RuntimeError) 44 | end 45 | 46 | it "raises an error if scope is outside the 1-3 (incl) range" do 47 | expect{gabba.set_custom_var(1, 'A', 'B', 0)}.to raise_error(RuntimeError) 48 | expect{gabba.set_custom_var(1, 'A', 'B', 4)}.to raise_error(RuntimeError) 49 | end 50 | end 51 | 52 | describe "#delete_custom_var" do 53 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 54 | 55 | before do 56 | gabba.utmn = '1009731272' 57 | gabba.utmcc = '' 58 | end 59 | 60 | it "deletes the matching variable" do 61 | gabba.set_custom_var 1, 'A (B*\'!)', 'Yes', Gabba::Gabba::SESSION 62 | gabba.delete_custom_var 1 63 | expect(gabba.custom_var_data).to eq "" 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/lib/event_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe Gabba::Gabba do 3 | describe "#event" do 4 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 5 | 6 | before do 7 | gabba.utmn = '1009731272' 8 | gabba.utmcc = '' 9 | end 10 | 11 | it "requires a Google Analytics account" do 12 | expect{ 13 | Gabba::Gabba.new(nil, nil).event("cat1", "act1", "lab1", "val1") 14 | }.to raise_error Gabba::NoGoogleAnalyticsAccountError 15 | end 16 | 17 | it "requires a Google Analytics domain" do 18 | expect{ 19 | Gabba::Gabba.new('abs', nil).event("cat1", "act1", "lab1", "val1") 20 | }.to raise_error Gabba::NoGoogleAnalyticsDomainError 21 | end 22 | 23 | it "sends the request to Google" do 24 | stub_analytics( 25 | gabba.event_params "cat1", "act1", "lab1", "val1", false, "6783939397" 26 | ) 27 | event = gabba.event "cat1", "act1", "lab1", "val1", false, "6783939397" 28 | expect(event.code).to eq '200' 29 | end 30 | 31 | it 'can send non-interactive events to Google' do 32 | stub_analytics(gabba.event_params "cat1", "act1", "lab1", "val1") 33 | event = gabba.event "cat1", "act1", "lab1", "val1" 34 | expect(event.code).to eq '200' 35 | end 36 | end 37 | 38 | describe '#event_data' do 39 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 40 | 41 | it 'returns data formatted to send to Google' do 42 | data = gabba.event_data("cat1", "act1", "lab1", "val1") 43 | expect(data).to eq "5(cat1*act1*lab1)(val1)" 44 | end 45 | 46 | it 'can create event data with only category and action' do 47 | expect(gabba.event_data("cat1", "act1")).to eq "5(cat1*act1)" 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/lib/gabba_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Gabba::Gabba do 4 | describe '#user_agent' do 5 | describe "when given" do 6 | let(:gabba) { Gabba::Gabba.new 'abc', '123', 'CUSTOM USER AGENT' } 7 | 8 | it 'returns the provided User Agent' do 9 | expect(gabba.user_agent).to eq 'CUSTOM USER AGENT' 10 | end 11 | end 12 | 13 | describe "when not specified" do 14 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 15 | 16 | it 'returns the default User Agent' do 17 | expect(gabba.user_agent).to eq Gabba::Gabba::USER_AGENT 18 | end 19 | end 20 | 21 | describe "when nil" do 22 | let(:gabba) { Gabba::Gabba.new 'abc', '123', nil } 23 | 24 | it 'returns the default User Agent' do 25 | expect(gabba.user_agent).to eq Gabba::Gabba::USER_AGENT 26 | end 27 | end 28 | 29 | describe "default" do 30 | it "includes the current version number" do 31 | expect(Gabba::Gabba::USER_AGENT).to eq "Gabba #{Gabba::VERSION} Agent" 32 | end 33 | end 34 | 35 | describe "when empty string" do 36 | let(:gabba) { Gabba::Gabba.new 'abc', '123', '' } 37 | 38 | it 'returns the default User Agent' do 39 | expect(gabba.user_agent).to eq Gabba::Gabba::USER_AGENT 40 | end 41 | end 42 | end 43 | 44 | describe "#identify_user" do 45 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 46 | 47 | before do 48 | gabba.utmn = '1009731272' 49 | gabba.utmcc = '' 50 | end 51 | 52 | it "uses the supplied utma value in the cookie params" do 53 | cookies = { :__utma => 'long_code' } 54 | gabba.identify_user cookies[:__utma] 55 | 56 | expect(gabba.cookie_params).to match /utma=long_code;/ 57 | expect(gabba.cookie_params).to match /utmz=.*direct.*;/ 58 | end 59 | 60 | it "should use the optional utmz value in the cookie params" do 61 | cookies = { :__utma => 'long_code', :__utmz => 'utmz_code' } 62 | gabba.identify_user cookies[:__utma], cookies[:__utmz] 63 | 64 | expect(gabba.cookie_params).to match /utma=long_code;/ 65 | expect(gabba.cookie_params).to match /utmz=utmz_code;/ 66 | end 67 | end 68 | 69 | describe "#referer" do 70 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 71 | let(:referer) { "http://www.someurl.com/blah/blah" } 72 | 73 | before do 74 | gabba.utmn = '1009731272' 75 | gabba.utmcc = '' 76 | gabba.referer referer 77 | end 78 | 79 | it "uses the specified referer in page_view_params" do 80 | page_view_params = gabba.page_view_params 'whocares', 'doesntmatter' 81 | expect(page_view_params[:utmr]).to eq referer 82 | end 83 | 84 | it "uses the specified referer in event_params" do 85 | event_params = gabba.event_params 'whocares', 'doesntmatter' 86 | expect(event_params[:utmr]).to eq referer 87 | end 88 | 89 | it "should use the specified referer in transaction_params" do 90 | transaction_params = gabba.transaction_params( 91 | 'order_id', 'total', 'store_name', 92 | 'tax', 'shipping', 'city', 93 | 'region', 'country', 'utmhid' 94 | ) 95 | expect(transaction_params[:utmr]).to eq referer 96 | end 97 | 98 | it "should use the specified referer in item_params" do 99 | item_params = gabba.item_params( 100 | 'order_id', 'item_sku', 'name', 101 | 'category', 'price', 'quantity', 'utmhid' 102 | ) 103 | expect(item_params[:utmr]).to eq referer 104 | end 105 | end 106 | 107 | describe "#ip" do 108 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 109 | let(:ip) { "192.168.1.1" } 110 | let(:masked_ip) { "192.168.1.0" } 111 | 112 | before do 113 | gabba.utmn = '1009731272' 114 | gabba.utmcc = '' 115 | gabba.ip ip 116 | end 117 | 118 | it "uses the specified IP in page_view_params" do 119 | page_view_params = gabba.page_view_params 'whocares', 'doesntmatter' 120 | expect(page_view_params[:utmip]).to eq masked_ip 121 | end 122 | 123 | it "uses the specified IP in event_params" do 124 | event_params = gabba.event_params 'whocares', 'doesntmatter' 125 | expect(event_params[:utmip]).to eq masked_ip 126 | end 127 | 128 | it "should use the specified IP in transaction_params" do 129 | transaction_params = gabba.transaction_params( 130 | 'order_id', 'total', 'store_name', 131 | 'tax', 'shipping', 'city', 132 | 'region', 'country', 'utmhid' 133 | ) 134 | expect(transaction_params[:utmip]).to eq masked_ip 135 | end 136 | 137 | it "should use the specified IP in item_params" do 138 | item_params = gabba.item_params( 139 | 'order_id', 'item_sku', 'name', 140 | 'category', 'price', 'quantity', 'utmhid' 141 | ) 142 | expect(item_params[:utmip]).to eq masked_ip 143 | end 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /spec/lib/item_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Gabba::Gabba do 4 | describe "#add_item" do 5 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 6 | 7 | before do 8 | gabba.utmn = '1009731272' 9 | gabba.utmcc = '' 10 | end 11 | 12 | it "requires a Google Analytics account" do 13 | expect{ 14 | Gabba::Gabba.new(nil, nil).add_item( 15 | "orderid", "1234", "widget", "widgets", "9.99", "1", "6783939397" 16 | ) 17 | }.to raise_error Gabba::NoGoogleAnalyticsAccountError 18 | end 19 | 20 | it "requires a Google Analytics domain" do 21 | expect{ 22 | Gabba::Gabba.new('abs', nil).add_item( 23 | "orderid", "1234", "widget", "widgets", "9.99", "1", "6783939397" 24 | ) 25 | }.to raise_error Gabba::NoGoogleAnalyticsDomainError 26 | end 27 | 28 | it "sends the 'add item' request to Google" do 29 | stub_analytics( 30 | gabba.item_params( 31 | "orderid", "1234", "widget", "widgets", "9.99", "1", "6783939397" 32 | ) 33 | ) 34 | item = gabba.add_item( 35 | "orderid", "1234", "widget", "widgets", "9.99", "1", "6783939397" 36 | ) 37 | expect(item.code).to eq '200' 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/lib/page_view_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Gabba::Gabba do 4 | describe "#page_view" do 5 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 6 | 7 | before do 8 | gabba.utmn = '1009731272' 9 | gabba.utmcc = '' 10 | end 11 | 12 | it "requires a Google Analytics account" do 13 | expect{ 14 | Gabba::Gabba.new(nil, nil).page_view('thing', 'thing') 15 | }.to raise_error Gabba::NoGoogleAnalyticsAccountError 16 | end 17 | 18 | it "requires a Google Analytics domain" do 19 | expect{ 20 | Gabba::Gabba.new('abs', nil).page_view('thing', 'thing') 21 | }.to raise_error Gabba::NoGoogleAnalyticsDomainError 22 | end 23 | 24 | it "sends the request to Google" do 25 | stub_analytics gabba.page_view_params 'title', '/page/path', '6783939397' 26 | page_view = gabba.page_view 'title', '/page/path', '6783939397' 27 | expect(page_view.code).to eq '200' 28 | end 29 | end 30 | 31 | describe '#page_view_params' do 32 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 33 | 34 | it "returns the params to be sent to Google" do 35 | params = gabba.page_view_params 'hiya', '/tracker/page' 36 | expect(params[:utmdt]).to eq 'hiya' 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/lib/transaction_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Gabba::Gabba do 4 | describe '#transaction' do 5 | let(:gabba) { Gabba::Gabba.new 'abc', '123' } 6 | 7 | before do 8 | gabba.utmn = '1009731272' 9 | gabba.utmcc = '' 10 | end 11 | 12 | it "requires a Google Analytics account" do 13 | expect{ 14 | Gabba::Gabba.new(nil, nil).transaction( 15 | "orderid", 16 | "9.99", 17 | "acme stores", 18 | ".25", 19 | "1.00", 20 | "San Jose", 21 | "CA", 22 | "United States", 23 | "6783939397" 24 | ) 25 | }.to raise_error Gabba::NoGoogleAnalyticsAccountError 26 | end 27 | 28 | it "requires a Google Analytics domain" do 29 | expect{ 30 | Gabba::Gabba.new('abs', nil).transaction( 31 | "orderid", "9.99", 32 | "acme stores", ".25", 33 | "1.00", "San Jose", 34 | "CA", "United States", "6783939397" 35 | ) 36 | }.to raise_error Gabba::NoGoogleAnalyticsDomainError 37 | end 38 | 39 | it "makes a transaction request to Google" do 40 | stub_analytics( 41 | gabba.transaction_params( 42 | "orderid", "9.99", 43 | "acme stores", ".25", 44 | "1.00", "San Jose", 45 | "CA", "United States", "6783939397" 46 | ) 47 | ) 48 | transaction = gabba.transaction( 49 | "orderid", "9.99", 50 | "acme stores", ".25", 51 | "1.00", "San Jose", 52 | "CA", "United States", "6783939397" 53 | ) 54 | expect(transaction.code).to eq '200' 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/lib/yo_gabba_gabba_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Yo::Gabba::Gabba do 4 | describe "#new" do 5 | let(:gabba) { Yo::Gabba::Gabba.new 'abc', '123' } 6 | 7 | it "is aliased to Gabba::Gabba#new" do 8 | expect(gabba).to be_a Gabba::Gabba 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'gabba' 2 | require 'rspec' 3 | 4 | require 'webmock/rspec' 5 | WebMock.disable_net_connect! 6 | 7 | def stub_analytics(expected_params) 8 | stub_request( 9 | :get, 10 | /www.google-analytics.com\/__utm.gif\?utmac=#{expected_params[:utmac]}&.*/ 11 | ).to_return(:status => 200, :body => '', :headers => {}) 12 | end 13 | --------------------------------------------------------------------------------