snowplow-tracker 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTZkNTg1MGZiZTIyNzY0NmY4ZTk2ZDYxMjVkMTU3ZmJkZDllODlkMA==
4
+ ZjRhYzM4NmY5ZjI3ZWNkZDY0MGJkNDRhMWRiZGU0N2I0YjhkMDU3Yg==
5
5
  data.tar.gz: !binary |-
6
- YTQ5ZDhhYTFiNmJlODI4YTMyNTg1YWIwODQ3ZWJmMzNkZDk4MmE1YQ==
6
+ MTVkNjQxNDU2OWRhZWU2MDc5YjRkMmNhNTg5NmVlNjU4YTE1MzY2OA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODhmY2ZmMmNjMTA2MzNmZTg2OGEzNDRhODVkZjc3YjY0NGI5NzAyZjUwNjc2
10
- MDFmYzZhYjNmZjg4ZmIwZTA4MmFlOTI5NmZlODljYjAwNWQ1OGVlZGFmOTFl
11
- ZjhhOTVjNGE3NzY2ZTViMjE2OTI0YmUzYTg1Zjg2OWJkZWJkNjU=
9
+ YzM1MTc1Y2E0ZGQ1ZjY3NzljZDcwNDdjYWUzYjM4Y2MzMTQ1MTE4ODUwYjk0
10
+ NzIxZGQ1NjY1MDAzY2IzZTljN2M4ZWM0NmEwMTZmNzllZWY0NzYzOGMyNDMz
11
+ ODZlNjY4NDYyZDlhY2ZmNGMyZDQ1M2YwMDYwOGIxYTEwMDU2NTI=
12
12
  data.tar.gz: !binary |-
13
- Y2UyMTIwOWRhNWYxNTkxZTAxYjgxMTFhMjMzMWMxYjc0MDYyNTNkMTZiYmNk
14
- MGU2MjQ0MzU2ODAyNGZhZjk0YmIxYTNhOWI5MjhhNzFmNGYyMTdmZGM4Mzlh
15
- OTg4MDUyZTNiY2NmN2Q1MjZjNmEwMGM0MDQ1YTQ3MWEyMzJkM2Q=
13
+ MDMxMzZjYTQxNWU3NDhhYzUwZjJhNjkwNGI4MTk2ZTI1YzBmMjE1MDEzNWZj
14
+ MTY5OGU5ZWE1MTExYmQ0YWRhMmFiNjA5MzgxNDhlNDg4NzEyYWNlMTQ1ZTU4
15
+ NWE5MTkxNjg1NDUxZTU0ZjgyZGE1NjFmNWU1ODExNDZkZGY5ZDA=
@@ -13,6 +13,9 @@
13
13
  # Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
14
14
  # License:: Apache License Version 2.0
15
15
 
16
+ require 'snowplow-tracker/contracts.rb'
16
17
  require 'snowplow-tracker/version.rb'
17
18
  require 'snowplow-tracker/payload.rb'
19
+ require 'snowplow-tracker/subject.rb'
20
+ require 'snowplow-tracker/emitters.rb'
18
21
  require 'snowplow-tracker/tracker.rb'
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ require 'contracts'
17
+ include Contracts
18
+
19
+ module SnowplowTracker
20
+
21
+ ORIGINAL_FAILURE_CALLBACK = Contract.method(:failure_callback)
22
+
23
+ def self.disable_contracts
24
+ Contract.define_singleton_method(:failure_callback) {|data| true}
25
+ end
26
+
27
+ def self.enable_contracts
28
+ Contract.define_singleton_method(:failure_callback, ORIGINAL_FAILURE_CALLBACK)
29
+ end
30
+ end
@@ -0,0 +1,218 @@
1
+ # Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ require 'net/http'
17
+ require 'set'
18
+ require 'logger'
19
+ require 'contracts'
20
+ include Contracts
21
+
22
+ module SnowplowTracker
23
+
24
+ LOGGER = Logger.new(STDERR)
25
+ LOGGER.level = Logger::INFO
26
+
27
+ class Emitter
28
+
29
+ @@ConfigHash = ({
30
+ :protocol => Maybe[Or['http', 'https']],
31
+ :port => Maybe[Num],
32
+ :method => Maybe[Or['get', 'post']],
33
+ :buffer_size => Maybe[Num],
34
+ :on_success => Maybe[Func[Num => Any]],
35
+ :on_failure => Maybe[Func[Num, Hash => Any]]
36
+ })
37
+
38
+ @@StrictConfigHash = And[@@ConfigHash, lambda { |x|
39
+ x.class == Hash and Set.new(x.keys).subset? Set.new(@@ConfigHash.keys)
40
+ }]
41
+
42
+ @@DefaultConfig = {
43
+ :protocol => 'http',
44
+ :method => 'get'
45
+ }
46
+
47
+ Contract String, @@StrictConfigHash => lambda { |x| x.is_a? Emitter }
48
+ def initialize(endpoint, config={})
49
+ config = @@DefaultConfig.merge(config)
50
+ @collector_uri = as_collector_uri(endpoint, config[:protocol], config[:port], config[:method])
51
+ @buffer = []
52
+ if not config[:buffer_size].nil?
53
+ @buffer_size = config[:buffer_size]
54
+ elsif config[:method] == 'get'
55
+ @buffer_size = 0
56
+ else
57
+ @buffer_size = 10
58
+ end
59
+ @method = config[:method]
60
+ @on_success = config[:on_success]
61
+ @on_failure = config[:on_failure]
62
+ @threads = []
63
+ LOGGER.info("#{self.class} initialized with endpoint #{@collector_uri}")
64
+
65
+ self
66
+ end
67
+
68
+ # Build the collector URI from the configuration hash
69
+ #
70
+ Contract String, String, Maybe[Num], String => String
71
+ def as_collector_uri(endpoint, protocol, port, method)
72
+ port_string = port == nil ? '' : ":#{port.to_s}"
73
+ path = method == 'get' ? '/i' : '/com.snowplowanalytics.snowplow/tp2'
74
+
75
+ "#{protocol}://#{endpoint}#{port_string}#{path}"
76
+ end
77
+
78
+ # Add an event to the buffer and flush it if maximum size has been reached
79
+ #
80
+ Contract Hash => nil
81
+ def input(payload)
82
+ payload.each { |k,v| payload[k] = v.to_s}
83
+ @buffer.push(payload)
84
+ if @buffer.size > @buffer_size
85
+ flush
86
+ end
87
+
88
+ nil
89
+ end
90
+
91
+ # Flush the buffer
92
+ #
93
+ Contract Bool => nil
94
+ def flush(sync=false)
95
+ send_requests
96
+
97
+ nil
98
+ end
99
+
100
+ # Send all events in the buffer to the collector
101
+ #
102
+ Contract None => nil
103
+ def send_requests
104
+ LOGGER.info("Attempting to send #{@buffer.size} request#{@buffer.size == 1 ? '' : 's'}")
105
+ temp_buffer = @buffer
106
+ @buffer = []
107
+
108
+ if @method == 'get'
109
+ success_count = 0
110
+ unsent_requests = []
111
+ temp_buffer.each do |payload|
112
+ request = http_get(payload)
113
+ if request.code.to_i == 200
114
+ success_count += 1
115
+ else
116
+ unsent_requests.push(payload)
117
+ end
118
+ if unsent_requests.size == 0
119
+ unless @on_success.nil?
120
+ @on_success.call(success_count)
121
+ end
122
+ else
123
+ unless @on_failure.nil?
124
+ @on_failure.call(success_count, unsent_requests)
125
+ end
126
+ end
127
+ end
128
+
129
+ elsif @method == 'post'
130
+ if temp_buffer.size > 0
131
+ request = http_post({
132
+ 'schema' => 'iglu:com.snowplowanalytics.snowplow/payload_data/1-0-0',
133
+ 'data' => temp_buffer
134
+ })
135
+
136
+ if request.code.to_i == 200
137
+ unless @on_success.nil?
138
+ @on_success.call(temp_buffer.size)
139
+ end
140
+ else
141
+ unless @on_failure.nil?
142
+ @on_failure.call(0, temp_buffer)
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+
149
+ nil
150
+ end
151
+
152
+ # Send a GET request
153
+ #
154
+ Contract Hash => lambda { |x| x.is_a? Net::HTTPResponse }
155
+ def http_get(payload)
156
+ destination = URI(@collector_uri + '?' + URI.encode_www_form(payload))
157
+ LOGGER.info("Sending GET request to #{@collector_uri}...")
158
+ LOGGER.debug("Payload: #{payload}")
159
+ response = Net::HTTP.get_response(destination)
160
+ LOGGER.add(response.code == '200' ? Logger::INFO : Logger::WARN) {
161
+ "GET request to #{@collector_uri} finished with status code #{response.code}"
162
+ }
163
+
164
+ response
165
+ end
166
+
167
+ # Send a POST request
168
+ #
169
+ Contract Hash => lambda { |x| x.is_a? Net::HTTPResponse }
170
+ def http_post(payload)
171
+ LOGGER.info("Sending POST request to #{@collector_uri}...")
172
+ LOGGER.debug("Payload: #{payload}")
173
+ destination = URI(@collector_uri)
174
+ http = Net::HTTP.new(destination.host, destination.port)
175
+ request = Net::HTTP::Post.new(destination)
176
+ request.form_data = payload
177
+ request.set_content_type('application/json; charset=utf-8')
178
+ response = http.request(request)
179
+ LOGGER.add(response.code == '200' ? Logger::INFO : Logger::WARN) {
180
+ "POST request to #{@collector_uri} finished with status code #{response.code}"
181
+ }
182
+
183
+ response
184
+ end
185
+
186
+ private :as_collector_uri,
187
+ :http_get,
188
+ :http_post
189
+
190
+ end
191
+
192
+
193
+ class AsyncEmitter < Emitter
194
+
195
+ # Flush the buffer in a new thread
196
+ # If sync is true, block until all flushing threads have exited
197
+ #
198
+ def flush(sync=false)
199
+ t = Thread.new do
200
+ send_requests
201
+ end
202
+ t.abort_on_exception = true
203
+ @threads.select!{ |thread| thread.alive?}
204
+ @threads.push(t)
205
+
206
+ if sync
207
+ LOGGER.info('Starting synchronous flush')
208
+ @threads.each do |thread|
209
+ thread.join(10)
210
+ end
211
+ end
212
+
213
+ nil
214
+ end
215
+
216
+ end
217
+
218
+ end
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ require 'contracts'
17
+ include Contracts
18
+
19
+ module SnowplowTracker
20
+
21
+ class Subject
22
+
23
+ @@default_platform = 'srv'
24
+ @@supported_platforms = ['pc', 'tv', 'mob', 'cnsl', 'iot']
25
+
26
+ attr_reader :standard_nv_pairs
27
+
28
+ Contract None => Subject
29
+ def initialize
30
+ @standard_nv_pairs = {"p" => @@default_platform}
31
+ self
32
+ end
33
+
34
+ # Specify the platform
35
+ #
36
+ Contract String => Subject
37
+ def set_platform(value)
38
+ if @@supported_platforms.include?(value)
39
+ @standard_nv_pairs['p'] = value
40
+ else
41
+ raise "#{value} is not a supported platform"
42
+ end
43
+
44
+ self
45
+ end
46
+
47
+ # Set the business-defined user ID for a user
48
+ #
49
+ Contract String => Subject
50
+ def set_user_id(user_id)
51
+ @standard_nv_pairs['uid'] = user_id
52
+ self
53
+ end
54
+
55
+ # Set the screen resolution for a device
56
+ #
57
+ Contract Num, Num => Subject
58
+ def set_screen_resolution(width, height)
59
+ @standard_nv_pairs['res'] = "#{width}x#{height}"
60
+ self
61
+ end
62
+
63
+ # Set the dimensions of the current viewport
64
+ #
65
+ Contract Num, Num => Subject
66
+ def set_viewport(width, height)
67
+ @standard_nv_pairs['vp'] = "#{width}x#{height}"
68
+ self
69
+ end
70
+
71
+ # Set the color depth of the device in bits per pixel
72
+ #
73
+ Contract Num => Subject
74
+ def set_color_depth(depth)
75
+ @standard_nv_pairs['cd'] = depth
76
+ self
77
+ end
78
+
79
+ # Set the timezone field
80
+ #
81
+ Contract String => Subject
82
+ def set_timezone(timezone)
83
+ @standard_nv_pairs['tz'] = timezone
84
+ self
85
+ end
86
+
87
+ # Set the language field
88
+ #
89
+ Contract String => Subject
90
+ def set_lang(lang)
91
+ @standard_nv_pairs['lang'] = lang
92
+ self
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -13,7 +13,6 @@
13
13
  # Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
14
14
  # License:: Apache License Version 2.0
15
15
 
16
- require 'net/http'
17
16
  require 'contracts'
18
17
  require 'set'
19
18
  include Contracts
@@ -24,6 +23,8 @@ module SnowplowTracker
24
23
 
25
24
  class Tracker
26
25
 
26
+ @@EmitterInput = Or[lambda {|x| x.is_a? Emitter}, ArrayOf[lambda {|x| x.is_a? Emitter}]]
27
+
27
28
  @@required_transaction_keys = Set.new(%w(order_id total_value))
28
29
  @@recognised_transaction_keys = Set.new(%w(order_id total_value affiliation tax_value shipping city state country currency))
29
30
 
@@ -66,38 +67,41 @@ module SnowplowTracker
66
67
 
67
68
  @@version = TRACKER_VERSION
68
69
  @@default_encode_base64 = true
69
- @@default_platform = 'pc'
70
- @@supported_platforms = ['pc', 'tv', 'mob', 'cnsl', 'iot']
71
- @@http_errors = ['host not found',
72
- 'No address associated with name',
73
- 'No address associated with hostname']
74
70
 
75
71
  @@base_schema_path = "iglu:com.snowplowanalytics.snowplow"
76
72
  @@schema_tag = "jsonschema"
77
73
  @@context_schema = "#{@@base_schema_path}/contexts/#{@@schema_tag}/1-0-0"
78
74
  @@unstruct_event_schema = "#{@@base_schema_path}/unstruct_event/#{@@schema_tag}/1-0-0"
79
75
 
80
- Contract String, Maybe[String], Maybe[String], Bool => Tracker
81
- def initialize(endpoint, namespace=nil, app_id=nil, encode_base64=@@default_encode_base64)
82
- @collector_uri = as_collector_uri(endpoint)
76
+ Contract @@EmitterInput, Maybe[Subject], Maybe[String], Maybe[String], Bool => Tracker
77
+ def initialize(emitters, subject=nil, namespace=nil, app_id=nil, encode_base64=@@default_encode_base64)
78
+ @emitters = Array(emitters)
79
+ if subject.nil?
80
+ @subject = Subject.new
81
+ else
82
+ @subject = subject
83
+ end
83
84
  @standard_nv_pairs = {
84
85
  'tna' => namespace,
85
86
  'tv' => @@version,
86
- 'p' => @@default_platform,
87
87
  'aid' => app_id
88
88
  }
89
89
  @config = {
90
90
  'encode_base64' => encode_base64
91
91
  }
92
92
  @uuid = UUID.new
93
+
93
94
  self
94
95
  end
95
96
 
96
- # Adds the protocol to the fron of the collector URL, and /i to the end
97
+ # Call subject methods from tracker instance
97
98
  #
98
- Contract String => String
99
- def as_collector_uri(host)
100
- "http://#{host}/i"
99
+ Subject.instance_methods(false).each do |name|
100
+ define_method name, ->(*splat) do
101
+ @subject.method(name.to_sym).call(*splat)
102
+
103
+ self
104
+ end
101
105
  end
102
106
 
103
107
  # Generates a type-4 UUID to identify this event
@@ -123,92 +127,24 @@ module SnowplowTracker
123
127
  }
124
128
  end
125
129
 
126
- # Send request
127
- #
128
- Contract Payload => [Bool, Num]
129
- def http_get(payload)
130
- destination = URI(@collector_uri + '?' + URI.encode_www_form(payload.context))
131
- r = Net::HTTP.get_response(destination)
132
- if @@http_errors.include? r.code
133
- return false, "Host [#{r.host}] not found (possible connectivity error)"
134
- elsif r.code.to_i < 0 or 400 <= r.code.to_i
135
- return false, r.code.to_i
136
- else
137
- return true, r.code.to_i
138
- end
139
- end
140
-
141
- # Setter methods
142
-
143
- # Specify the platform
144
- #
145
- Contract String => String
146
- def set_platform(value)
147
- if @@supported_platforms.include?(value)
148
- @standard_nv_pairs['p'] = value
149
- else
150
- raise "#{value} is not a supported platform"
151
- end
152
- end
153
-
154
- # Set the business-defined user ID for a user
155
- #
156
- Contract String => String
157
- def set_user_id(user_id)
158
- @standard_nv_pairs['uid'] = user_id
159
- end
160
-
161
- # Set the screen resolution for a device
162
- #
163
- Contract Num, Num => String
164
- def set_screen_resolution(width, height)
165
- @standard_nv_pairs['res'] = "#{width}x#{height}"
166
- end
167
-
168
- # Set the dimensions of the current viewport
169
- #
170
- Contract Num, Num => String
171
- def set_viewport(width, height)
172
- @standard_nv_pairs['vp'] = "#{width}x#{height}"
173
- end
174
-
175
- # Set the color depth of the device in bits per pixel
176
- #
177
- Contract Num => Num
178
- def set_color_depth(depth)
179
- @standard_nv_pairs['cd'] = depth
180
- end
181
-
182
- # Set the timezone field
183
- #
184
- Contract String => String
185
- def set_timezone(timezone)
186
- @standard_nv_pairs['tz'] = timezone
187
- end
188
-
189
- # Set the language field
190
- #
191
- Contract String => String
192
- def set_lang(lang)
193
- @standard_nv_pairs['lang'] = lang
194
- end
195
-
196
130
  # Tracking methods
197
131
 
198
132
  # Attaches all the fields in @standard_nv_pairs to the request
199
133
  # Only attaches the context vendor if the event has a custom context
200
134
  #
201
- Contract Payload => [Bool, Num]
135
+ Contract Payload => nil
202
136
  def track(pb)
137
+ pb.add_dict(@subject.standard_nv_pairs)
203
138
  pb.add_dict(@standard_nv_pairs)
204
139
  pb.add('eid', get_event_id())
140
+ @emitters.each{ |emitter| emitter.input(pb.context)}
205
141
 
206
- http_get(pb)
142
+ nil
207
143
  end
208
144
 
209
145
  # Log a visit to this page
210
146
  #
211
- Contract String, Maybe[String], Maybe[String], Maybe[@@ContextsInput] => [Bool, Num]
147
+ Contract String, Maybe[String], Maybe[String], Maybe[@@ContextsInput] => Tracker
212
148
  def track_page_view(page_url, page_title=nil, referrer=nil, context=nil, tstamp=nil)
213
149
  pb = Payload.new
214
150
  pb.add('e', 'pv')
@@ -224,12 +160,14 @@ module SnowplowTracker
224
160
  end
225
161
  pb.add('dtm', tstamp)
226
162
  track(pb)
163
+
164
+ self
227
165
  end
228
166
 
229
167
  # Track a single item within an ecommerce transaction
230
168
  # Not part of the public API
231
169
  #
232
- Contract @@AugmentedItem => [Bool, Num]
170
+ Contract @@AugmentedItem => self
233
171
  def track_ecommerce_transaction_item(argmap)
234
172
  pb = Payload.new
235
173
  pb.add('e', 'ti')
@@ -245,11 +183,13 @@ module SnowplowTracker
245
183
  end
246
184
  pb.add('dtm', argmap['tstamp'])
247
185
  track(pb)
186
+
187
+ self
248
188
  end
249
189
 
250
190
  # Track an ecommerce transaction and all the items in it
251
191
  #
252
- Contract @@Transaction, ArrayOf[@@Item], Maybe[@@ContextsInput], Maybe[Num] => ({'transaction_result' => [Bool, Num], 'item_results' => ArrayOf[[Bool, Num]]})
192
+ Contract @@Transaction, ArrayOf[@@Item], Maybe[@@ContextsInput], Maybe[Num] => Tracker
253
193
  def track_ecommerce_transaction(transaction, items,
254
194
  context=nil, tstamp=nil)
255
195
  pb = Payload.new
@@ -272,22 +212,21 @@ module SnowplowTracker
272
212
  end
273
213
  pb.add('dtm', tstamp)
274
214
 
275
- transaction_result = track(pb)
276
- item_results = []
215
+ track(pb)
277
216
 
278
217
  for item in items
279
218
  item['tstamp'] = tstamp
280
219
  item['order_id'] = transaction['order_id']
281
220
  item['currency'] = transaction['currency']
282
- item_results.push(track_ecommerce_transaction_item(item))
221
+ track_ecommerce_transaction_item(item)
283
222
  end
284
223
 
285
- {'transaction_result' => transaction_result, 'item_results' => item_results}
224
+ self
286
225
  end
287
226
 
288
227
  # Track a structured event
289
228
  #
290
- Contract String, String, Maybe[String], Maybe[String], Maybe[Num], Maybe[@@ContextsInput], Maybe[Num] => [Bool, Num]
229
+ Contract String, String, Maybe[String], Maybe[String], Maybe[Num], Maybe[@@ContextsInput], Maybe[Num] => Tracker
291
230
  def track_struct_event(category, action, label=nil, property=nil, value=nil, context=nil, tstamp=nil)
292
231
  pb = Payload.new
293
232
  pb.add('e', 'se')
@@ -304,13 +243,18 @@ module SnowplowTracker
304
243
  end
305
244
  pb.add('dtm', tstamp)
306
245
  track(pb)
246
+
247
+ self
307
248
  end
308
249
 
309
250
  # Track a screen view event
310
251
  #
311
- Contract String, Maybe[String], Maybe[@@ContextsInput], Maybe[Num] => [Bool, Num]
312
- def track_screen_view(name, id=nil, context=nil, tstamp=nil)
313
- screen_view_properties = {'name' => name}
252
+ Contract Maybe[String], Maybe[String], Maybe[@@ContextsInput], Maybe[Num] => Tracker
253
+ def track_screen_view(name=nil, id=nil, context=nil, tstamp=nil)
254
+ screen_view_properties = {}
255
+ unless name.nil?
256
+ screen_view_properties['name'] = name
257
+ end
314
258
  unless id.nil?
315
259
  screen_view_properties['id'] = id
316
260
  end
@@ -318,11 +262,13 @@ module SnowplowTracker
318
262
  event_json = {schema: screen_view_schema, data: screen_view_properties}
319
263
 
320
264
  self.track_unstruct_event(event_json, context, tstamp)
265
+
266
+ self
321
267
  end
322
268
 
323
269
  # Track an unstructured event
324
270
  #
325
- Contract @@SelfDescribingJson, Maybe[@@ContextsInput], Maybe[Num] => [Bool, Num]
271
+ Contract @@SelfDescribingJson, Maybe[@@ContextsInput], Maybe[Num] => Tracker
326
272
  def track_unstruct_event(event_json, context=nil, tstamp=nil)
327
273
  pb = Payload.new
328
274
  pb.add('e', 'ue')
@@ -343,12 +289,39 @@ module SnowplowTracker
343
289
  pb.add('dtm', tstamp)
344
290
 
345
291
  track(pb)
292
+
293
+ self
294
+ end
295
+
296
+ # Flush all events stored in all emitters
297
+ #
298
+ Contract Bool => Tracker
299
+ def flush(sync=false)
300
+ @emitters.each do |emitter|
301
+ emitter.flush(sync)
302
+ end
303
+
304
+ self
305
+ end
306
+
307
+ # Set the subject of the events fired by the tracker
308
+ #
309
+ Contract Subject => Tracker
310
+ def set_subject(subject)
311
+ @subject = subject
312
+ self
313
+ end
314
+
315
+ # Add a new emitter
316
+ #
317
+ Contract Emitter => Tracker
318
+ def add_emitter(emitter)
319
+ @emitters.push(emitter)
320
+ self
346
321
  end
347
322
 
348
- private :as_collector_uri,
349
- :get_timestamp,
323
+ private :get_timestamp,
350
324
  :build_context,
351
- :http_get,
352
325
  :track,
353
326
  :track_ecommerce_transaction_item
354
327
 
@@ -14,6 +14,6 @@
14
14
  # License:: Apache License Version 2.0
15
15
 
16
16
  module SnowplowTracker
17
- VERSION = '0.2.0'
17
+ VERSION = '0.3.0'
18
18
  TRACKER_VERSION = "rb-#{VERSION}"
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snowplow-tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Dean
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-31 00:00:00.000000000 Z
12
+ date: 2014-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: contracts
@@ -76,10 +76,13 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - LICENSE-2.0.txt
78
78
  - README.md
79
- - lib/snowplow-tracker.rb
79
+ - lib/snowplow-tracker/contracts.rb
80
+ - lib/snowplow-tracker/emitters.rb
80
81
  - lib/snowplow-tracker/payload.rb
82
+ - lib/snowplow-tracker/subject.rb
81
83
  - lib/snowplow-tracker/tracker.rb
82
84
  - lib/snowplow-tracker/version.rb
85
+ - lib/snowplow-tracker.rb
83
86
  homepage: http://github.com/snowplow/snowplow-ruby-tracker
84
87
  licenses:
85
88
  - Apache License 2.0
@@ -100,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
103
  version: '0'
101
104
  requirements: []
102
105
  rubyforge_project:
103
- rubygems_version: 2.2.2
106
+ rubygems_version: 2.1.11
104
107
  signing_key:
105
108
  specification_version: 4
106
109
  summary: Ruby Analytics for Snowplow