staccato 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -0
- data/lib/staccato.rb +15 -0
- data/lib/staccato/event.rb +4 -0
- data/lib/staccato/exception.rb +4 -0
- data/lib/staccato/hit.rb +48 -9
- data/lib/staccato/option_set.rb +2 -0
- data/lib/staccato/pageview.rb +4 -0
- data/lib/staccato/social.rb +4 -0
- data/lib/staccato/timing.rb +6 -0
- data/lib/staccato/tracker.rb +69 -0
- data/lib/staccato/transaction.rb +4 -0
- data/lib/staccato/transaction_item.rb +4 -0
- data/lib/staccato/version.rb +2 -1
- data/spec/lib/staccato/pageview_spec.rb +20 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -78,6 +78,14 @@ events that are not directly the result of a user's interaction.
|
|
78
78
|
|
79
79
|
The option `non_interactive` is accepted for all methods on `tracker`.
|
80
80
|
|
81
|
+
# Tracking an Experiment
|
82
|
+
# useful for tracking A/B or Multivariate testing
|
83
|
+
tracker.pageview({
|
84
|
+
path: '/blog',
|
85
|
+
experiment_id: 'a7a8d91df',
|
86
|
+
experiment_variant: 'a'
|
87
|
+
})
|
88
|
+
|
81
89
|
## Google Documentation
|
82
90
|
|
83
91
|
https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
|
data/lib/staccato.rb
CHANGED
@@ -5,7 +5,18 @@ require 'securerandom'
|
|
5
5
|
|
6
6
|
require "staccato/version"
|
7
7
|
|
8
|
+
# The `Staccato` module namespace
|
9
|
+
#
|
10
|
+
# @author Tony Pitale
|
8
11
|
module Staccato
|
12
|
+
# Build a new tracker instance
|
13
|
+
# If the first argument is explicitly `nil`, a `NoopTracker` is returned
|
14
|
+
# which responds to all the same `tracker` methods but does no tracking
|
15
|
+
#
|
16
|
+
# @param id [String, nil] the id provided by google, i.e., `UA-XXXXXX-Y`
|
17
|
+
# @param client_id [String, Integer, nil] a unique id to track the session of
|
18
|
+
# an individual user
|
19
|
+
# @return [Staccato::Tracker] a new tracker is returned
|
9
20
|
def self.tracker(id, client_id = nil)
|
10
21
|
if id.nil?
|
11
22
|
Staccato::NoopTracker.new
|
@@ -14,10 +25,14 @@ module Staccato
|
|
14
25
|
end
|
15
26
|
end
|
16
27
|
|
28
|
+
# Build a new random `client_id`
|
29
|
+
#
|
30
|
+
# @return [String] a random value suitable for use as a `client_id`
|
17
31
|
def self.build_client_id
|
18
32
|
SecureRandom.uuid
|
19
33
|
end
|
20
34
|
|
35
|
+
# The tracking endpoint we use to submit requests to GA
|
21
36
|
def self.tracking_uri
|
22
37
|
URI('http://www.google-analytics.com/collect')
|
23
38
|
end
|
data/lib/staccato/event.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Event Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Event
|
5
|
+
# Event field definitions
|
3
6
|
FIELDS = {
|
4
7
|
category: 'ec',
|
5
8
|
action: 'ea',
|
@@ -9,6 +12,7 @@ module Staccato
|
|
9
12
|
|
10
13
|
include Hit
|
11
14
|
|
15
|
+
# event hit type
|
12
16
|
def type
|
13
17
|
:event
|
14
18
|
end
|
data/lib/staccato/exception.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Exception Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Exception
|
5
|
+
# Exception field definitions
|
3
6
|
FIELDS = {
|
4
7
|
description: 'exd',
|
5
8
|
fatal: 'exf'
|
@@ -12,6 +15,7 @@ module Staccato
|
|
12
15
|
options[:fatal] = 1 if options[:fatal]
|
13
16
|
end
|
14
17
|
|
18
|
+
# exception hit type
|
15
19
|
def type
|
16
20
|
:exception
|
17
21
|
end
|
data/lib/staccato/hit.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
module Staccato
|
2
|
+
# The `Hit` module enables a class to track the appropriate parameters
|
3
|
+
# to Google Analytics given a defined set of `FIELDS` in a map between
|
4
|
+
# the option name and its specified GA field name
|
5
|
+
#
|
6
|
+
# @author Tony Pitale
|
2
7
|
module Hit
|
8
|
+
# this module is included into each model hit type
|
9
|
+
# to share the common behavior required to hit
|
10
|
+
# the Google Analytics /collect api endpoint
|
3
11
|
def self.included(model)
|
4
12
|
model.extend Forwardable
|
5
13
|
|
@@ -10,37 +18,68 @@ module Staccato
|
|
10
18
|
end
|
11
19
|
end
|
12
20
|
|
21
|
+
# sets up a new hit
|
22
|
+
# @param tracker [Staccato::Tracker] the tracker to collect to
|
23
|
+
# @param options [Hash] options for the specific hit type
|
13
24
|
def initialize(tracker, options = {})
|
14
25
|
self.tracker = tracker
|
15
26
|
self.options = OptionSet.new(options)
|
16
27
|
end
|
17
28
|
|
29
|
+
# return the fields for this hit type
|
30
|
+
# @return [Hash] the field definitions
|
18
31
|
def fields
|
19
32
|
self.class::FIELDS
|
20
33
|
end
|
21
34
|
|
35
|
+
# collects the parameters from options for this hit type
|
22
36
|
def params
|
23
|
-
{
|
24
|
-
'v' => 1,
|
25
|
-
'tid' => tracker.id,
|
26
|
-
'cid' => tracker.client_id,
|
27
|
-
'ni' => non_interactive,
|
28
|
-
't' => type.to_s
|
29
|
-
}.merge(Hash[
|
30
|
-
fields.map {|field,key| [key, options[field]]}
|
31
|
-
]).reject {|_,v| v.nil?}
|
37
|
+
base_params.merge(global_options_params).merge(hit_params).reject {|_,v| v.nil?}
|
32
38
|
end
|
33
39
|
|
40
|
+
# is this a non interactive hit
|
41
|
+
# @return [Integer, nil]
|
34
42
|
def non_interactive
|
35
43
|
1 if options[:non_interactive] # defaults to nil
|
36
44
|
end
|
37
45
|
|
46
|
+
# post the hit to GA collection endpoint
|
47
|
+
# @return [Net::HTTPOK] the GA api always returns 200 OK
|
38
48
|
def track!
|
39
49
|
post(Staccato.tracking_uri, params)
|
40
50
|
end
|
41
51
|
|
52
|
+
private
|
53
|
+
# @private
|
42
54
|
def post(uri, params = {})
|
43
55
|
Net::HTTP.post_form(uri, params)
|
44
56
|
end
|
57
|
+
|
58
|
+
# @private
|
59
|
+
def base_params
|
60
|
+
{
|
61
|
+
'v' => 1,
|
62
|
+
'tid' => tracker.id,
|
63
|
+
'cid' => tracker.client_id,
|
64
|
+
'ni' => non_interactive,
|
65
|
+
't' => type.to_s
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
# @private
|
70
|
+
def global_options_params
|
71
|
+
{
|
72
|
+
'dr' => options[:referrer],
|
73
|
+
'de' => options[:encoding],
|
74
|
+
'ul' => options[:user_language],
|
75
|
+
'xid' => options[:experiment_id],
|
76
|
+
'xvar' => options[:experiment_variant]
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
# @private
|
81
|
+
def hit_params
|
82
|
+
Hash[fields.map {|field,key| [key, options[field]]}]
|
83
|
+
end
|
45
84
|
end
|
46
85
|
end
|
data/lib/staccato/option_set.rb
CHANGED
data/lib/staccato/pageview.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Pageview Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Pageview
|
5
|
+
# Pageview field definitions
|
3
6
|
FIELDS = {
|
4
7
|
hostname: 'dh',
|
5
8
|
path: 'dp',
|
@@ -8,6 +11,7 @@ module Staccato
|
|
8
11
|
|
9
12
|
include Hit
|
10
13
|
|
14
|
+
# pageview hit type
|
11
15
|
def type
|
12
16
|
:pageview
|
13
17
|
end
|
data/lib/staccato/social.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Social Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Social
|
5
|
+
# Social field definitions
|
3
6
|
FIELDS = {
|
4
7
|
action: 'sa',
|
5
8
|
network: 'sn',
|
@@ -8,6 +11,7 @@ module Staccato
|
|
8
11
|
|
9
12
|
include Hit
|
10
13
|
|
14
|
+
# social hit type
|
11
15
|
def type
|
12
16
|
:social
|
13
17
|
end
|
data/lib/staccato/timing.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Timing Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Timing
|
5
|
+
# Timing field definitions
|
3
6
|
FIELDS = {
|
4
7
|
category: 'utc',
|
5
8
|
variable: 'utv',
|
@@ -9,10 +12,13 @@ module Staccato
|
|
9
12
|
|
10
13
|
include Hit
|
11
14
|
|
15
|
+
# timing hit type
|
12
16
|
def type
|
13
17
|
:timing
|
14
18
|
end
|
15
19
|
|
20
|
+
# tracks the timing hit type
|
21
|
+
# @param block [#call] block is executed and time recorded
|
16
22
|
def track!(&block)
|
17
23
|
if block_given?
|
18
24
|
start_at = Time.now
|
data/lib/staccato/tracker.rb
CHANGED
@@ -1,64 +1,133 @@
|
|
1
1
|
module Staccato
|
2
|
+
# The `Tracker` class has methods to create all `Hit` types
|
3
|
+
# using the tracker and client id
|
4
|
+
#
|
5
|
+
# @author Tony Pitale
|
2
6
|
class Tracker
|
7
|
+
# sets up a new tracker
|
8
|
+
# @param id [String] the GA tracker id
|
9
|
+
# @param client_id [String, nil] unique value to track user sessions
|
3
10
|
def initialize(id, client_id = nil)
|
4
11
|
@id = id
|
5
12
|
@client_id = client_id
|
6
13
|
end
|
7
14
|
|
15
|
+
# The tracker id for GA
|
16
|
+
# @return [String, nil]
|
8
17
|
def id
|
9
18
|
@id
|
10
19
|
end
|
11
20
|
|
21
|
+
# The unique client id
|
22
|
+
# @return [String]
|
12
23
|
def client_id
|
13
24
|
@client_id ||= Staccato.build_client_id
|
14
25
|
end
|
15
26
|
|
27
|
+
# Track a pageview
|
28
|
+
#
|
29
|
+
# @param options [Hash] options include:
|
30
|
+
# * path (optional) the path of the current page view
|
31
|
+
# * hostname (optional) the hostname of the current page view
|
32
|
+
# * title (optional) the page title
|
33
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
16
34
|
def pageview(options = {})
|
17
35
|
Staccato::Pageview.new(self, options).track!
|
18
36
|
end
|
19
37
|
|
38
|
+
# Track an event
|
39
|
+
#
|
40
|
+
# @param options [Hash] options include:
|
41
|
+
# * category (optional)
|
42
|
+
# * action (optional)
|
43
|
+
# * label (optional)
|
44
|
+
# * value (optional)
|
45
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
20
46
|
def event(options = {})
|
21
47
|
Staccato::Event.new(self, options).track!
|
22
48
|
end
|
23
49
|
|
50
|
+
# Track a social event such as a Facebook Like or Twitter Share
|
51
|
+
#
|
52
|
+
# @param options [Hash] options include:
|
53
|
+
# * action (required) the action taken, e.g., 'like'
|
54
|
+
# * network (required) the network used, e.g., 'facebook'
|
55
|
+
# * target (required) the target page path, e.g., '/blog/something-awesome'
|
56
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
24
57
|
def social(options = {})
|
25
58
|
Staccato::Social.new(self, options).track!
|
26
59
|
end
|
27
60
|
|
61
|
+
# Track an exception
|
62
|
+
#
|
63
|
+
# @param options [Hash] options include:
|
64
|
+
# * description (optional) often the class of exception, e.g., RuntimeException
|
65
|
+
# * fatal (optional) was the exception fatal? boolean, defaults to false
|
66
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
28
67
|
def exception(options = {})
|
29
68
|
Staccato::Exception.new(self, options).track!
|
30
69
|
end
|
31
70
|
|
71
|
+
# Track timing
|
72
|
+
#
|
73
|
+
# @param options [Hash] options include:
|
74
|
+
# * category (optional) e.g., 'runtime'
|
75
|
+
# * variable (optional) e.g., 'database'
|
76
|
+
# * label (optional) e.g., 'query'
|
77
|
+
# * time (recommended) the integer time in milliseconds
|
78
|
+
# @param block [#call] if a block is provided, the time it takes to
|
79
|
+
# run will be recorded and set as the `time` value option
|
80
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
32
81
|
def timing(options = {}, &block)
|
33
82
|
Staccato::Timing.new(self, options).track!(&block)
|
34
83
|
end
|
35
84
|
|
85
|
+
# Track an ecommerce transaction
|
86
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
36
87
|
def transaction(options = {})
|
37
88
|
Staccato::Transaction.new(self, options).track!
|
38
89
|
end
|
39
90
|
|
91
|
+
# Track an item in an ecommerce transaction
|
92
|
+
# @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
|
40
93
|
def transaction_item(options = {})
|
41
94
|
Staccato::TransactionItem.new(self, options).track!
|
42
95
|
end
|
43
96
|
end
|
44
97
|
|
98
|
+
# A tracker which does no tracking
|
99
|
+
# Useful in testing
|
45
100
|
class NoopTracker
|
101
|
+
# (see Tracker#initialize)
|
46
102
|
def initialize(*); end
|
47
103
|
|
104
|
+
# (see Tracker#id)
|
48
105
|
def id
|
49
106
|
nil
|
50
107
|
end
|
51
108
|
|
109
|
+
# (see Tracker#client_id)
|
52
110
|
def client_id
|
53
111
|
nil
|
54
112
|
end
|
55
113
|
|
114
|
+
# (see Tracker#pageview)
|
56
115
|
def pageview(*); end
|
116
|
+
# (see Tracker#event)
|
57
117
|
def event(*); end
|
118
|
+
# (see Tracker#social)
|
58
119
|
def social(*); end
|
120
|
+
# (see Tracker#exception)
|
59
121
|
def exception(*); end
|
122
|
+
# (see Tracker#timing)
|
60
123
|
def timing(*)
|
61
124
|
yield if block_given?
|
62
125
|
end
|
126
|
+
# (see Tracker#transaction)
|
127
|
+
def transaction(*)
|
128
|
+
end
|
129
|
+
# (see Tracker#transaction_item)
|
130
|
+
def transaction_item(*)
|
131
|
+
end
|
63
132
|
end
|
64
133
|
end
|
data/lib/staccato/transaction.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Transaction Hit type field definitions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class Transaction
|
5
|
+
# Transaction field definitions
|
3
6
|
FIELDS = {
|
4
7
|
transaction_id: 'ti',
|
5
8
|
affiliation: 'ta',
|
@@ -11,6 +14,7 @@ module Staccato
|
|
11
14
|
|
12
15
|
include Hit
|
13
16
|
|
17
|
+
# transaction hit type
|
14
18
|
def type
|
15
19
|
:transaction
|
16
20
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module Staccato
|
2
|
+
# Item Hit type field definitions for Transactions
|
3
|
+
# @author Tony Pitale
|
2
4
|
class TransactionItem
|
5
|
+
# Item field definitions
|
3
6
|
FIELDS = {
|
4
7
|
transaction_id: 'ti',
|
5
8
|
name: 'in',
|
@@ -12,6 +15,7 @@ module Staccato
|
|
12
15
|
|
13
16
|
include Hit
|
14
17
|
|
18
|
+
# item hit type
|
15
19
|
def type
|
16
20
|
:item
|
17
21
|
end
|
data/lib/staccato/version.rb
CHANGED
@@ -75,4 +75,24 @@ describe Staccato::Pageview do
|
|
75
75
|
})
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
context "with experiment_* options" do
|
80
|
+
let(:pageview) do
|
81
|
+
Staccato::Pageview.new(tracker, {
|
82
|
+
experiment_id: 'ac67afa889',
|
83
|
+
experiment_variant: 'c'
|
84
|
+
})
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'has require params' do
|
88
|
+
pageview.params.should eq({
|
89
|
+
'v' => 1,
|
90
|
+
'tid' => 'UA-XXXX-Y',
|
91
|
+
'cid' => '555',
|
92
|
+
't' => 'pageview',
|
93
|
+
'xid' => 'ac67afa889',
|
94
|
+
'xvar' => 'c'
|
95
|
+
})
|
96
|
+
end
|
97
|
+
end
|
78
98
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: staccato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-01-
|
12
|
+
date: 2014-01-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|