staccato 0.0.2 → 0.0.3

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 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,4 +1,6 @@
1
1
  module Staccato
2
+ # Extends OpenStruct with `[]` access method when
3
+ # the current version of ruby does not include it
2
4
  class OptionSet < OpenStruct
3
5
  unless OpenStruct.instance_methods.include?(:[])
4
6
  extend Forwardable
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,3 +1,4 @@
1
1
  module Staccato
2
- VERSION = "0.0.2"
2
+ # The current Staccato VERSION
3
+ VERSION = "0.0.3"
3
4
  end
@@ -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.2
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-10 00:00:00.000000000 Z
12
+ date: 2014-01-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler