visitor_sources 0.0.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.
- data/README.md +11 -0
- data/VERSION +1 -0
- data/lib/visitor_sources/search_engine.rb +59 -0
- data/lib/visitor_sources/traffic_source.rb +109 -0
- data/lib/visitor_sources/traffic_source_middleware.rb +16 -0
- data/lib/visitor_sources/traffic_sources.rb +13 -0
- data/lib/visitor_sources.rb +4 -0
- data/test/app.rb +13 -0
- data/test/search_engine_test.rb +18 -0
- data/test/test_helper.rb +47 -0
- data/test/traffic_source_middleware_test.rb +22 -0
- data/test/traffic_source_test.rb +214 -0
- data/test/traffic_sources_test.rb +18 -0
- metadata +81 -0
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Visitor Sources
|
2
|
+
===============
|
3
|
+
|
4
|
+
This code is not finished
|
5
|
+
-------------------------
|
6
|
+
|
7
|
+
Track where a visitor has come from and kep a record of each visit in the cookie. To get around the "last click wins" nature of Google Analytics
|
8
|
+
|
9
|
+
|
10
|
+
# requires the use of Rack::Session::Cookie
|
11
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class SearchEngine
|
2
|
+
SEARCH_ENGINES = {
|
3
|
+
"google" => "q",
|
4
|
+
"yahoo" => "p",
|
5
|
+
"msn" => "q",
|
6
|
+
"aol" => "query",
|
7
|
+
"aol" => "encquery",
|
8
|
+
"lycos" => "query",
|
9
|
+
"ask" => "q",
|
10
|
+
"altavista" => "q",
|
11
|
+
"netscape" => "query",
|
12
|
+
"cnn" => "query",
|
13
|
+
"looksmart" => "qt",
|
14
|
+
"about" => "terms",
|
15
|
+
"mamma" => "query",
|
16
|
+
"alltheweb" => "q",
|
17
|
+
"gigablast" => "q",
|
18
|
+
"voila" => "rdata",
|
19
|
+
"virgilio" => "qs",
|
20
|
+
"live" => "q",
|
21
|
+
"baidu" => "wd",
|
22
|
+
"alice" => "qs",
|
23
|
+
"yandex" => "text",
|
24
|
+
"najdi" => "q",
|
25
|
+
"aol" => "q",
|
26
|
+
"club-internet" => "query",
|
27
|
+
"mama" => "query",
|
28
|
+
"seznam" => "q",
|
29
|
+
"search" => "q",
|
30
|
+
"wp" => "szukaj",
|
31
|
+
"onet" => "qt",
|
32
|
+
"netsprint" => "q",
|
33
|
+
"google.interia" => "q",
|
34
|
+
"szukacz" => "q",
|
35
|
+
"yam" => "k",
|
36
|
+
"pchome" => "q",
|
37
|
+
"kvasir" => "searchExpr",
|
38
|
+
"sesam" => "q",
|
39
|
+
"ozu" => "q",
|
40
|
+
"terra" => "query",
|
41
|
+
"nostrum" => "query",
|
42
|
+
"mynet" => "q",
|
43
|
+
"ekolay" => "q",
|
44
|
+
"search.ilse" => "search_for"}
|
45
|
+
|
46
|
+
attr_accessor :name, :search_parameter
|
47
|
+
|
48
|
+
def self.find(domain)
|
49
|
+
SEARCH_ENGINES.each do |name, search_parameter|
|
50
|
+
if domain =~ /#{name}/
|
51
|
+
engine = SearchEngine.new
|
52
|
+
engine.name = name
|
53
|
+
engine.search_parameter = search_parameter
|
54
|
+
return engine
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return nil
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# To minimise amount of stored data in the cookie (limited to 4KB) a traffic source gets converted to a string with variables
|
2
|
+
# seperated by a pipe(|), different traffic sources are separated by commas(,)
|
3
|
+
#
|
4
|
+
# The string looks like the following:
|
5
|
+
# 1|1266945604|ppc|just%20tv%20stands|google|December%20Campaign|/content
|
6
|
+
# Broken down, this is what the variables mean
|
7
|
+
# 1 => encoder_version makes it easy to change how this works in the future without loosing old data already in peoples cookies
|
8
|
+
# 1266945604 => unix_timestamp at which the TrafficSource was generated
|
9
|
+
# ppc => medium how the person cameto the site (main ones are cpc, direct, organic or referal)
|
10
|
+
# just%20tv%20stands => term The search term that bought the user to the site [not required]
|
11
|
+
# google => source Where the person came from. Could be keyword such as `google` or a domain name [not required]
|
12
|
+
# December%20Campaign => campaign Usually set for ppc traffic in adwords [not required]
|
13
|
+
# /content => content when a referal, this is the path from which they came from [not required]
|
14
|
+
|
15
|
+
require "uri"
|
16
|
+
class TrafficSource
|
17
|
+
attr_accessor :encoder_version, :unix_timestamp, :medium, :term, :source, :campaign, :content, :custom_parameter_mapping, :env
|
18
|
+
|
19
|
+
COOKIE_LINE_PARAMETERS = ['encoder_version', 'unix_timestamp', 'medium', 'term', 'source', 'campaign', 'content']
|
20
|
+
STANDARD_PARAMETER_MAPPING = {:medium => :utm_medium, :term => :utm_term, :source => :utm_source, :campaign => :utm_campaign, :content => :utm_content}
|
21
|
+
|
22
|
+
def initialize(attributes={})
|
23
|
+
attributes.each do |key, value|
|
24
|
+
self.send("#{key}=", value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.updated_rack_environment(old_env, custom_parameter_mapping = {})
|
29
|
+
old_env["rack.session"][:traffic_sources] ||= ''
|
30
|
+
traffic_sources = TrafficSources.new(old_env["rack.session"][:traffic_sources])
|
31
|
+
latest_source = TrafficSource.initialize_with_rack_env(old_env, custom_parameter_mapping)
|
32
|
+
return old_env if latest_source.to_s.nil?
|
33
|
+
if traffic_sources.length > 0
|
34
|
+
return old_env if latest_source.same_as?(traffic_sources.last)
|
35
|
+
end
|
36
|
+
traffic_sources << latest_source
|
37
|
+
old_env["rack.session"][:traffic_sources] = traffic_sources.to_s
|
38
|
+
return old_env
|
39
|
+
end
|
40
|
+
|
41
|
+
def TrafficSource.initialize_with_rack_env(env, custom_parameter_mapping = {})
|
42
|
+
traffic_source = self.new(:env => env, :custom_parameter_mapping => custom_parameter_mapping,
|
43
|
+
:unix_timestamp => Time.now.to_i, :encoder_version => 1)
|
44
|
+
|
45
|
+
COOKIE_LINE_PARAMETERS.last(5).each do |attribute|
|
46
|
+
traffic_source.send("#{attribute}=", traffic_source.query_string_value_for(attribute.to_sym))
|
47
|
+
end
|
48
|
+
|
49
|
+
#special case for adwords auto tagging
|
50
|
+
traffic_source.medium = 'cpc' if traffic_source.medium.nil? && !traffic_source.env["rack.request.query_hash"]["gclid"].nil?
|
51
|
+
|
52
|
+
if traffic_source.medium.nil?
|
53
|
+
if env["HTTP_REFERER"].nil?
|
54
|
+
traffic_source.medium = "direct"
|
55
|
+
else
|
56
|
+
traffic_source.medium = "referal" unless env["HTTP_REFERER"] =~ /#{env['HTTP_HOST']}/
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if traffic_source.source.nil?
|
60
|
+
begin
|
61
|
+
uri = URI.parse(env["HTTP_REFERER"])
|
62
|
+
traffic_source.source = uri.host
|
63
|
+
search_engine = SearchEngine.find(traffic_source.source)
|
64
|
+
if search_engine
|
65
|
+
traffic_source.source = search_engine.name
|
66
|
+
traffic_source.term = Rack::Utils.parse_query(uri.query)[search_engine.search_parameter] if traffic_source.term.nil?
|
67
|
+
traffic_source.medium = "organic" unless traffic_source.medium == 'cpc'
|
68
|
+
end
|
69
|
+
traffic_source.content = uri.path if traffic_source.content.nil? && !search_engine
|
70
|
+
rescue; end
|
71
|
+
end
|
72
|
+
return traffic_source
|
73
|
+
end
|
74
|
+
|
75
|
+
def TrafficSource.initialize_from_string(string)
|
76
|
+
string_attributes = string.split("|")
|
77
|
+
traffic_source = TrafficSource.new(:encoder_version => string_attributes[0].to_i, :unix_timestamp => string_attributes[1].to_i)
|
78
|
+
COOKIE_LINE_PARAMETERS.last(5).each_with_index do |attribute, index|
|
79
|
+
traffic_source.send("#{attribute}=", string_attributes[index+2])
|
80
|
+
end
|
81
|
+
return traffic_source
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
return nil if medium.nil?
|
86
|
+
# join each element by pipes(|), remove any unnecessary unused pipes from the end
|
87
|
+
COOKIE_LINE_PARAMETERS.collect{|param| self.send(param)}.join("|").gsub(/\|+$/, '')
|
88
|
+
end
|
89
|
+
|
90
|
+
def query_string_value_for(attribute)
|
91
|
+
if custom_parameter_mapping[attribute] && !env["rack.request.query_hash"][custom_parameter_mapping[attribute].to_s].nil?
|
92
|
+
return env["rack.request.query_hash"][custom_parameter_mapping[attribute].to_s]
|
93
|
+
end
|
94
|
+
if env["rack.request.query_hash"][STANDARD_PARAMETER_MAPPING[attribute].to_s]
|
95
|
+
return env["rack.request.query_hash"][STANDARD_PARAMETER_MAPPING[attribute].to_s]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def same_as?(traffic_source)
|
100
|
+
COOKIE_LINE_PARAMETERS.last(5).each do |attribute|
|
101
|
+
return false if self.send(attribute).to_s != traffic_source.send(attribute).to_s
|
102
|
+
end
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
|
106
|
+
def date
|
107
|
+
Time.at(unix_timestamp)
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class TrafficSourceMiddleware
|
2
|
+
def initialize(app, options={})
|
3
|
+
@app = app
|
4
|
+
@options = options
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
@options[:custom_parameter_mapping] ||= {}
|
9
|
+
env["rack.request.query_hash"] = Rack::Utils.parse_query(env["QUERY_STRING"])
|
10
|
+
env = TrafficSource.updated_rack_environment(env, @options[:custom_parameter_mapping])
|
11
|
+
env[:traffic_sources] = TrafficSources.new(env["rack.session"][:traffic_sources])
|
12
|
+
@status, @headers, @response = @app.call(env)
|
13
|
+
[@status, @headers, @response]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class TrafficSources < Array
|
2
|
+
|
3
|
+
def initialize(string)
|
4
|
+
traffic_source_strings = string.split(",")
|
5
|
+
traffic_source_strings.each do |string|
|
6
|
+
self << TrafficSource.initialize_from_string(string)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
each.collect(&:to_s).join(",")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/visitor_sources/search_engine')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/visitor_sources/traffic_source')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/visitor_sources/traffic_sources')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/visitor_sources/traffic_source_middleware')
|
data/test/app.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/visitor_sources')
|
4
|
+
|
5
|
+
use Rack::Session::Cookie
|
6
|
+
use TrafficSourceMiddleware, :custom_parameter_mapping => {:campaign => :campaign}
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
get "/" do
|
11
|
+
request.env[:traffic_sources].to_s
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
|
3
|
+
class SearchEngineTest < Test::Unit::TestCase
|
4
|
+
context "SearchEngineTest" do
|
5
|
+
context "find" do
|
6
|
+
should "return a search engine if one matches" do
|
7
|
+
engine = SearchEngine.find("www.google.com")
|
8
|
+
assert_equal "google", engine.name
|
9
|
+
assert_equal "q", engine.search_parameter
|
10
|
+
end
|
11
|
+
|
12
|
+
should "return nil if no engine found" do
|
13
|
+
engine = SearchEngine.find("www.fakeengine.com")
|
14
|
+
assert_nil engine
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rack/test'
|
4
|
+
require 'shoulda'
|
5
|
+
require 'base64'
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + '/app')
|
7
|
+
|
8
|
+
EXAMPLE_RACK_ENV = {
|
9
|
+
"rack.session"=>{:traffic_sources=>""},
|
10
|
+
"HTTP_HOST"=>"localhost:9393",
|
11
|
+
"HTTP_ACCEPT"=>"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
12
|
+
"SERVER_NAME"=>"localhost",
|
13
|
+
"rack.request.cookie_hash"=>{"rack.session"=>"BAh7BjoUdHJhZmZpY19zb3VyY2VzIghBQkM=\n"},
|
14
|
+
"rack.url_scheme"=>"http",
|
15
|
+
"REQUEST_PATH"=>"/",
|
16
|
+
"HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6",
|
17
|
+
"HTTP_KEEP_ALIVE"=>"115",
|
18
|
+
"rack.errors"=>{},
|
19
|
+
"HTTP_ACCEPT_LANGUAGE"=>"en-us,en;q=0.5",
|
20
|
+
"SERVER_PROTOCOL"=>"HTTP/1.1",
|
21
|
+
"rack.version"=>[1, 0],
|
22
|
+
"rack.run_once"=>false,
|
23
|
+
"SERVER_SOFTWARE"=>"Mongrel 1.1.5",
|
24
|
+
"PATH_INFO"=>"/",
|
25
|
+
"REMOTE_ADDR"=>"::1",
|
26
|
+
"rack.request.cookie_string"=>"rack.session=BAh7BjoUdHJhZmZpY19zb3VyY2VzIghBQkM%3D%0A",
|
27
|
+
"HTTP_REFERER"=>"http://localhost:9393/",
|
28
|
+
"SCRIPT_NAME"=>"",
|
29
|
+
"rack.multithread"=>true,
|
30
|
+
"HTTP_VERSION"=>"HTTP/1.1",
|
31
|
+
"HTTP_COOKIE"=>"rack.session=BAh7BjoUdHJhZmZpY19zb3VyY2VzIghBQkM%3D%0A",
|
32
|
+
"rack.request.form_vars"=>"",
|
33
|
+
"rack.multiprocess"=>false,
|
34
|
+
"REQUEST_URI"=>"/",
|
35
|
+
"rack.request.form_input"=>{},
|
36
|
+
"rack.request.query_hash"=>{},
|
37
|
+
"HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
38
|
+
"SERVER_PORT"=>"9393",
|
39
|
+
"rack.session.options"=>{:domain=>nil, :expire_after=>nil, :path=>"/"},
|
40
|
+
"REQUEST_METHOD"=>"GET",
|
41
|
+
"rack.request.form_hash"=>{},
|
42
|
+
"rack.request.query_string"=>"",
|
43
|
+
"QUERY_STRING"=>"",
|
44
|
+
"rack.input"=>{},
|
45
|
+
"HTTP_ACCEPT_ENCODING"=>"gzip,deflate",
|
46
|
+
"HTTP_CONNECTION"=>"keep-alive",
|
47
|
+
"GATEWAY_INTERFACE"=>"CGI/1.2"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
|
3
|
+
|
4
|
+
class TrafficSourceMiddlewareTest < Test::Unit::TestCase
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
Sinatra::Application
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_should_display_traffic_source_line
|
12
|
+
start_time = Time.now.to_i
|
13
|
+
get "/", params = {}, rack_env = {}
|
14
|
+
assert last_response.ok?
|
15
|
+
assert_equal "1|#{start_time}|direct", last_response.body
|
16
|
+
sleep 1
|
17
|
+
get "/", params = {:campaign => "mycampaign", :utm_medium => "cpc"}, rack_env = {}
|
18
|
+
assert_equal "1|#{start_time}|direct,1|#{start_time+1}|cpc|||mycampaign", last_response.body
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
|
3
|
+
# Priority of variables set
|
4
|
+
# custom variables configured when using the plugin take the most priority
|
5
|
+
# if no custom variable matches, then the standard google variables take priority: 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_campaign'
|
6
|
+
# if no match standard google variables then try and work out the required data from referers etc
|
7
|
+
|
8
|
+
class TrafficSourceTest < Test::Unit::TestCase
|
9
|
+
context "TrafficSourceTest" do
|
10
|
+
setup do
|
11
|
+
@rack_env = EXAMPLE_RACK_ENV.dup
|
12
|
+
@custom_variable_matches = {:campaign => :custom_campaign, :term => :custom_keywords, :medium => :custom_medium}
|
13
|
+
end
|
14
|
+
context "initialize_with_rack_env" do
|
15
|
+
|
16
|
+
context "when there are custom variables in the url present" do
|
17
|
+
should "use the custom variables to set the correct TrafficSource" do
|
18
|
+
@rack_env["rack.request.query_hash"] = {"custom_campaign" => "MyCamp1", "custom_keywords" => "Product One", "gclid" => "AutoAdwordsTaggingClid"}
|
19
|
+
@rack_env["HTTP_REFERER"] = "http://www.google.co.uk/search"
|
20
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
21
|
+
assert_equal "cpc", traffic_source.medium
|
22
|
+
assert_equal "MyCamp1", traffic_source.campaign
|
23
|
+
assert_equal "Product One", traffic_source.term
|
24
|
+
assert_equal Time.now.to_i, traffic_source.unix_timestamp
|
25
|
+
assert_equal "1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1", traffic_source.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
should "use presume organic if no gclid and from a search engine" do
|
29
|
+
@rack_env["rack.request.query_hash"] = {"custom_campaign" => "MyCamp1", "custom_keywords" => "Product One"}
|
30
|
+
@rack_env["HTTP_REFERER"] = "http://www.google.co.uk/search"
|
31
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
32
|
+
assert_equal "organic", traffic_source.medium
|
33
|
+
assert_equal "MyCamp1", traffic_source.campaign
|
34
|
+
assert_equal "Product One", traffic_source.term
|
35
|
+
assert_equal Time.now.to_i, traffic_source.unix_timestamp
|
36
|
+
assert_equal "1|#{Time.now.to_i}|organic|Product One|google|MyCamp1", traffic_source.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
should "assign to cpc if a custom variable says thats the case" do
|
40
|
+
@rack_env["rack.request.query_hash"] = {"custom_campaign" => "MyCamp1", "custom_keywords" => "Product One", "custom_medium" => "cpc"}
|
41
|
+
@rack_env["HTTP_REFERER"] = "http://www.google.co.uk/search"
|
42
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
43
|
+
assert_equal "cpc", traffic_source.medium
|
44
|
+
assert_equal "MyCamp1", traffic_source.campaign
|
45
|
+
assert_equal "Product One", traffic_source.term
|
46
|
+
assert_equal Time.now.to_i, traffic_source.unix_timestamp
|
47
|
+
assert_equal "1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1", traffic_source.to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when no custom or standard variables matching" do
|
52
|
+
context "when there is no referer" do
|
53
|
+
should "add create a TrafficSource instance with medium of direct" do
|
54
|
+
@rack_env["HTTP_REFERER"] = nil
|
55
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
56
|
+
assert_equal "direct", traffic_source.medium
|
57
|
+
assert_equal Time.now.to_i, traffic_source.unix_timestamp
|
58
|
+
assert_equal "1|#{Time.now.to_i}|direct", traffic_source.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when there is a referer" do
|
63
|
+
context "when the referer is an interal address" do
|
64
|
+
should "have no medium and to_s return nil" do
|
65
|
+
@rack_env["HTTP_REFERER"] = "http://localhost:9393/some/path"
|
66
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
67
|
+
assert_nil traffic_source.medium
|
68
|
+
assert_nil traffic_source.to_s
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when the referer is external" do
|
73
|
+
should "have a medium of referer with source and content" do
|
74
|
+
@rack_env["HTTP_REFERER"] = "http://matthewfawcett.co.uk/some/path"
|
75
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
76
|
+
assert_equal "referal", traffic_source.medium
|
77
|
+
assert_equal "matthewfawcett.co.uk", traffic_source.source
|
78
|
+
assert_equal "/some/path", traffic_source.content
|
79
|
+
assert_equal "1|#{Time.now.to_i}|referal||matthewfawcett.co.uk||/some/path", traffic_source.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
should "assign to a search engine with correct keywords if referer matches" do
|
83
|
+
@rack_env["HTTP_REFERER"] = "http://google.co.uk/search?q=mysearchterms"
|
84
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
85
|
+
assert_equal "organic", traffic_source.medium
|
86
|
+
assert_equal "google", traffic_source.source
|
87
|
+
assert_equal "mysearchterms", traffic_source.term
|
88
|
+
assert_nil traffic_source.content
|
89
|
+
assert_equal "1|#{Time.now.to_i}|organic|mysearchterms|google", traffic_source.to_s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "using standard google variables" do
|
96
|
+
should "should assign to ppc if the variables say so" do
|
97
|
+
@rack_env["rack.request.query_hash"] = {"utm_campaign" => "MyCamp1", "utm_term" => "Product One", "utm_medium" => "cpc", "utm_source" => "google", "utm_term" => "Product One"}
|
98
|
+
@rack_env["HTTP_REFERER"] = "http://www.google.co.uk/search"
|
99
|
+
traffic_source = TrafficSource.initialize_with_rack_env(@rack_env, @custom_variable_matches)
|
100
|
+
assert_equal "cpc", traffic_source.medium
|
101
|
+
assert_equal "MyCamp1", traffic_source.campaign
|
102
|
+
assert_equal "Product One", traffic_source.term
|
103
|
+
assert_equal Time.now.to_i, traffic_source.unix_timestamp
|
104
|
+
assert_equal "1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1", traffic_source.to_s
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "query_string_value_for" do
|
110
|
+
setup do
|
111
|
+
@traffic_source = TrafficSource.new
|
112
|
+
@traffic_source.custom_parameter_mapping = {:campaign => :custom_campaign, :keyword => :custom_keywords, :medium => :custom_medium}
|
113
|
+
end
|
114
|
+
|
115
|
+
should "use the custom value if there is a match" do
|
116
|
+
@traffic_source.env = @rack_env.merge("rack.request.query_hash" => {"custom_campaign" => "mattscustomcampaign", "utm_campaign" => "standardcampaign"})
|
117
|
+
assert_equal "mattscustomcampaign", @traffic_source.query_string_value_for(:campaign)
|
118
|
+
end
|
119
|
+
|
120
|
+
should "use the standard value if there is a match and no custom match" do
|
121
|
+
@traffic_source.env = @rack_env.merge("rack.request.query_hash" => {"utm_campaign" => "standardcampaign"})
|
122
|
+
assert_equal "standardcampaign", @traffic_source.query_string_value_for(:campaign)
|
123
|
+
end
|
124
|
+
|
125
|
+
should "use the standard match if we don't even have any custom parameter mapping" do
|
126
|
+
@traffic_source.custom_parameter_mapping = {}
|
127
|
+
@traffic_source.env = @rack_env.merge("rack.request.query_hash" => {"custom_campaign" => "mattscustomcampaign", "utm_campaign" => "standardcampaign"})
|
128
|
+
assert_equal "standardcampaign", @traffic_source.query_string_value_for(:campaign)
|
129
|
+
end
|
130
|
+
|
131
|
+
should "be nil if no match" do
|
132
|
+
@traffic_source.env = @rack_env.merge("rack.request.query_hash" => {})
|
133
|
+
assert_nil @traffic_source.query_string_value_for(:campaign)
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
context "updated_rack_environment" do
|
139
|
+
|
140
|
+
should "not update the enviroment if the current TrafficSource#to_s is nil" do
|
141
|
+
@rack_env["HTTP_REFERER"] = "http://localhost:9393/some/path"
|
142
|
+
rack_env = TrafficSource.updated_rack_environment(@rack_env)
|
143
|
+
assert_equal "", rack_env["rack.session"][:traffic_sources]
|
144
|
+
end
|
145
|
+
|
146
|
+
should "not update the enviroment if the last TrafficSource#to_s is the same as the current traffic source" do
|
147
|
+
@rack_env["HTTP_REFERER"] = nil
|
148
|
+
rack_env = TrafficSource.updated_rack_environment(@rack_env)
|
149
|
+
assert_equal "1|#{Time.now.to_i}|direct", rack_env["rack.session"][:traffic_sources]
|
150
|
+
|
151
|
+
rack_env = TrafficSource.updated_rack_environment(@rack_env)
|
152
|
+
assert_equal "1|#{Time.now.to_i}|direct", rack_env["rack.session"][:traffic_sources]
|
153
|
+
end
|
154
|
+
|
155
|
+
should "update the traffic source if the current one is differenty from the last one" do
|
156
|
+
@rack_env["HTTP_REFERER"] = nil
|
157
|
+
rack_env = TrafficSource.updated_rack_environment(@rack_env)
|
158
|
+
assert_equal "1|#{Time.now.to_i}|direct", rack_env["rack.session"][:traffic_sources]
|
159
|
+
|
160
|
+
rack_env["rack.request.query_hash"] = {"utm_campaign" => "MyCamp1", "utm_term" => "Product One", "utm_medium" => "cpc", "utm_source" => "google", "utm_term" => "Product One"}
|
161
|
+
rack_env["HTTP_REFERER"] = "http://www.google.co.uk/search"
|
162
|
+
rack_env = TrafficSource.updated_rack_environment(@rack_env)
|
163
|
+
assert_equal "1|#{Time.now.to_i}|direct,1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1", rack_env["rack.session"][:traffic_sources]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
context "same_as?" do
|
172
|
+
setup do
|
173
|
+
@source_1 = TrafficSource.new(:encoder_version => 1, :unix_timestamp => Time.now.to_i, :medium => 'cpc',
|
174
|
+
:term => 'myterm', :source => 'google', :campaign => 'mycamp')
|
175
|
+
@source_2 = @source_1.dup
|
176
|
+
end
|
177
|
+
|
178
|
+
should "be true if all the main fields are the same" do
|
179
|
+
assert @source_1.same_as?(@source_2)
|
180
|
+
@source_2.encoder_version = 2
|
181
|
+
@source_2.unix_timestamp = 1234
|
182
|
+
assert @source_1.same_as?(@source_2)
|
183
|
+
end
|
184
|
+
|
185
|
+
should "be false if one of the fields are different" do
|
186
|
+
@source_2.medium = "direct"
|
187
|
+
assert !@source_1.same_as?(@source_2)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "initialize_from_string" do
|
192
|
+
should "create a new TrafficSource using the correct parameters from the string" do
|
193
|
+
string = "1|123456|organic|mysearchterms|google"
|
194
|
+
source = TrafficSource.initialize_from_string(string)
|
195
|
+
assert_equal 1, source.encoder_version
|
196
|
+
assert_equal 123456, source.unix_timestamp
|
197
|
+
assert_equal "organic", source.medium
|
198
|
+
assert_equal "mysearchterms", source.term
|
199
|
+
assert_equal "google", source.source
|
200
|
+
assert_nil source.campaign
|
201
|
+
assert_nil source.content
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "date" do
|
206
|
+
should "return a date object using the timestamp" do
|
207
|
+
@source = TrafficSource.new(:unix_timestamp => 1267804832)
|
208
|
+
assert_equal Time.at(1267804832), @source.date
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
|
3
|
+
class TrafficSourcesTest < Test::Unit::TestCase
|
4
|
+
context "TrafficSourcesTest" do
|
5
|
+
context "new" do
|
6
|
+
should "allow the raw string to be used to build the array of TrafficSources" do
|
7
|
+
assert_equal 2, TrafficSources.new("1|#{Time.now.to_i}|direct,1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1").length
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "to_s" do
|
12
|
+
should "call to_s on each TrafficSource instance and join with commas" do
|
13
|
+
traffic_sources = TrafficSources.new("1|#{Time.now.to_i}|direct,1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1")
|
14
|
+
assert_equal "1|#{Time.now.to_i}|direct,1|#{Time.now.to_i}|cpc|Product One|google|MyCamp1", traffic_sources.to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: visitor_sources
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Fawcett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-05 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Use a cookie to record the sources that each visitor came to your site
|
26
|
+
email: mail@matthewfawcett.co.uk
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.md
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- VERSION
|
36
|
+
- lib/visitor_sources.rb
|
37
|
+
- lib/visitor_sources/search_engine.rb
|
38
|
+
- lib/visitor_sources/traffic_source.rb
|
39
|
+
- lib/visitor_sources/traffic_source_middleware.rb
|
40
|
+
- lib/visitor_sources/traffic_sources.rb
|
41
|
+
- test/app.rb
|
42
|
+
- test/search_engine_test.rb
|
43
|
+
- test/test_helper.rb
|
44
|
+
- test/traffic_source_middleware_test.rb
|
45
|
+
- test/traffic_source_test.rb
|
46
|
+
- test/traffic_sources_test.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/mattfawcett/visitor_sources
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --charset=UTF-8
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.3.5
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Use a cookie to record the sources that each visitor came to your site
|
75
|
+
test_files:
|
76
|
+
- test/app.rb
|
77
|
+
- test/search_engine_test.rb
|
78
|
+
- test/test_helper.rb
|
79
|
+
- test/traffic_source_middleware_test.rb
|
80
|
+
- test/traffic_source_test.rb
|
81
|
+
- test/traffic_sources_test.rb
|