staccato 0.1.1 → 0.2.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.
@@ -0,0 +1,44 @@
1
+ module Staccato
2
+ # Measurable adds field mapping and param collection
3
+ # for Measurement classes to be add to Hit
4
+ module Measurable
5
+ def self.included(model)
6
+ model.extend Forwardable
7
+
8
+ model.class_eval do
9
+ attr_accessor :options
10
+
11
+ def_delegators :@options, *model::FIELDS.keys
12
+ end
13
+ end
14
+
15
+ # @param options [Hash] options for the measurement fields
16
+ def initialize(options = {})
17
+ self.options = OptionSet.new(options)
18
+ end
19
+
20
+ # fields from options for this measurement
21
+ def fields
22
+ self.class::FIELDS
23
+ end
24
+
25
+ # measurement option prefix
26
+ # @return [String]
27
+ def prefix
28
+ ''
29
+ end
30
+
31
+ # collects the parameters from options for this measurement
32
+ # @return [Hash]
33
+ def params
34
+ Hash[
35
+ fields.map { |field,key|
36
+ next if key.nil?
37
+ key = (prefix+key.to_s)
38
+
39
+ [key, options[field]] unless options[field].nil?
40
+ }.compact
41
+ ]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require 'staccato/measurable'
2
+ require 'staccato/null_measurement'
3
+
4
+ require 'staccato/measurement/checkout'
5
+ require 'staccato/measurement/checkout_option'
6
+ require 'staccato/measurement/impression_list'
7
+ require 'staccato/measurement/product'
8
+ require 'staccato/measurement/product_impression'
9
+ require 'staccato/measurement/promotion'
10
+ require 'staccato/measurement/transaction'
11
+
12
+ module Staccato
13
+ # Classes for measurements to be add to Hits
14
+ module Measurement
15
+ # List of measurement classes by lookup key
16
+ TYPES = Hash[
17
+ [
18
+ Checkout,
19
+ CheckoutOption,
20
+ ImpressionList,
21
+ Product,
22
+ ProductImpression,
23
+ Promotion,
24
+ Transaction
25
+ ].map { |k| [k.lookup_key, k] }
26
+ ].freeze
27
+
28
+ # Lookup a measurement class by its key
29
+ # @param key [Symbol]
30
+ # @return [Class] measurement class or NullMeasurement
31
+ def lookup(key)
32
+ measurement_types[key] || NullMeasurement
33
+ end
34
+ module_function :lookup
35
+
36
+ # List of measurement classes by lookup key
37
+ # @return [Hash]
38
+ def measurement_types
39
+ TYPES
40
+ end
41
+ module_function :measurement_types
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for checkout action steps
4
+ class Checkout
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :checkout
9
+ end
10
+
11
+ # Checkout measurement options fields
12
+ FIELDS = {
13
+ step: 'cos', # integer
14
+ step_options: 'col' # text
15
+ }.freeze
16
+
17
+ include Measurable
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for checkout options
4
+ class CheckoutOption
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :checkout_option
9
+ end
10
+
11
+ # Checkout option measurement options fields
12
+ FIELDS = {
13
+ step: 'cos', # integer
14
+ step_options: 'col' # text
15
+ }.freeze
16
+
17
+ include Measurable
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for impressions in a list for products
4
+ class ImpressionList
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :impression_list
9
+ end
10
+
11
+ # impression list prefix
12
+ # @return [String]
13
+ def prefix
14
+ 'il'+index.to_s
15
+ end
16
+
17
+ # Impression list measurement options fields
18
+ FIELDS = {
19
+ index: nil,
20
+ name: 'nm'
21
+ }.freeze
22
+
23
+ include Measurable
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for products in a transaction or other action
4
+ class Product
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :product
9
+ end
10
+
11
+ # product prefix
12
+ # @return [String]
13
+ def prefix
14
+ 'pr'+index.to_s
15
+ end
16
+
17
+ # Product measurement options fields
18
+ FIELDS = {
19
+ index: nil,
20
+ id: 'id', # text
21
+ name: 'nm', # text
22
+ brand: 'br', # text
23
+ category: 'ca', # text
24
+ variant: 'va', # text
25
+ price: 'pr', # currency (looks like a double?)
26
+ quantity: 'qt', # integer
27
+ coupon_code: 'cc', # text
28
+ position: 'ps' # integer
29
+ }.freeze
30
+
31
+ include Measurable
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for product impressions in a list
4
+ class ProductImpression
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :product_impression
9
+ end
10
+
11
+ # product impress prefix
12
+ # @return [String]
13
+ def prefix
14
+ 'il' + list_index.to_s + 'pr' + index.to_s
15
+ end
16
+
17
+ # Product impression measurement options fields
18
+ FIELDS = {
19
+ index: nil,
20
+ list_index: nil,
21
+ id: 'id', # text
22
+ name: 'nm', # text
23
+ brand: 'br', # text
24
+ category: 'ca', # text
25
+ variant: 'va', # text
26
+ price: 'pr', # currency (looks like a double?)
27
+ position: 'ps' # integer
28
+ }.freeze
29
+
30
+ include Measurable
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for promotion impressions/clicks
4
+ class Promotion
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :promotion
9
+ end
10
+
11
+ # promotion prefix
12
+ # @return [String]
13
+ def prefix
14
+ 'promo'+index.to_s
15
+ end
16
+
17
+ # Promotion measurement options fields
18
+ FIELDS = {
19
+ index: nil,
20
+ id: 'id', # text
21
+ name: 'nm', # text
22
+ creative: 'cr', # text
23
+ position: 'ps' # text
24
+ }.freeze
25
+
26
+ include Measurable
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ module Staccato
2
+ module Measurement
3
+ # Measurement class for transaction (non-hit data)
4
+ class Transaction
5
+ # lookup key for use in Hit#add_measurement
6
+ # @return [Symbol]
7
+ def self.lookup_key
8
+ :transaction
9
+ end
10
+
11
+ # Transaction measurement options fields
12
+ FIELDS = {
13
+ transaction_id: 'ti',
14
+ affiliation: 'ta',
15
+ revenue: 'tr',
16
+ shipping: 'ts',
17
+ tax: 'tt',
18
+ currency: 'cu',
19
+ coupon_code: 'tcc'
20
+ }.freeze
21
+
22
+ include Measurable
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # Measurement class for when we need a standin
2
+ class NullMeasurement
3
+ # Measurement fields for a noop
4
+ FIELDS = {}.freeze
5
+
6
+ # Initialize a noop measurement standin
7
+ def initialize(*); end
8
+
9
+ # Params for this noop measurement
10
+ # @return [Hash]
11
+ def params(*); {}; end
12
+ end
@@ -9,6 +9,7 @@ module Staccato
9
9
  # sets up a new tracker
10
10
  # @param id [String] the GA tracker id
11
11
  # @param client_id [String, nil] unique value to track user sessions
12
+ # @param hit_defaults [Hash]
12
13
  def initialize(id, client_id = nil, hit_defaults = {})
13
14
  @id = id
14
15
  @client_id = client_id
@@ -28,6 +29,17 @@ module Staccato
28
29
  @client_id ||= Staccato.build_client_id
29
30
  end
30
31
 
32
+ # Build a pageview
33
+ #
34
+ # @param options [Hash] options include:
35
+ # * path (optional) the path of the current page view
36
+ # * hostname (optional) the hostname of the current page view
37
+ # * title (optional) the page title
38
+ # @return [Pageview]
39
+ def build_pageview(options = {})
40
+ Staccato::Pageview.new(self, options)
41
+ end
42
+
31
43
  # Track a pageview
32
44
  #
33
45
  # @param options [Hash] options include:
@@ -36,7 +48,19 @@ module Staccato
36
48
  # * title (optional) the page title
37
49
  # @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
38
50
  def pageview(options = {})
39
- Staccato::Pageview.new(self, options).track!
51
+ build_pageview(options).track!
52
+ end
53
+
54
+ # Build an event
55
+ #
56
+ # @param options [Hash] options include:
57
+ # * category (optional)
58
+ # * action (optional)
59
+ # * label (optional)
60
+ # * value (optional)
61
+ # @return [Event]
62
+ def build_event(options = {})
63
+ Staccato::Event.new(self, options)
40
64
  end
41
65
 
42
66
  # Track an event
@@ -48,7 +72,7 @@ module Staccato
48
72
  # * value (optional)
49
73
  # @return [<Net::HTTPOK] the GA `/collect` endpoint always returns a 200
50
74
  def event(options = {})
51
- Staccato::Event.new(self, options).track!
75
+ build_event(options).track!
52
76
  end
53
77
 
54
78
  # Track a social event such as a Facebook Like or Twitter Share
@@ -123,8 +147,10 @@ module Staccato
123
147
  # Useful in testing
124
148
  class NoopTracker
125
149
  # (see Tracker#initialize)
126
- def initialize(*); end
150
+ def initialize(id = nil, client_id = nil, hit_defaults = {}); end
127
151
 
152
+ # hit defaults for our noop
153
+ # @return [Hash]
128
154
  def hit_defaults
129
155
  {}
130
156
  end
@@ -139,26 +165,31 @@ module Staccato
139
165
  nil
140
166
  end
141
167
 
168
+ # (see Tracker#build_pageview)
169
+ def build_pageview(options = {}); end
142
170
  # (see Tracker#pageview)
143
- def pageview(*); end
171
+ def pageview(options = {}); end
172
+ # (see Tracker#build_event)
173
+ def build_event(options = {}); end
144
174
  # (see Tracker#event)
145
- def event(*); end
175
+ def event(options = {}); end
146
176
  # (see Tracker#social)
147
- def social(*); end
177
+ def social(options = {}); end
148
178
  # (see Tracker#exception)
149
- def exception(*); end
179
+ def exception(options = {}); end
150
180
  # (see Tracker#timing)
151
- def timing(*)
181
+ def timing(options = {}, &block)
152
182
  yield if block_given?
153
183
  end
154
184
  # (see Tracker#transaction)
155
- def transaction(*)
185
+ def transaction(options = {})
156
186
  end
157
187
  # (see Tracker#transaction_item)
158
- def transaction_item(*)
188
+ def transaction_item(options = {})
159
189
  end
160
190
 
161
- def track(*)
191
+ # (see Tracker#track)
192
+ def track(params = {})
162
193
  end
163
194
  end
164
195
  end
@@ -1,4 +1,4 @@
1
1
  module Staccato
2
2
  # The current Staccato VERSION
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2.0"
4
4
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Staccato::Measurement::CheckoutOption do
4
+ let(:uri) {Staccato.tracking_uri}
5
+ let(:tracker) {Staccato.tracker('UA-XXXX-Y')}
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
+ context 'a pageview with a transaction' do
14
+ let(:pageview) {
15
+ tracker.build_pageview({
16
+ path: '/checkout', hostname: 'mystore.com',
17
+ title: 'Complete Your Checkout', product_action: 'checkout_option'
18
+ })
19
+ }
20
+
21
+ let(:measurment_options) {{
22
+ step: 1,
23
+ step_options: 'Visa'
24
+ }}
25
+
26
+ before(:each) do
27
+ pageview.add_measurement(:checkout_option, measurment_options)
28
+
29
+ pageview.track!
30
+ end
31
+
32
+ it 'tracks the measurment' do
33
+ Net::HTTP.should have_received(:post_form).with(uri, {
34
+ 'v' => 1,
35
+ 'tid' => 'UA-XXXX-Y',
36
+ 'cid' => '555',
37
+ 't' => 'pageview',
38
+ 'dh' => 'mystore.com',
39
+ 'dp' => '/checkout',
40
+ 'dt' => 'Complete Your Checkout',
41
+ 'pa' => 'checkout_option',
42
+ 'cos' => 1,
43
+ 'col' => 'Visa'
44
+ })
45
+ end
46
+ end
47
+ end