staccato 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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