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 CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ coverage
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p448
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ script: bundle exec rake
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
+ [![Build Status](https://travis-ci.org/tpitale/staccato.png?branch=master)](https://travis-ci.org/tpitale/staccato)
6
+ [![Code Climate](https://codeclimate.com/github/tpitale/staccato.png)](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
- Staccato::Tracker.new(id, client_id)
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 = OpenStruct.new(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,9 @@
1
+ module Staccato
2
+ class OptionSet < OpenStruct
3
+ unless OpenStruct.instance_methods.include?(:[])
4
+ extend Forwardable
5
+
6
+ def_delegators :@table, :[], :[]=
7
+ end
8
+ end
9
+ 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
@@ -10,7 +10,7 @@ module Staccato
10
10
  end
11
11
 
12
12
  def client_id
13
- @client_id ||= SecureRandom.uuid
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
@@ -0,0 +1,18 @@
1
+ module Staccato
2
+ class Transaction
3
+ FIELDS = {
4
+ transaction_id: 'ti',
5
+ affiliation: 'ta',
6
+ revenue: 'tr',
7
+ shipping: 'ts',
8
+ tax: 'tt',
9
+ currency: 'cu'
10
+ }
11
+
12
+ include Hit
13
+
14
+ def type
15
+ :transaction
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module Staccato
2
+ class TransactionItem
3
+ FIELDS = {
4
+ transaction_id: 'ti',
5
+ name: 'in',
6
+ price: 'ip',
7
+ quantity: 'iq',
8
+ code: 'ic',
9
+ variation: 'iv',
10
+ currency: 'cu'
11
+ }
12
+
13
+ include Hit
14
+
15
+ def type
16
+ :item
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Staccato
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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 social action, network, target' do
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
@@ -1,3 +1,6 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  require 'bundler/setup'
2
5
 
3
6
  require 'rspec'
data/staccato.gemspec CHANGED
@@ -23,6 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rspec"
24
24
  spec.add_development_dependency "mocha"
25
25
  spec.add_development_dependency "bourne"
26
-
27
- # spec.add_runtime_dependency "uuid"
26
+ spec.add_development_dependency "simplecov"
28
27
  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.1
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: 2013-08-04 00:00:00.000000000 Z
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: