staccato 0.0.1 → 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 +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +20 -0
- data/README.md +44 -1
- data/lib/staccato.rb +14 -2
- data/lib/staccato/hit.rb +6 -1
- data/lib/staccato/option_set.rb +9 -0
- data/lib/staccato/timing.rb +28 -0
- data/lib/staccato/tracker.rb +33 -1
- data/lib/staccato/transaction.rb +18 -0
- data/lib/staccato/transaction_item.rb +19 -0
- data/lib/staccato/version.rb +1 -1
- data/spec/integration/noop_tracker_spec.rb +102 -0
- data/spec/integration/tracker_spec.rb +124 -2
- data/spec/spec_helper.rb +3 -0
- data/staccato.gemspec +1 -2
- metadata +27 -2
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p448
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
## Staccato 0.0.2 ##
|
2
|
+
|
3
|
+
* adds timing tracking with block timing
|
4
|
+
* adds ecommerce tracking
|
5
|
+
* adds non-interactive tracking option
|
6
|
+
* automate building a random client id with SecureRandom.uuid
|
7
|
+
* adds no-op tracking for unconfigured and testing environments
|
8
|
+
* adds travis CI
|
9
|
+
* adds coverage metric
|
10
|
+
* adds code climate
|
11
|
+
|
12
|
+
*Tony Pitale*
|
13
|
+
|
14
|
+
## Staccato 0.0.1 ##
|
15
|
+
|
16
|
+
* Initial implementation
|
17
|
+
* Track a pageview
|
18
|
+
* Track an event
|
19
|
+
|
20
|
+
*Tony Pitale*
|
data/README.md
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
Ruby Google Analytics Measurement
|
4
4
|
|
5
|
+
[](https://travis-ci.org/tpitale/staccato)
|
6
|
+
[](https://codeclimate.com/github/tpitale/staccato)
|
7
|
+
|
5
8
|
## Installation
|
6
9
|
|
7
10
|
Add this line to your application's Gemfile:
|
@@ -16,13 +19,15 @@ Or install it yourself as:
|
|
16
19
|
|
17
20
|
$ gem install staccato
|
18
21
|
|
19
|
-
## Usage
|
22
|
+
## Usage ##
|
20
23
|
|
21
24
|
tracker = Staccato.tracker('UA-XXXX-Y') # REQUIRED, your Google Analytics Tracking ID
|
22
25
|
|
23
26
|
`#tracker` optionally takes a second param for the `client_id` value
|
24
27
|
By default, the `client_id` is set to a random UUID with `SecureRandom.uuid`
|
25
28
|
|
29
|
+
### Track some data ###
|
30
|
+
|
26
31
|
# Track a Pageview (all values optional)
|
27
32
|
tracker.pageview(path: '/page-path', hostname: 'mysite.com', title: 'A Page!')
|
28
33
|
|
@@ -35,6 +40,44 @@ By default, the `client_id` is set to a random UUID with `SecureRandom.uuid`
|
|
35
40
|
# Track exceptions (all values optional)
|
36
41
|
tracker.exception(description: 'RuntimeException', fatal: true)
|
37
42
|
|
43
|
+
# Track timing (all values optional, but should include time)
|
44
|
+
tracker.timing(category: 'runtime', variable: 'db', label: 'query', time: 50) # time in milliseconds
|
45
|
+
|
46
|
+
tracker.timing(category: 'runtime', variable: 'db', label: 'query') do
|
47
|
+
some_code_here
|
48
|
+
end
|
49
|
+
|
50
|
+
# Track transaction (transaction_id REQUIRED)
|
51
|
+
tracker.transaction({
|
52
|
+
transaction_id: 12345,
|
53
|
+
affiliation: 'clothing',
|
54
|
+
revenue: 17.98,
|
55
|
+
shipping: 2.00,
|
56
|
+
tax: 2.50,
|
57
|
+
currency: 'EUR'
|
58
|
+
})
|
59
|
+
|
60
|
+
# Track transaction item (matching transaction_id and item name REQUIRED)
|
61
|
+
tracker.transaction_item({
|
62
|
+
transaction_id: 12345,
|
63
|
+
name: 'Shirt',
|
64
|
+
price: 8.99,
|
65
|
+
quantity: 2,
|
66
|
+
code: 'afhcka1230',
|
67
|
+
variation: 'red',
|
68
|
+
currency: 'EUR'
|
69
|
+
})
|
70
|
+
|
71
|
+
### "Global" Options ###
|
72
|
+
|
73
|
+
# Track a Non-Interactive Event
|
74
|
+
tracker.event(category: 'video', action: 'play', non_interactive: true)
|
75
|
+
|
76
|
+
Non-Interactive events are useful for tracking things like emails sent, or other
|
77
|
+
events that are not directly the result of a user's interaction.
|
78
|
+
|
79
|
+
The option `non_interactive` is accepted for all methods on `tracker`.
|
80
|
+
|
38
81
|
## Google Documentation
|
39
82
|
|
40
83
|
https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
|
data/lib/staccato.rb
CHANGED
@@ -7,17 +7,29 @@ require "staccato/version"
|
|
7
7
|
|
8
8
|
module Staccato
|
9
9
|
def self.tracker(id, client_id = nil)
|
10
|
-
|
10
|
+
if id.nil?
|
11
|
+
Staccato::NoopTracker.new
|
12
|
+
else
|
13
|
+
Staccato::Tracker.new(id, client_id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.build_client_id
|
18
|
+
SecureRandom.uuid
|
11
19
|
end
|
12
20
|
|
13
21
|
def self.tracking_uri
|
14
|
-
URI('http://www.')
|
22
|
+
URI('http://www.google-analytics.com/collect')
|
15
23
|
end
|
16
24
|
end
|
17
25
|
|
26
|
+
require 'staccato/option_set'
|
18
27
|
require 'staccato/hit'
|
19
28
|
require 'staccato/pageview'
|
20
29
|
require 'staccato/event'
|
21
30
|
require 'staccato/social'
|
22
31
|
require 'staccato/exception'
|
32
|
+
require 'staccato/timing'
|
33
|
+
require 'staccato/transaction'
|
34
|
+
require 'staccato/transaction_item'
|
23
35
|
require 'staccato/tracker'
|
data/lib/staccato/hit.rb
CHANGED
@@ -12,7 +12,7 @@ module Staccato
|
|
12
12
|
|
13
13
|
def initialize(tracker, options = {})
|
14
14
|
self.tracker = tracker
|
15
|
-
self.options =
|
15
|
+
self.options = OptionSet.new(options)
|
16
16
|
end
|
17
17
|
|
18
18
|
def fields
|
@@ -24,12 +24,17 @@ module Staccato
|
|
24
24
|
'v' => 1,
|
25
25
|
'tid' => tracker.id,
|
26
26
|
'cid' => tracker.client_id,
|
27
|
+
'ni' => non_interactive,
|
27
28
|
't' => type.to_s
|
28
29
|
}.merge(Hash[
|
29
30
|
fields.map {|field,key| [key, options[field]]}
|
30
31
|
]).reject {|_,v| v.nil?}
|
31
32
|
end
|
32
33
|
|
34
|
+
def non_interactive
|
35
|
+
1 if options[:non_interactive] # defaults to nil
|
36
|
+
end
|
37
|
+
|
33
38
|
def track!
|
34
39
|
post(Staccato.tracking_uri, params)
|
35
40
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Staccato
|
2
|
+
class Timing
|
3
|
+
FIELDS = {
|
4
|
+
category: 'utc',
|
5
|
+
variable: 'utv',
|
6
|
+
label: 'utl',
|
7
|
+
time: 'utt'
|
8
|
+
}
|
9
|
+
|
10
|
+
include Hit
|
11
|
+
|
12
|
+
def type
|
13
|
+
:timing
|
14
|
+
end
|
15
|
+
|
16
|
+
def track!(&block)
|
17
|
+
if block_given?
|
18
|
+
start_at = Time.now
|
19
|
+
block.call
|
20
|
+
end_at = Time.now
|
21
|
+
|
22
|
+
self.options.time = (end_at - start_at).to_i*1000
|
23
|
+
end
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/staccato/tracker.rb
CHANGED
@@ -10,7 +10,7 @@ module Staccato
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def client_id
|
13
|
-
@client_id ||=
|
13
|
+
@client_id ||= Staccato.build_client_id
|
14
14
|
end
|
15
15
|
|
16
16
|
def pageview(options = {})
|
@@ -28,5 +28,37 @@ module Staccato
|
|
28
28
|
def exception(options = {})
|
29
29
|
Staccato::Exception.new(self, options).track!
|
30
30
|
end
|
31
|
+
|
32
|
+
def timing(options = {}, &block)
|
33
|
+
Staccato::Timing.new(self, options).track!(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def transaction(options = {})
|
37
|
+
Staccato::Transaction.new(self, options).track!
|
38
|
+
end
|
39
|
+
|
40
|
+
def transaction_item(options = {})
|
41
|
+
Staccato::TransactionItem.new(self, options).track!
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class NoopTracker
|
46
|
+
def initialize(*); end
|
47
|
+
|
48
|
+
def id
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def client_id
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def pageview(*); end
|
57
|
+
def event(*); end
|
58
|
+
def social(*); end
|
59
|
+
def exception(*); end
|
60
|
+
def timing(*)
|
61
|
+
yield if block_given?
|
62
|
+
end
|
31
63
|
end
|
32
64
|
end
|
data/lib/staccato/version.rb
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Staccato::NoopTracker do
|
4
|
+
let(:uri) {Staccato.tracking_uri}
|
5
|
+
let(:tracker) {Staccato.tracker(nil)}
|
6
|
+
let(:response) {stub(:body => '', :status => 201)}
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
SecureRandom.stubs(:uuid).returns('555')
|
10
|
+
Net::HTTP.stubs(:post_form).returns(response)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#pageview" do
|
14
|
+
before(:each) do
|
15
|
+
tracker.pageview(path: '/foobar', title: 'FooBar', hostname: 'mysite.com')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'does not track page path and page title' do
|
19
|
+
Net::HTTP.should have_received(:post_form).never
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#event" do
|
24
|
+
before(:each) do
|
25
|
+
tracker.event({
|
26
|
+
category: 'video',
|
27
|
+
action: 'play',
|
28
|
+
label: 'cars',
|
29
|
+
value: 1
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not track event category, action, label, value' do
|
34
|
+
Net::HTTP.should have_received(:post_form).never
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#social" do
|
39
|
+
before(:each) do
|
40
|
+
tracker.social({
|
41
|
+
action: 'like',
|
42
|
+
network: 'facebook',
|
43
|
+
target: '/blog'
|
44
|
+
})
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'does not track social action, network, target' do
|
48
|
+
Net::HTTP.should have_received(:post_form).never
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#exception" do
|
53
|
+
before(:each) do
|
54
|
+
tracker.exception({
|
55
|
+
description: 'RuntimeException',
|
56
|
+
fatal: true
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'does not track exception description and fatality' do
|
61
|
+
Net::HTTP.should have_received(:post_form).never
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#timing" do
|
66
|
+
before(:each) do
|
67
|
+
tracker.timing({
|
68
|
+
category: 'view',
|
69
|
+
variable: 'runtime',
|
70
|
+
label: 'rails',
|
71
|
+
time: 1000
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does not track user timing category, variable, label, and time' do
|
76
|
+
Net::HTTP.should have_received(:post_form).never
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#timing with block" do
|
81
|
+
let(:codez) {stub(:test => true)}
|
82
|
+
|
83
|
+
before(:each) do
|
84
|
+
start_at = Time.now
|
85
|
+
end_at = start_at + 1 # 1 second
|
86
|
+
|
87
|
+
Time.stubs(:now).returns(start_at).returns(end_at)
|
88
|
+
|
89
|
+
tracker.timing({ category: 'view', variable: 'runtime', label: 'rails' }) do
|
90
|
+
codez.test
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'does not track user timing category, variable, label, and time' do
|
95
|
+
Net::HTTP.should have_received(:post_form).never
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'yields to the block' do
|
99
|
+
codez.should have_received(:test)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -78,19 +78,141 @@ describe Staccato::Tracker do
|
|
78
78
|
before(:each) do
|
79
79
|
tracker.exception({
|
80
80
|
description: 'RuntimeException',
|
81
|
-
fatal: true
|
81
|
+
fatal: true,
|
82
|
+
non_interactive: true
|
82
83
|
})
|
83
84
|
end
|
84
85
|
|
85
|
-
it 'tracks
|
86
|
+
it 'tracks exception description and fatality' do
|
86
87
|
Net::HTTP.should have_received(:post_form).with(uri, {
|
87
88
|
'v' => 1,
|
88
89
|
'tid' => 'UA-XXXX-Y',
|
89
90
|
'cid' => '555',
|
91
|
+
'ni' => 1,
|
90
92
|
't' => 'exception',
|
91
93
|
'exd' => 'RuntimeException',
|
92
94
|
'exf' => 1
|
93
95
|
})
|
94
96
|
end
|
95
97
|
end
|
98
|
+
|
99
|
+
describe "#timing" do
|
100
|
+
before(:each) do
|
101
|
+
tracker.timing({
|
102
|
+
category: 'view',
|
103
|
+
variable: 'runtime',
|
104
|
+
label: 'rails',
|
105
|
+
time: 1000
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'tracks user timing category, variable, label, and time' do
|
110
|
+
Net::HTTP.should have_received(:post_form).with(uri, {
|
111
|
+
'v' => 1,
|
112
|
+
'tid' => 'UA-XXXX-Y',
|
113
|
+
'cid' => '555',
|
114
|
+
't' => 'timing',
|
115
|
+
'utc' => 'view',
|
116
|
+
'utv' => 'runtime',
|
117
|
+
'utl' => 'rails',
|
118
|
+
'utt' => 1000 # value in milliseconds
|
119
|
+
})
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#timing with block" do
|
124
|
+
let(:codez) {stub(:test => true)}
|
125
|
+
|
126
|
+
before(:each) do
|
127
|
+
start_at = Time.now
|
128
|
+
end_at = start_at + 1 # 1 second
|
129
|
+
|
130
|
+
Time.stubs(:now).returns(start_at).returns(end_at)
|
131
|
+
|
132
|
+
tracker.timing({ category: 'view', variable: 'runtime', label: 'rails' }) do
|
133
|
+
codez.test
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'tracks user timing category, variable, label, and time' do
|
138
|
+
Net::HTTP.should have_received(:post_form).with(uri, {
|
139
|
+
'v' => 1,
|
140
|
+
'tid' => 'UA-XXXX-Y',
|
141
|
+
'cid' => '555',
|
142
|
+
't' => 'timing',
|
143
|
+
'utc' => 'view',
|
144
|
+
'utv' => 'runtime',
|
145
|
+
'utl' => 'rails',
|
146
|
+
'utt' => 1000
|
147
|
+
})
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'yields to the block' do
|
151
|
+
codez.should have_received(:test)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "Transactions" do
|
156
|
+
describe "#transaction" do
|
157
|
+
let(:transaction_id) {1293281}
|
158
|
+
|
159
|
+
before(:each) do
|
160
|
+
tracker.transaction({
|
161
|
+
transaction_id: transaction_id,
|
162
|
+
affiliation: 'western',
|
163
|
+
revenue: 5.99,
|
164
|
+
shipping: 12.00,
|
165
|
+
tax: 1.40,
|
166
|
+
currency: 'USD'
|
167
|
+
})
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'tracks the transaction values' do
|
171
|
+
Net::HTTP.should have_received(:post_form).with(uri, {
|
172
|
+
'v' => 1,
|
173
|
+
'tid' => 'UA-XXXX-Y',
|
174
|
+
'cid' => '555',
|
175
|
+
't' => 'transaction',
|
176
|
+
'ti' => transaction_id,
|
177
|
+
'ta' => 'western',
|
178
|
+
'tr' => 5.99,
|
179
|
+
'ts' => 12.0,
|
180
|
+
'tt' => 1.4,
|
181
|
+
'cu' => 'USD'
|
182
|
+
})
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#transaction_item" do
|
187
|
+
let(:transaction_id) {1293281}
|
188
|
+
|
189
|
+
before(:each) do
|
190
|
+
tracker.transaction_item({
|
191
|
+
transaction_id: transaction_id,
|
192
|
+
name: 'Sofa',
|
193
|
+
price: 804.99,
|
194
|
+
quantity: 2,
|
195
|
+
code: 'afhcka1230',
|
196
|
+
variation: 'furniture',
|
197
|
+
currency: 'USD'
|
198
|
+
})
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'tracks the item values' do
|
202
|
+
Net::HTTP.should have_received(:post_form).with(uri, {
|
203
|
+
'v' => 1,
|
204
|
+
'tid' => 'UA-XXXX-Y',
|
205
|
+
'cid' => '555',
|
206
|
+
't' => 'item',
|
207
|
+
'ti' => transaction_id,
|
208
|
+
'in' => 'Sofa',
|
209
|
+
'ip' => 804.99,
|
210
|
+
'iq' => 2,
|
211
|
+
'ic' => 'afhcka1230',
|
212
|
+
'iv' => 'furniture',
|
213
|
+
'cu' => 'USD'
|
214
|
+
})
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
96
218
|
end
|
data/spec/spec_helper.rb
CHANGED
data/staccato.gemspec
CHANGED
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.2
|
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:
|
12
|
+
date: 2014-01-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -91,6 +91,22 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: simplecov
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
94
110
|
description: Ruby Google Analytics Measurement
|
95
111
|
email:
|
96
112
|
- tpitale@gmail.com
|
@@ -100,6 +116,8 @@ extra_rdoc_files: []
|
|
100
116
|
files:
|
101
117
|
- .gitignore
|
102
118
|
- .rspec
|
119
|
+
- .ruby-version
|
120
|
+
- .travis.yml
|
103
121
|
- CHANGELOG.md
|
104
122
|
- Gemfile
|
105
123
|
- LICENSE.txt
|
@@ -109,10 +127,15 @@ files:
|
|
109
127
|
- lib/staccato/event.rb
|
110
128
|
- lib/staccato/exception.rb
|
111
129
|
- lib/staccato/hit.rb
|
130
|
+
- lib/staccato/option_set.rb
|
112
131
|
- lib/staccato/pageview.rb
|
113
132
|
- lib/staccato/social.rb
|
133
|
+
- lib/staccato/timing.rb
|
114
134
|
- lib/staccato/tracker.rb
|
135
|
+
- lib/staccato/transaction.rb
|
136
|
+
- lib/staccato/transaction_item.rb
|
115
137
|
- lib/staccato/version.rb
|
138
|
+
- spec/integration/noop_tracker_spec.rb
|
116
139
|
- spec/integration/tracker_spec.rb
|
117
140
|
- spec/lib/stacatto_spec.rb
|
118
141
|
- spec/lib/staccato/event_spec.rb
|
@@ -146,9 +169,11 @@ signing_key:
|
|
146
169
|
specification_version: 3
|
147
170
|
summary: Ruby Google Analytics Measurement
|
148
171
|
test_files:
|
172
|
+
- spec/integration/noop_tracker_spec.rb
|
149
173
|
- spec/integration/tracker_spec.rb
|
150
174
|
- spec/lib/stacatto_spec.rb
|
151
175
|
- spec/lib/staccato/event_spec.rb
|
152
176
|
- spec/lib/staccato/pageview_spec.rb
|
153
177
|
- spec/lib/staccato/tracker_spec.rb
|
154
178
|
- spec/spec_helper.rb
|
179
|
+
has_rdoc:
|