snowplow-tracker 0.7.0 → 0.8.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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23047d83eb7b5f22343e668d97e0885fbf1cacf684706b8bb83465e98fc78e40
4
- data.tar.gz: edf65b28b3264412a3c11f2f0e9ee3a440647fbece99228ab450e9a01148b0f5
3
+ metadata.gz: 828096deb0a370f527d14f17e2e48eb1481428b5cdc1b2897235b539be64f327
4
+ data.tar.gz: e0b5b026cfad092a2c4269876bc0b7e5d240ba5ec8b18b67b8a1e97d7c127a93
5
5
  SHA512:
6
- metadata.gz: d996e91a98e1ce69d459dd91655ff052d578e0dfed0c41c69731d1f37b93dfa95ca50e11b82d43df78b599197f8e94b5f5ad6a7fad5f4f8498d886c1dfdeae95
7
- data.tar.gz: 88053e746e569713d537bfbbd75cb61ec4e38bbf19a0e8f36de13d057450fec5ab4f3e5a13715b13df1dc8188791e6e9dc38d9aed27b47bcc99c415d2edc6df5
6
+ metadata.gz: b75d45c5b03f55398ab27a9945d9ddbe91340348d803e8be8d4c74b108f39931cd7a7e17a661a818ffd9e3d81aac71bdf3a8d5486c397881a741bfc5e1b881b0
7
+ data.tar.gz: 650468a842f96ab6951aa54bc374115ee0dc3a466b6f15807c8a0e8fb1e86127b630ee226f8c0ba49b3316ae20d342c24c6211810e2c2eac65791d7f4fa9f478
data/README.md CHANGED
@@ -9,30 +9,28 @@
9
9
 
10
10
  ## Overview
11
11
 
12
- Add analytics to your Ruby and Rails apps and gems with the **[Snowplow][snowplow]** event tracker for **[Ruby][ruby]**.
12
+ Add analytics to your **[Ruby][ruby]** and **[Ruby on Rails][rails]** apps and **[gems][rubygems]** with the **[Snowplow][snowplow]** event tracker for **[Ruby][ruby]**.
13
13
 
14
14
  Snowplow is a scalable open-source platform for rich, high quality, low-latency data collection. It is designed to collect high quality, complete behavioral data for enterprise business.
15
15
 
16
16
  **To find out more, please check out the [Snowplow website][snowplow] and our [documentation][docs].**
17
17
 
18
- With this tracker you can collect event data from your **[Ruby][ruby]** applications, **[Ruby on Rails][rails]** web applications and **[Ruby gems][rubygems]**.
19
-
20
18
  ## Quickstart
21
19
 
22
20
  Add this gem to your Gemfile. It is compatible with Ruby versions 2.1 to 3.0+.
23
21
 
24
22
  ```ruby
25
- gem "snowplow-tracker", "~> 0.7.0"
23
+ gem "snowplow-tracker", "~> 0.8.0"
26
24
  ```
27
25
 
28
26
  See our [demo app][demoapp] for an example of implementing the Ruby tracker in a Rails app.
29
27
 
30
28
  ## Find out more
31
29
 
32
- | Technical Docs | API Docs | Contributing |
30
+ | Snowplow Docs | API Docs | Contributing |
33
31
  | ------------------------------ | ----------------------- | ----------------------------------- |
34
32
  | ![i1][techdocs-image] | ![i1][techdocs-image] | ![i4][contributing-image] |
35
- | **[Technical Docs][techdocs]** | **[API Docs][apidocs]** | **[Contributing](Contributing.md)** |
33
+ | **[Snowplow Docs][techdocs]** | **[API Docs][apidocs]** | **[Contributing](Contributing.md)** |
36
34
 
37
35
  ## Maintainer Quickstart
38
36
 
@@ -47,11 +45,16 @@ The `-v` flag for `docker run` creates a bind mount for the project directory. T
47
45
 
48
46
  Alternatively, test directly by installing Ruby 2.1+ and [Bundler][bundler]. Then run:
49
47
 
50
- ```
48
+ ```bash
51
49
  bundle install
52
50
  rspec
53
51
  ```
54
52
 
53
+ To generate documentation using YARD, make sure the YARD and redcarpet gems are installed locally. Then run:
54
+ ```bash
55
+ yard doc
56
+ ```
57
+
55
58
  ## Contributing
56
59
 
57
60
  Feedback and contributions are welcome - if you have identified a bug, please log an issue on this repo. For all other feedback, discussion or questions please open a thread on our [Discourse forum][discourse].
@@ -72,7 +75,7 @@ limitations under the License.
72
75
  [license-image]: https://img.shields.io/badge/license-Apache--2-blue.svg?style=flat
73
76
  [license]: https://www.apache.org/licenses/LICENSE-2.0
74
77
  [gh-actions]: https://github.com/snowplow/snowplow-ruby-tracker/actions
75
- [gh-actions-image]: https://github.com/snowplow/snowplow-ruby-tracker/workflows/test.yml/badge.svg
78
+ [gh-actions-image]: https://github.com/snowplow/snowplow-ruby-tracker/workflows/Test/badge.svg
76
79
  [tracker-classification]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/tracker-maintenance-classification/
77
80
  [early-release]: https://img.shields.io/static/v1?style=flat&label=Snowplow&message=Early%20Release&color=014477&labelColor=9ba0aa&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAeFBMVEVMaXGXANeYANeXANZbAJmXANeUANSQAM+XANeMAMpaAJhZAJeZANiXANaXANaOAM2WANVnAKWXANZ9ALtmAKVaAJmXANZaAJlXAJZdAJxaAJlZAJdbAJlbAJmQAM+UANKZANhhAJ+EAL+BAL9oAKZnAKVjAKF1ALNBd8J1AAAAKHRSTlMAa1hWXyteBTQJIEwRgUh2JjJon21wcBgNfmc+JlOBQjwezWF2l5dXzkW3/wAAAHpJREFUeNokhQOCA1EAxTL85hi7dXv/E5YPCYBq5DeN4pcqV1XbtW/xTVMIMAZE0cBHEaZhBmIQwCFofeprPUHqjmD/+7peztd62dWQRkvrQayXkn01f/gWp2CrxfjY7rcZ5V7DEMDQgmEozFpZqLUYDsNwOqbnMLwPAJEwCopZxKttAAAAAElFTkSuQmCC
78
81
 
@@ -17,7 +17,6 @@
17
17
  require 'net/https'
18
18
  require 'set'
19
19
  require 'logger'
20
- require 'contracts'
21
20
 
22
21
  module SnowplowTracker
23
22
  # @see Emitter
@@ -38,7 +37,10 @@ module SnowplowTracker
38
37
  # | Buffer size | 1 |
39
38
  # | Path | `/i` |
40
39
  #
41
- # The buffer size is 1 because GET requests can only contain one event.
40
+ # The buffer size is the number of events which will be buffered before they
41
+ # are all sent simultaneously. The process of sending all buffered events is
42
+ # called "flushing". The default buffer size is 1 because GET requests can
43
+ # only contain one event.
42
44
  #
43
45
  # If you choose to use POST requests, the buffer_size defaults to 10, and the
44
46
  # buffered events are all sent together in a single request. The default path
@@ -61,42 +63,15 @@ module SnowplowTracker
61
63
  # require 'logger'
62
64
  # SnowplowTracker::LOGGER.level = Logger::DEBUG
63
65
  class Emitter
64
- include Contracts
65
-
66
- # Contract types
67
-
68
- # @private
69
- CONFIG_HASH = {
70
- path: Maybe[String],
71
- protocol: Maybe[Or['http', 'https']],
72
- port: Maybe[Num],
73
- method: Maybe[Or['get', 'post']],
74
- buffer_size: Maybe[Num],
75
- on_success: Maybe[Func[Num => Any]],
76
- on_failure: Maybe[Func[Num, Hash => Any]],
77
- thread_count: Maybe[Num],
78
- logger: Maybe[Logger]
79
- }
80
-
81
- # @private
82
- STRICT_CONFIG_HASH = And[CONFIG_HASH, ->(x) {
83
- (x.class == Hash) && Set.new(x.keys).subset?(Set.new(CONFIG_HASH.keys))
84
- }]
85
-
86
- # @!group Public constants
87
-
88
66
  # Default Emitter settings
89
67
  DEFAULT_CONFIG = {
90
68
  protocol: 'http',
91
69
  method: 'get'
92
70
  }
93
71
 
94
- # @!endgroup
95
-
96
72
  # @private
97
73
  attr_reader :logger
98
74
 
99
- Contract KeywordArgs[endpoint: String, options: Optional[STRICT_CONFIG_HASH]] => Any
100
75
  # Create a new Emitter instance. The endpoint is required.
101
76
  #
102
77
  # @example Initializing an Emitter with all the possible extra configuration.
@@ -105,7 +80,7 @@ module SnowplowTracker
105
80
  # puts "#{success_count} events sent successfully, #{failures.size} sent unsuccessfully"
106
81
  # end
107
82
  #
108
- # Emitter.new(endpoint: 'collector.example.com',
83
+ # SnowplowTracker::Emitter.new(endpoint: 'collector.example.com',
109
84
  # options: { path: '/my-pipeline/1',
110
85
  # protocol: 'https',
111
86
  # port: 443,
@@ -124,8 +99,8 @@ module SnowplowTracker
124
99
  # | port | The port for the connection | Integer |
125
100
  # | method | 'get' or 'post' | String |
126
101
  # | buffer_size | Number of events to send at once | Integer |
127
- # | on_success | A function to call if events were sent successfully | Function |
128
- # | on_failure | A function to call if events did not send | Function |
102
+ # | on_success | A method to call if events were sent successfully | Method |
103
+ # | on_failure | A method to call if events did not send | Method |
129
104
  # | thread_count | Number of threads to use | Integer |
130
105
  # | logger | Log somewhere other than STDERR | Logger |
131
106
  #
@@ -134,6 +109,13 @@ module SnowplowTracker
134
109
  #
135
110
  # If you choose to use HTTPS, we recommend using port 443.
136
111
  #
112
+ # Only 2xx and 3xx status codes are considered successes.
113
+ #
114
+ # The `on_success` callback should accept one argument: the number of
115
+ # requests sent this way. The `on_failure` callback should accept two
116
+ # arguments: the number of successfully sent events, and an array containing
117
+ # the unsuccessful events.
118
+ #
137
119
  # @param endpoint [String] the endpoint to send the events to
138
120
  # @param options [Hash] allowed configuration options
139
121
  #
@@ -153,7 +135,6 @@ module SnowplowTracker
153
135
  logger.info("#{self.class} initialized with endpoint #{@collector_uri}")
154
136
  end
155
137
 
156
- Contract Hash => Num
157
138
  # Creates the `@buffer_size` variable during initialization. Unless
158
139
  # otherwise defined, it's 1 for Emitters using GET and 10 for Emitters using
159
140
  # POST requests.
@@ -164,7 +145,6 @@ module SnowplowTracker
164
145
  config[:method] == 'get' ? 1 : 10
165
146
  end
166
147
 
167
- Contract Hash => String
168
148
  # Creates the `@path` variable during initialization. Allows a non-standard
169
149
  # path to be provided.
170
150
  # @private
@@ -174,9 +154,6 @@ module SnowplowTracker
174
154
  config[:method] == 'get' ? '/i' : '/com.snowplowanalytics.snowplow/tp2'
175
155
  end
176
156
 
177
- # Build the collector URI from the configuration hash
178
- #
179
- Contract String, String, Maybe[Num], String => String
180
157
  # Creates the `@collector_uri` variable during initialization.
181
158
  # The default is "http://{endpoint}/i".
182
159
  # @private
@@ -186,7 +163,6 @@ module SnowplowTracker
186
163
  "#{protocol}://#{endpoint}#{port_string}#{path}"
187
164
  end
188
165
 
189
- Contract Hash => nil
190
166
  # Add an event to the buffer and flush it if maximum size has been reached.
191
167
  # This method is not required for standard Ruby tracker usage. A {Tracker}
192
168
  # privately calls this method once the event payload is ready to send.
@@ -197,6 +173,9 @@ module SnowplowTracker
197
173
  # to send. You could use {#input} as part of your callback to immediately
198
174
  # retry the failed event.
199
175
  #
176
+ # The `on_failure` callback should accept two arguments: the number of
177
+ # successfully sent events, and an array containing the unsuccessful events.
178
+ #
200
179
  # @example A possible `on_failure` method using `#input`
201
180
  # def retry_on_failure(failed_event_count, failed_events)
202
181
  # # possible backoff-and-retry timeout here
@@ -216,7 +195,6 @@ module SnowplowTracker
216
195
  nil
217
196
  end
218
197
 
219
- Contract Bool => nil
220
198
  # Flush the Emitter, forcing it to send all the events in its
221
199
  # buffer, even if the buffer is not full. {Emitter} objects, unlike
222
200
  # {AsyncEmitter}s, can only `flush` synchronously. A {Tracker} can manually flush all
@@ -237,7 +215,6 @@ module SnowplowTracker
237
215
  nil
238
216
  end
239
217
 
240
- Contract ArrayOf[Hash] => nil
241
218
  # Send all events in the buffer to the collector
242
219
  # @private
243
220
  def send_requests(events)
@@ -262,7 +239,6 @@ module SnowplowTracker
262
239
  nil
263
240
  end
264
241
 
265
- Contract ArrayOf[Hash] => nil
266
242
  # Part of {#send_requests}.
267
243
  # @private
268
244
  def send_requests_with_post(events)
@@ -286,7 +262,6 @@ module SnowplowTracker
286
262
  nil
287
263
  end
288
264
 
289
- Contract ArrayOf[Hash] => nil
290
265
  # Part of {#send_requests}.
291
266
  # @private
292
267
  def send_requests_with_get(events)
@@ -307,7 +282,6 @@ module SnowplowTracker
307
282
  nil
308
283
  end
309
284
 
310
- Contract Hash => Bool
311
285
  # Part of {#send_requests_with_get}.
312
286
  # @private
313
287
  def process_get_event(event)
@@ -321,7 +295,6 @@ module SnowplowTracker
321
295
  get_succeeded
322
296
  end
323
297
 
324
- Contract Hash => ->(x) { x.is_a? Net::HTTPResponse }
325
298
  # Part of {#process_get_event}. This sends a GET request.
326
299
  # @private
327
300
  def http_get(payload)
@@ -339,7 +312,6 @@ module SnowplowTracker
339
312
  response
340
313
  end
341
314
 
342
- Contract Hash => ->(x) { x.is_a? Net::HTTPResponse }
343
315
  # Part of {#send_requests_with_post}. This sends a POST request.
344
316
  # @private
345
317
  def http_post(payload)
@@ -359,7 +331,6 @@ module SnowplowTracker
359
331
  response
360
332
  end
361
333
 
362
- Contract String => Bool
363
334
  # Check if the response is good.
364
335
  # Only 2xx and 3xx status codes are considered successes.
365
336
  # @private
@@ -381,7 +352,6 @@ module SnowplowTracker
381
352
  # @see Emitter
382
353
  # @api public
383
354
  class AsyncEmitter < Emitter
384
- Contract KeywordArgs[endpoint: String, options: Optional[STRICT_CONFIG_HASH]] => Any
385
355
  # Create a new AsyncEmitter object. The endpoint is required.
386
356
  #
387
357
  # @example Initializing an AsyncEmitter with all the possible extra configuration.
@@ -390,7 +360,7 @@ module SnowplowTracker
390
360
  # puts "#{success_count} events sent successfully, #{failures.size} sent unsuccessfully"
391
361
  # end
392
362
  #
393
- # Emitter.new(endpoint: 'collector.example.com',
363
+ # SnowplowTracker::Emitter.new(endpoint: 'collector.example.com',
394
364
  # options: { path: '/my-pipeline/1',
395
365
  # protocol: 'https',
396
366
  # port: 443,
@@ -420,6 +390,13 @@ module SnowplowTracker
420
390
  #
421
391
  # If you choose to use HTTPS, we recommend using port 443.
422
392
  #
393
+ # Only 2xx and 3xx status codes are considered successes.
394
+ #
395
+ # The `on_success` callback should accept one argument: the number of
396
+ # requests sent this way. The `on_failure` callback should accept two
397
+ # arguments: the number of successfully sent events, and an array containing
398
+ # the unsuccessful events.
399
+ #
423
400
  # @note if you test the AsyncEmitter by using a short script to send an
424
401
  # event, you may find that the event fails to send. This is because the
425
402
  # process exits before the flushing thread is finished. You can get round
@@ -14,8 +14,6 @@
14
14
  # License:: Apache License Version 2.0
15
15
 
16
16
 
17
- require 'contracts'
18
-
19
17
  module SnowplowTracker
20
18
  # If the Ruby tracker is incorporated into a website server, the events
21
19
  # tracked will describe user activity on specific webpages. Knowing on which
@@ -33,18 +31,15 @@ module SnowplowTracker
33
31
  # @note For {Tracker#track_page_view}, properties set in the Page object will
34
32
  # override those properties given as arguments.
35
33
  class Page
36
- include Contracts
37
-
38
34
  # @return [Hash] the stored page properties
39
35
  attr_reader :details
40
36
 
41
- Contract KeywordArgs[page_url: Maybe[String], page_title: Maybe[String], referrer: Maybe[String]] => Any
42
37
  # Create a Page object for attaching page properties to events.
43
38
  #
44
39
  # Page properties will directly populate the event's `page_url`, `page_title` and `referrer` parameters.
45
40
  #
46
41
  # @example Creating a Page
47
- # Page.new(page_url: 'http://www.example.com/second-page',
42
+ # SnowplowTracker::Page.new(page_url: 'http://www.example.com/second-page',
48
43
  # page_title: 'Example title',
49
44
  # referrer: 'http://www.example.com/first-page')
50
45
  #
@@ -17,7 +17,6 @@
17
17
  require 'base64'
18
18
  require 'json'
19
19
  require 'net/http'
20
- require 'contracts'
21
20
 
22
21
  module SnowplowTracker
23
22
  # @private
@@ -26,28 +25,22 @@ module SnowplowTracker
26
25
  # hash. These properties form the raw event, after the completed hash is
27
26
  # given to the Emitter.
28
27
  class Payload
29
- include Contracts
30
-
31
28
  attr_reader :data
32
29
 
33
- Contract nil => Any
34
30
  def initialize
35
31
  @data = {}
36
32
  end
37
33
 
38
- Contract String, Or[String, Bool, Num, nil] => Or[String, Bool, Num, nil]
39
34
  # Add a single name-value pair to @data.
40
35
  def add(name, value)
41
36
  @data[name] = value if (value != '') && !value.nil?
42
37
  end
43
38
 
44
- Contract Hash => Hash
45
39
  # Add each name-value pair in a hash to @data.
46
40
  def add_hash(hash)
47
41
  hash.each { |key, value| add(key, value) }
48
42
  end
49
43
 
50
- Contract Maybe[Hash], Bool, String, String => Maybe[String]
51
44
  # Stringify a JSON and add it to @data.
52
45
  #
53
46
  # In practice, the JSON provided will be a SelfDescribingJson. This method
@@ -77,7 +77,7 @@ module SnowplowTracker
77
77
  # # Creating the SelfDescribingJson
78
78
  # schema_name = "iglu:com.snowplowanalytics/ad_click/jsonschema/1-0-0"
79
79
  # event_data = { bannerId: "4acd518feb82" }
80
- # SelfDescribingJson.new(schema_name, event_data)
80
+ # SnowplowTracker::SelfDescribingJson.new(schema_name, event_data)
81
81
  #
82
82
  # # The self-describing JSON that will be sent (stringified) with the event
83
83
  # {
@@ -14,8 +14,6 @@
14
14
  # License:: Apache License Version 2.0
15
15
 
16
16
 
17
- require 'contracts'
18
-
19
17
  module SnowplowTracker
20
18
  # Subject objects store information about the user associated with the event,
21
19
  # such as their `user_id`, what type of device they used, or what size screen
@@ -68,7 +66,7 @@ module SnowplowTracker
68
66
  #
69
67
  # Since many of the Subject parameters describe the user, different Subject
70
68
  # properties may often be desired for each event, if there are multiple users.
71
- # This can be achieved in one of two ways:
69
+ # This can be achieved in one of three ways:
72
70
  #
73
71
  # 1. the properties of the Tracker-associated Subject can be overriden by the
74
72
  # properties of an event-specific Subject. A Subject can be added to any
@@ -76,19 +74,22 @@ module SnowplowTracker
76
74
  # set the platform for the event Subject if you're not using `srv`.
77
75
  # 2. the Tracker-associated Subject can be swapped for another Subject, using
78
76
  # the Tracker method {Tracker#set_subject}.
77
+ # 3. the properties of the Tracker-associated Subject can be changed before
78
+ # every `#track_x_event`, by calling the Subject methods via the Tracker.
79
79
  #
80
80
  # @see Tracker#set_subject
81
81
  # @see
82
82
  # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol
83
83
  # the Snowplow Tracker Protocol
84
+ # @see
85
+ # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/enriching-your-events/
86
+ # the Snowplow docs page about adding context and other extra data to events
84
87
  # @api public
85
88
  #
86
89
  # @note All the Subject instance methods return the Subject object, allowing
87
90
  # method chaining, e.g.
88
- # `Subject.new.set_timezone('Europe/London').set_user_id('12345')`
91
+ # `SnowplowTracker::Subject.new.set_timezone('Europe/London').set_user_id('12345')`
89
92
  class Subject
90
- include Contracts
91
-
92
93
  # @private
93
94
  DEFAULT_PLATFORM = 'srv'
94
95
 
@@ -108,22 +109,22 @@ module SnowplowTracker
108
109
 
109
110
  # Access the Subject parameters
110
111
  # @example
111
- # Subject.new.set_user_id('12345').details
112
+ # SnowplowTracker::Subject.new.set_user_id('12345').details
112
113
  # => {"p"=>"srv", "uid"=>"12345"}
113
114
  # @api public
114
115
  attr_reader :details
115
116
 
116
- Contract None => Any
117
117
  # @api public
118
118
  def initialize
119
119
  @details = { 'p' => DEFAULT_PLATFORM }
120
120
  end
121
121
 
122
- Contract String => Subject
123
122
  # Set the platform to one of the supported platform values.
124
123
  # @note Value is sent in the event as `p` (raw event) or `platform` (processed event).
125
124
  # @see Subject::SUPPORTED_PLATFORMS
126
125
  # @param [String] platform a valid platform choice
126
+ # @example
127
+ # subject.set_platform('app')
127
128
  # @return self
128
129
  # @api public
129
130
  def set_platform(platform)
@@ -133,7 +134,6 @@ module SnowplowTracker
133
134
  self
134
135
  end
135
136
 
136
- Contract String => Subject
137
137
  # Set the unique business-defined user ID for a user.
138
138
  # @note Value is sent in the event as `uid` (raw event) or `user_id` (processed event).
139
139
  # For example, an email address.
@@ -152,45 +152,49 @@ module SnowplowTracker
152
152
  self
153
153
  end
154
154
 
155
- Contract Num => Subject
156
155
  # Set a business-defined fingerprint for a user.
157
156
  # @note Value is sent in the event as `fp` (raw event) or `user_fingerprint` (processed event).
158
157
  # @param [Num] fingerprint a user fingerprint
159
158
  # @return self
159
+ # @example
160
+ # subject.set_fingerprint(4048966212)
160
161
  # @api public
161
162
  def set_fingerprint(fingerprint)
162
163
  @details['fp'] = fingerprint
163
164
  self
164
165
  end
165
166
 
166
- Contract KeywordArgs[width: Num, height: Num] => Subject
167
167
  # Set the device screen resolution.
168
168
  # @note Value is sent in the event as `res` (raw event) or `dvce_screenheight` and `dvce_screenwidth` (processed event).
169
- # @param [Num] width the screen width, in pixels (must be a positive integer)
170
- # @param [Num] height the screen height, in pixels (must be a positive integer)
169
+ # @param [Integer] width the screen width, in pixels (must be a positive integer)
170
+ # @param [Integer] height the screen height, in pixels (must be a positive integer)
171
171
  # @return self
172
+ # @example
173
+ # subject.set_screen_resolution(width: 2880, height: 1800)
172
174
  # @api public
173
175
  def set_screen_resolution(width:, height:)
174
176
  @details['res'] = "#{width}x#{height}"
175
177
  self
176
178
  end
177
179
 
178
- Contract KeywordArgs[width: Num, height: Num] => Subject
179
180
  # Set the dimensions of the current viewport.
180
181
  # @note Value is sent in the event as `vp` (raw event) or `br_viewwidth` and `br_viewheight` (processed event).
181
- # @param [Num] width the viewport width, in pixels (must be a positive integer)
182
- # @param [Num] height the viewport height, in pixels (must be a positive integer)
182
+ # @param [Integer] width the viewport width, in pixels (must be a positive integer)
183
+ # @param [Integer] height the viewport height, in pixels (must be a positive integer)
183
184
  # @return self
185
+ # @example
186
+ # subject.set_viewport(width: 1440, height: 762)
184
187
  # @api public
185
188
  def set_viewport(width:, height:)
186
189
  @details['vp'] = "#{width}x#{height}"
187
190
  self
188
191
  end
189
192
 
190
- Contract Num => Subject
191
- # Set the color depth of the device, in bits per pixel.
193
+ # Set the color depth of the browser, in bits per pixel.
192
194
  # @note Value is sent in the event as `cd` (raw event) or `br_colordepth` (processed event).
193
195
  # @param [Num] depth the colour depth
196
+ # @example
197
+ # subject.set_color_depth(24)
194
198
  # @return self
195
199
  # @api public
196
200
  def set_color_depth(depth)
@@ -198,7 +202,6 @@ module SnowplowTracker
198
202
  self
199
203
  end
200
204
 
201
- Contract String => Subject
202
205
  # Set the timezone to that of the user's OS.
203
206
  # @note Value is sent in the event as `tz` (raw event) or `os_timezone` (processed event).
204
207
  # @example
@@ -211,7 +214,6 @@ module SnowplowTracker
211
214
  self
212
215
  end
213
216
 
214
- Contract String => Subject
215
217
  # Set the language.
216
218
  # @note Value is sent in the event as `lang` (raw event) or `br_lang` (processed event).
217
219
  # @example Setting the language to Spanish
@@ -224,7 +226,6 @@ module SnowplowTracker
224
226
  self
225
227
  end
226
228
 
227
- Contract String => Subject
228
229
  # Set the domain user ID.
229
230
  # @note Value is sent in the event as `duid` (raw event) or `domain_userid` (processed event).
230
231
  # @see Subject#set_network_user_id
@@ -260,7 +261,6 @@ module SnowplowTracker
260
261
  self
261
262
  end
262
263
 
263
- Contract String => Subject
264
264
  # Set the domain session ID.
265
265
  # @note Value is sent in the event as `sid` (raw event) or `domain_sessionid` (processed event).
266
266
  # @see Subject#set_network_user_id
@@ -283,7 +283,6 @@ module SnowplowTracker
283
283
  self
284
284
  end
285
285
 
286
- Contract Num => Subject
287
286
  # Set the domain session index.
288
287
  # @note Value is sent in the event as `vid` (raw event) or `domain_sessionidx` (processed event).
289
288
  # @see Subject#set_network_user_id
@@ -307,18 +306,18 @@ module SnowplowTracker
307
306
  self
308
307
  end
309
308
 
310
- Contract String => Subject
311
309
  # Set the user's IP address.
312
310
  # @note Value is sent in the event as `ip` (raw event) or `user_ipaddress` (processed event).
313
311
  # @param [String] ip the IP address
314
312
  # @return self
313
+ # @example
314
+ # subject.set_ip_address('37.157.33.178')
315
315
  # @api public
316
316
  def set_ip_address(ip)
317
317
  @details['ip'] = ip
318
318
  self
319
319
  end
320
320
 
321
- Contract String => Subject
322
321
  # Set the browser user agent.
323
322
  # @note Value is sent in the event as `ua` (raw event) or `useragent` (processed event).
324
323
  # @example
@@ -331,7 +330,6 @@ module SnowplowTracker
331
330
  self
332
331
  end
333
332
 
334
- Contract String => Subject
335
333
  # Set the network user ID.
336
334
  # @note Value is sent in the event as `tnuid` (raw event) and `network_userid` (processed event).
337
335
  # @see Subject#set_domain_user_id
@@ -38,41 +38,39 @@ module SnowplowTracker
38
38
  # DeviceTimestamp by the Tracker, and will still be recorded as `dtm` in
39
39
  # the event.
40
40
  # 2. Manually create a DeviceTimestamp (e.g.
41
- # `DeviceTimestamp.new(1633596554978)`), and provide this to the
41
+ # `SnowplowTracker::DeviceTimestamp.new(1633596554978)`), and provide this to the
42
42
  # `#track_x_event` method. This will still be recorded as `dtm` in the
43
43
  # event.
44
44
  # 3. Provide a TrueTimestamp object to the `track_x_event` method (e.g.
45
- # `TrueTimestamp.new(1633596554978)`). This will result in a `ttm` field in
45
+ # `SnowplowTracker::TrueTimestamp.new(1633596554978)`). This will result in a `ttm` field in
46
46
  # the event.
47
47
  #
48
48
  # The timestamps that are added to the event once it has been emitted are not
49
49
  # the responsibility of this class. The collector receives the event and adds a
50
50
  # `collector_tstamp`. A later part of the pipeline adds the `etl_tstamp` when
51
- # the event enrichment has finished. A `derived_tstamp` is also calculated and
52
- # added to the event, which represents how long it took the event to be
53
- # processed. This is calculated by `collector_tstamp - (dvce_sent_tstamp -
54
- # dvce_created_tstamp)`.
51
+ # the event enrichment has finished.
52
+ #
53
+ # When DeviceTimestamp is used, a `derived_tstamp` is also calculated and
54
+ # added to the event. This timestamp attempts to take latency and possible
55
+ # inaccuracy of the device clock into account. It is calculated by
56
+ # `collector_tstamp - (dvce_sent_tstamp - dvce_created_tstamp)`. When
57
+ # TrueTimestamp is used, the `derived_stamp` will be the same as
58
+ # `true_tstamp`.
55
59
  #
56
60
  # @see
57
61
  # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol
58
62
  # the Snowplow Tracker Protocol
63
+ # @see
64
+ # https://discourse.snowplowanalytics.com/t/which-timestamp-is-the-best-to-see-when-an-event-occurred/538
65
+ # A Discourse forums post explaining timestamps
59
66
  # @api public
60
67
  class Timestamp
61
- include Contracts
62
-
63
68
  # @private
64
69
  attr_reader :type
65
70
 
66
71
  # @private
67
72
  attr_reader :value
68
73
 
69
- # @private
70
- # Contract type
71
- TIMESTAMP = ->(x) {
72
- return false unless x.is_a? Integer
73
- x.to_s.length == 13
74
- }
75
-
76
74
  # @private
77
75
  def initialize(type, value)
78
76
  @type = type
@@ -92,10 +90,9 @@ module SnowplowTracker
92
90
  # it is, namely `ttm`. This raw event `ttm` field will be processed into
93
91
  # `true_tstamp` in the completed event.
94
92
  class TrueTimestamp < Timestamp
95
- Contract TIMESTAMP => Any
96
93
  # @param [Num] value timestamp in milliseconds since the Unix epoch
97
94
  # @example
98
- # TrueTimestamp.new(1633596346786)
95
+ # SnowplowTracker::TrueTimestamp.new(1633596346786)
99
96
  def initialize(value)
100
97
  super 'ttm', value
101
98
  end
@@ -107,10 +104,9 @@ module SnowplowTracker
107
104
  # it is, namely `dtm`. This raw event `dtm` field will be processed into
108
105
  # `dvce_created_tstamp` in the completed event.
109
106
  class DeviceTimestamp < Timestamp
110
- Contract TIMESTAMP => Any
111
107
  # @param [Num] value timestamp in milliseconds since the Unix epoch
112
108
  # @example
113
- # DeviceTimestamp.new(1633596346786)
109
+ # SnowplowTracker::DeviceTimestamp.new(1633596346786)
114
110
  def initialize(value)
115
111
  super 'dtm', value
116
112
  end
@@ -14,7 +14,6 @@
14
14
  # License:: Apache License Version 2.0
15
15
 
16
16
 
17
- require 'contracts'
18
17
  require 'securerandom'
19
18
  require 'set'
20
19
 
@@ -118,62 +117,16 @@ module SnowplowTracker
118
117
  # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol
119
118
  # the Snowplow Tracker Protocol
120
119
  # @see
120
+ # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/tracking-events/
121
+ # the Snowplow docs page about tracking events
122
+ # @see
123
+ # https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/enriching-your-events/
124
+ # the Snowplow docs page about adding context and other extra data to events
125
+ # @see
121
126
  # https://docs.snowplowanalytics.com/docs/understanding-tracking-design/introduction-to-tracking-design/
122
127
  # introduction to Snowplow tracking design
123
128
  # @api public
124
129
  class Tracker
125
- include Contracts
126
-
127
- # Contract types
128
-
129
- # @private
130
- EMITTER_INPUT = Or[->(x) { x.is_a? Emitter }, ArrayOf[->(x) { x.is_a? Emitter }]]
131
-
132
- # @private
133
- REQUIRED_TRANSACTION_KEYS = Set.new(%w[order_id total_value])
134
- # @private
135
- RECOGNISED_TRANSACTION_KEYS = Set.new(%w[
136
- order_id total_value affiliation tax_value
137
- shipping city state country currency
138
- ])
139
-
140
- # @private
141
- TRANSACTION = ->(x) {
142
- return false unless x.class == Hash
143
- transaction_keys = Set.new(x.keys.map(&:to_s))
144
- REQUIRED_TRANSACTION_KEYS.subset?(transaction_keys) &&
145
- transaction_keys.subset?(RECOGNISED_TRANSACTION_KEYS)
146
- }
147
- # @private
148
- REQUIRED_ITEM_KEYS = Set.new(%w[sku price quantity])
149
- # @private
150
- RECOGNISED_ITEM_KEYS = Set.new(%w[sku price quantity name category context])
151
-
152
- # @private
153
- ITEM = ->(x) {
154
- return false unless x.class == Hash
155
- item_keys = Set.new(x.keys.map(&:to_s))
156
- REQUIRED_ITEM_KEYS.subset?(item_keys) &&
157
- item_keys.subset?(RECOGNISED_ITEM_KEYS)
158
- }
159
- # @private
160
- REQUIRED_AUGMENTED_ITEM_KEYS = Set.new(%w[sku price quantity tstamp order_id])
161
- # @private
162
- RECOGNISED_AUGMENTED_ITEM_KEYS = Set.new(%w[sku price quantity name category context tstamp order_id currency])
163
-
164
- # @private
165
- AUGMENTED_ITEM = ->(x) {
166
- return false unless x.class == Hash
167
- augmented_item_keys = Set.new(x.keys)
168
- REQUIRED_AUGMENTED_ITEM_KEYS.subset?(augmented_item_keys) &&
169
- augmented_item_keys.subset?(RECOGNISED_AUGMENTED_ITEM_KEYS)
170
- }
171
-
172
- # @private
173
- CONTEXTS_INPUT = ArrayOf[SelfDescribingJson]
174
-
175
- # Other constants
176
-
177
130
  # @!group Public constants
178
131
 
179
132
  # SelfDescribingJson objects are sent encoded by default
@@ -192,8 +145,6 @@ module SnowplowTracker
192
145
 
193
146
  # @!endgroup
194
147
 
195
- Contract KeywordArgs[emitters: EMITTER_INPUT, subject: Maybe[Subject], namespace: Maybe[String],
196
- app_id: Maybe[String], encode_base64: Optional[Bool]] => Any
197
148
  # Create a new Tracker. `emitters` is the only strictly required parameter.
198
149
  #
199
150
  # @param emitters [Emitter, Array<Emitter>] one or more Emitter objects
@@ -202,14 +153,18 @@ module SnowplowTracker
202
153
  # @param app_id [String] the app ID
203
154
  # @param encode_base64 [Bool] whether JSONs will be base64-encoded or not
204
155
  # @example Initializing a Tracker with all possible options
205
- # Tracker.new(
206
- # emitters: Emitter.new('collector.example.com'),
207
- # subject: Subject.new,
156
+ # SnowplowTracker::Tracker.new(
157
+ # emitters: SnowplowTracker::Emitter.new(endpoint: 'collector.example.com'),
158
+ # subject: SnowplowTracker::Subject.new,
208
159
  # namespace: 'tracker_no_encode',
209
160
  # app_id: 'rails_main',
210
161
  # encode_base64: false
211
162
  # )
212
163
  # @api public
164
+ #
165
+ # @note All the Tracker instance methods return the Tracker object, allowing
166
+ # method chaining, e.g.
167
+ # `SnowplowTracker::Tracker.new.set_user_id('12345').track_page_view(page_url: 'www.example.com`
213
168
  def initialize(emitters:, subject: nil, namespace: nil, app_id: nil, encode_base64: DEFAULT_ENCODE_BASE64)
214
169
  @emitters = Array(emitters)
215
170
  @subject = if subject.nil?
@@ -269,14 +224,12 @@ module SnowplowTracker
269
224
  end
270
225
  end
271
226
 
272
- Contract nil => String
273
227
  # Generates a type-4 UUID to identify this event
274
228
  # @private
275
229
  def event_id
276
230
  SecureRandom.uuid
277
231
  end
278
232
 
279
- Contract CONTEXTS_INPUT => Hash
280
233
  # Builds a single self-describing JSON from an array of custom contexts
281
234
  # @private
282
235
  def build_context(context)
@@ -286,7 +239,6 @@ module SnowplowTracker
286
239
  ).to_json
287
240
  end
288
241
 
289
- Contract Payload => nil
290
242
  # Sends the payload hash as a request to the Emitter(s)
291
243
  # @private
292
244
  def track(payload)
@@ -295,7 +247,6 @@ module SnowplowTracker
295
247
  nil
296
248
  end
297
249
 
298
- Contract Or[Timestamp, Num, nil] => Timestamp
299
250
  # Ensures that either a DeviceTimestamp or TrueTimestamp is associated with
300
251
  # every event.
301
252
  # @private
@@ -305,7 +256,6 @@ module SnowplowTracker
305
256
  tstamp
306
257
  end
307
258
 
308
- Contract Payload, Maybe[CONTEXTS_INPUT], Timestamp, Maybe[Subject], Maybe[Page] => nil
309
259
  # Attaches the more generic fields to the event payload. This includes
310
260
  # context, Subject, and Page if they are present. The timestamp is added, as
311
261
  # well as all fields from `@settings`.
@@ -329,10 +279,11 @@ module SnowplowTracker
329
279
  nil
330
280
  end
331
281
 
332
- Contract KeywordArgs[page_url: String, page_title: Maybe[String], referrer: Maybe[String],
333
- context: Maybe[CONTEXTS_INPUT], tstamp: Or[Timestamp, Num, nil],
334
- subject: Maybe[Subject], page: Maybe[Page]] => Tracker
335
282
  # Track a visit to a page.
283
+ # @example
284
+ # SnowplowTracker::Tracker.new.track_page_view(page_url: 'www.example.com',
285
+ # page_title: 'example',
286
+ # referrer: 'www.referrer.com')
336
287
  #
337
288
  # @param page_url [String] the URL of the page
338
289
  # @param page_title [String] the page title
@@ -359,9 +310,6 @@ module SnowplowTracker
359
310
  self
360
311
  end
361
312
 
362
- Contract KeywordArgs[transaction: TRANSACTION, items: ArrayOf[ITEM],
363
- context: Maybe[CONTEXTS_INPUT], tstamp: Or[Timestamp, Num, nil],
364
- subject: Maybe[Subject], page: Maybe[Page]] => Tracker
365
313
  # Track an eCommerce transaction, and all the items in it.
366
314
  #
367
315
  # This method is unique in sending multiple events: one `transaction` event,
@@ -482,7 +430,6 @@ module SnowplowTracker
482
430
  hash.keys.each { |key| hash[key.to_s] = hash.delete key }
483
431
  end
484
432
 
485
- Contract AUGMENTED_ITEM, Maybe[Subject], Maybe[Page] => self
486
433
  # Track a single item within an ecommerce transaction.
487
434
  # @private
488
435
  def track_ecommerce_transaction_item(details, subject, page)
@@ -502,10 +449,6 @@ module SnowplowTracker
502
449
  self
503
450
  end
504
451
 
505
- Contract KeywordArgs[category: String, action: String, label: Maybe[String],
506
- property: Maybe[String], value: Maybe[Num],
507
- context: Maybe[CONTEXTS_INPUT], tstamp: Or[Timestamp, Num, nil],
508
- subject: Maybe[Subject], page: Maybe[Page]] => Tracker
509
452
  # Track a structured event. `category` and `action` are required.
510
453
  #
511
454
  # This event type can be used to track many types of user activity, as it is
@@ -516,6 +459,15 @@ module SnowplowTracker
516
459
  # For fully customizable event tracking, we recommend you use
517
460
  # self-describing events.
518
461
  #
462
+ # @example
463
+ # SnowplowTracker::Tracker.new.track_struct_event(
464
+ # category: 'shop',
465
+ # action: 'add-to-basket',
466
+ # property: 'pcs',
467
+ # value: 2
468
+ # )
469
+ #
470
+ #
519
471
  # @see #track_self_describing_event
520
472
  #
521
473
  # @param category [String] the event category
@@ -547,9 +499,6 @@ module SnowplowTracker
547
499
  self
548
500
  end
549
501
 
550
- Contract KeywordArgs[name: Maybe[String], id: Maybe[String],
551
- context: Maybe[CONTEXTS_INPUT], tstamp: Or[Timestamp, Num, nil],
552
- subject: Maybe[Subject], page: Maybe[Page]] => Tracker
553
502
  # Track a screen view event. Note that while the `name` and `id` parameters
554
503
  # are both optional, you must provided at least one of them to create a
555
504
  # valid event.
@@ -560,6 +509,11 @@ module SnowplowTracker
560
509
  # "iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0", and
561
510
  # the data field will contain the name and/or ID.
562
511
  #
512
+ # @example
513
+ # SnowplowTracker::Tracker.new.track_screen_view(name: 'HUD > Save Game',
514
+ # id: 'screen23')
515
+ #
516
+ #
563
517
  # @see #track_page_view
564
518
  # @see #track_self_describing_event
565
519
  #
@@ -583,9 +537,6 @@ module SnowplowTracker
583
537
  self
584
538
  end
585
539
 
586
- Contract KeywordArgs[event_json: SelfDescribingJson, context: Maybe[CONTEXTS_INPUT],
587
- tstamp: Or[Timestamp, Num, nil], subject: Maybe[Subject],
588
- page: Maybe[Page]] => Tracker
589
540
  # Track a self-describing event. These are custom events based on
590
541
  # {SelfDescribingJson}, i.e. a JSON schema and a defined set of properties.
591
542
  #
@@ -595,6 +546,20 @@ module SnowplowTracker
595
546
  # This method creates an `unstruct` event type. It is actually an alias for
596
547
  # {#track_unstruct_event}, which is depreciated due to its unhelpful name.
597
548
  #
549
+ # @example
550
+ # self_desc_json = SnowplowTracker::SelfDescribingJson.new(
551
+ # "iglu:com.example_company/save_game/jsonschema/1-0-2",
552
+ # {
553
+ # "saveId" => "4321",
554
+ # "level" => 23,
555
+ # "difficultyLevel" => "HARD",
556
+ # "dlContent" => true
557
+ # }
558
+ # )
559
+ #
560
+ # SnowplowTracker::Tracker.new.track_self_describing_event(event_json: self_desc_json)
561
+ #
562
+ #
598
563
  # @param event_json [SelfDescribingJson] a SelfDescribingJson object
599
564
  # @param context [Array<SelfDescribingJson>] an array of SelfDescribingJson objects
600
565
  # @param tstamp [DeviceTimestamp, TrueTimestamp, Num] override the default DeviceTimestamp of the event
@@ -607,9 +572,6 @@ module SnowplowTracker
607
572
  tstamp: tstamp, subject: subject, page: page)
608
573
  end
609
574
 
610
- Contract KeywordArgs[event_json: SelfDescribingJson, context: Maybe[CONTEXTS_INPUT],
611
- tstamp: Or[Timestamp, Num, nil], subject: Maybe[Subject],
612
- page: Maybe[Page]] => Tracker
613
575
  # @deprecated Use {#track_self_describing_event} instead.
614
576
  #
615
577
  # @api public
@@ -628,7 +590,6 @@ module SnowplowTracker
628
590
  self
629
591
  end
630
592
 
631
- Contract KeywordArgs[async: Optional[Bool]] => Tracker
632
593
  # Manually flush all events stored in all Tracker-associated Emitters. By
633
594
  # default, this happens synchronously. {Emitter}s can only send events
634
595
  # synchronously, while {AsyncEmitter}s can send either synchronously or
@@ -645,7 +606,6 @@ module SnowplowTracker
645
606
  self
646
607
  end
647
608
 
648
- Contract Subject => Tracker
649
609
  # Replace the existing Tracker-associated Subject with the provided one. All
650
610
  # subsequent events will have the properties of the new Subject, unless they
651
611
  # are overriden by event-specific Subject parameters.
@@ -658,7 +618,6 @@ module SnowplowTracker
658
618
  self
659
619
  end
660
620
 
661
- Contract Emitter => Tracker
662
621
  # Add a new Emitter to the internal array of Tracker-associated Emitters.
663
622
  #
664
623
  # @param emitter [Emitter] an Emitter object
@@ -24,13 +24,6 @@
24
24
  # see an example of how to incorporate the Snowplow Ruby tracker in Ruby on
25
25
  # Rails app.
26
26
  #
27
- # # Type checking
28
- #
29
- # This gem uses the [Contracts](https://github.com/egonSchiele/contracts.ruby)
30
- # gem for typechecking. This cannot be disabled. The {Tracker} `track_x_event`
31
- # methods expect arguments of a certain type. If a check fails, a runtime error
32
- # is thrown.
33
- #
34
27
  # @see https://github.com/snowplow/snowplow-ruby-tracker
35
28
  # Ruby tracker on Github
36
29
  # @see https://github.com/snowplow-incubator/snowplow-ruby-tracker-examples
@@ -41,7 +34,7 @@
41
34
  # @api public
42
35
  module SnowplowTracker
43
36
  # The version of Ruby Snowplow tracker you are using
44
- VERSION = '0.7.0'
37
+ VERSION = '0.8.0'
45
38
 
46
39
  # All events from this tracker will have this string
47
40
  TRACKER_VERSION = "rb-#{VERSION}"
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snowplow-tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Snowplow Analytics Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-14 00:00:00.000000000 Z
11
+ date: 2021-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: contracts
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.7'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '0.17'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '0.7'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '0.17'
33
13
  - !ruby/object:Gem::Dependency
34
14
  name: rspec
35
15
  requirement: !ruby/object:Gem::Requirement