analytics-ruby 2.2.6 → 2.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 472dcf42eeb6b9d83166a526ebeb81bfbbdc74a429511776fedac53ae585da27
4
- data.tar.gz: 70d5bfbf53332c3899cb4cc0071a068c25da7fabee8e934ced0d335bbb08c45f
3
+ metadata.gz: 6c8742471c22e19783a69dee3403ddbd1ac2785b7bbd9608840432e34f4d50a5
4
+ data.tar.gz: dad6dfe750ebf0746e2228cd29551afc23e4ce38d40c7df00184994e6d16db8b
5
5
  SHA512:
6
- metadata.gz: 112f00cdfb0e27ab41ae0c74ebe76d8fba6777acd71ec0a46fc6576948f65a096668c59354393ef600f961631f6cf1938bde3bcbb4ff09aafd4fcf1ed73a2aa9
7
- data.tar.gz: 4af5e31b75e80dd20dacf7d3e5aeb58ce2e1280337dbe82b69b63c1588ba650d774a9625f00f930b0a25df612f8d7654ae16947cd5b3369ce6e6e3b4880e6483
6
+ metadata.gz: c5d305d7a968088a3ef5488faa360ce06ad6d97072bde0d6b068aae11bcb1824814f87fe1a18e8f09a231cbe34be2954b4565605cdb8a6b8e0d370ee56a6b492
7
+ data.tar.gz: 154b45294bff8f12f2dd8bc338742889d11017983f5e516cca36e9446bbb3c0e6aa61ac35252aaf20ba39ececa96a58c264990f9a1dece39d6d5b39435ab1ad3
@@ -1,6 +1,7 @@
1
1
  require 'segment/analytics/version'
2
2
  require 'segment/analytics/defaults'
3
3
  require 'segment/analytics/utils'
4
+ require 'segment/analytics/field_parser'
4
5
  require 'segment/analytics/client'
5
6
  require 'segment/analytics/worker'
6
7
  require 'segment/analytics/request'
@@ -23,9 +23,8 @@ module Segment
23
23
  @queue = Queue.new
24
24
  @write_key = opts[:write_key]
25
25
  @max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
26
- @options = opts
27
26
  @worker_mutex = Mutex.new
28
- @worker = Worker.new(@queue, @write_key, @options)
27
+ @worker = Worker.new(@queue, @write_key, opts)
29
28
 
30
29
  check_write_key!
31
30
 
@@ -43,58 +42,32 @@ module Segment
43
42
  end
44
43
  end
45
44
 
45
+ # @!macro common_attrs
46
+ # @option attrs [String] :anonymous_id ID for a user when you don't know
47
+ # who they are yet. (optional but you must provide either an
48
+ # `anonymous_id` or `user_id`)
49
+ # @option attrs [Hash] :context ({})
50
+ # @option attrs [Hash] :integrations What integrations this event
51
+ # goes to (optional)
52
+ # @option attrs [String] :message_id ID that uniquely
53
+ # identifies a message across the API. (optional)
54
+ # @option attrs [Time] :timestamp When the event occurred (optional)
55
+ # @option attrs [String] :user_id The ID for this user in your database
56
+ # (optional but you must provide either an `anonymous_id` or `user_id`)
57
+ # @option attrs [Hash] :options Options such as user traits (optional)
58
+
46
59
  # Tracks an event
47
60
  #
48
61
  # @see https://segment.com/docs/sources/server/ruby/#track
49
62
  #
50
63
  # @param [Hash] attrs
51
- # @option attrs [String] :anonymous_id ID for a user when you don't know
52
- # who they are yet. (optional but you must provide either an
53
- # `anonymous_id` or `user_id`)
54
- # @option attrs [Hash] :context ({})
64
+ #
55
65
  # @option attrs [String] :event Event name
56
- # @option attrs [Hash] :integrations What integrations this event
57
- # goes to (optional)
58
- # @option attrs [Hash] :options Options such as user traits (optional)
59
66
  # @option attrs [Hash] :properties Event properties (optional)
60
- # @option attrs [Time] :timestamp When the event occurred (optional)
61
- # @option attrs [String] :user_id The ID for this user in your database
62
- # (optional but you must provide either an `anonymous_id` or `user_id`)
63
- # @option attrs [String] :message_id ID that uniquely
64
- # identifies a message across the API. (optional)
67
+ # @macro common_attrs
65
68
  def track(attrs)
66
69
  symbolize_keys! attrs
67
- check_user_id! attrs
68
-
69
- event = attrs[:event]
70
- properties = attrs[:properties] || {}
71
- timestamp = attrs[:timestamp] || Time.new
72
- context = attrs[:context] || {}
73
- message_id = attrs[:message_id].to_s if attrs[:message_id]
74
-
75
- check_timestamp! timestamp
76
-
77
- if event.nil? || event.empty?
78
- raise ArgumentError, 'Must supply event as a non-empty string'
79
- end
80
-
81
- raise ArgumentError, 'Properties must be a Hash' unless properties.is_a? Hash
82
- isoify_dates! properties
83
-
84
- add_context context
85
-
86
- enqueue({
87
- :event => event,
88
- :userId => attrs[:user_id],
89
- :anonymousId => attrs[:anonymous_id],
90
- :context => context,
91
- :options => attrs[:options],
92
- :integrations => attrs[:integrations],
93
- :properties => properties,
94
- :messageId => message_id,
95
- :timestamp => datetime_in_iso8601(timestamp),
96
- :type => 'track'
97
- })
70
+ enqueue(FieldParser.parse_for_track(attrs))
98
71
  end
99
72
 
100
73
  # Identifies a user
@@ -102,46 +75,12 @@ module Segment
102
75
  # @see https://segment.com/docs/sources/server/ruby/#identify
103
76
  #
104
77
  # @param [Hash] attrs
105
- # @option attrs [String] :anonymous_id ID for a user when you don't know
106
- # who they are yet. (optional but you must provide either an
107
- # `anonymous_id` or `user_id`)
108
- # @option attrs [Hash] :context ({})
109
- # @option attrs [Hash] :integrations What integrations this event
110
- # goes to (optional)
111
- # @option attrs [Hash] :options Options such as user traits (optional)
112
- # @option attrs [Time] :timestamp When the event occurred (optional)
78
+ #
113
79
  # @option attrs [Hash] :traits User traits (optional)
114
- # @option attrs [String] :user_id The ID for this user in your database
115
- # (optional but you must provide either an `anonymous_id` or `user_id`)
116
- # @option attrs [String] :message_id ID that uniquely identifies a
117
- # message across the API. (optional)
80
+ # @macro common_attrs
118
81
  def identify(attrs)
119
82
  symbolize_keys! attrs
120
- check_user_id! attrs
121
-
122
- traits = attrs[:traits] || {}
123
- timestamp = attrs[:timestamp] || Time.new
124
- context = attrs[:context] || {}
125
- message_id = attrs[:message_id].to_s if attrs[:message_id]
126
-
127
- check_timestamp! timestamp
128
-
129
- raise ArgumentError, 'Must supply traits as a hash' unless traits.is_a? Hash
130
- isoify_dates! traits
131
-
132
- add_context context
133
-
134
- enqueue({
135
- :userId => attrs[:user_id],
136
- :anonymousId => attrs[:anonymous_id],
137
- :integrations => attrs[:integrations],
138
- :context => context,
139
- :traits => traits,
140
- :options => attrs[:options],
141
- :messageId => message_id,
142
- :timestamp => datetime_in_iso8601(timestamp),
143
- :type => 'identify'
144
- })
83
+ enqueue(FieldParser.parse_for_identify(attrs))
145
84
  end
146
85
 
147
86
  # Aliases a user from one id to another
@@ -149,39 +88,12 @@ module Segment
149
88
  # @see https://segment.com/docs/sources/server/ruby/#alias
150
89
  #
151
90
  # @param [Hash] attrs
152
- # @option attrs [Hash] :context ({})
153
- # @option attrs [Hash] :integrations What integrations this must be
154
- # sent to (optional)
155
- # @option attrs [Hash] :options Options such as user traits (optional)
91
+ #
156
92
  # @option attrs [String] :previous_id The ID to alias from
157
- # @option attrs [Time] :timestamp When the alias occurred (optional)
158
- # @option attrs [String] :user_id The ID to alias to
159
- # @option attrs [String] :message_id ID that uniquely identifies a
160
- # message across the API. (optional)
93
+ # @macro common_attrs
161
94
  def alias(attrs)
162
95
  symbolize_keys! attrs
163
-
164
- from = attrs[:previous_id]
165
- to = attrs[:user_id]
166
- timestamp = attrs[:timestamp] || Time.new
167
- context = attrs[:context] || {}
168
- message_id = attrs[:message_id].to_s if attrs[:message_id]
169
-
170
- check_presence! from, 'previous_id'
171
- check_presence! to, 'user_id'
172
- check_timestamp! timestamp
173
- add_context context
174
-
175
- enqueue({
176
- :previousId => from,
177
- :userId => to,
178
- :integrations => attrs[:integrations],
179
- :context => context,
180
- :options => attrs[:options],
181
- :messageId => message_id,
182
- :timestamp => datetime_in_iso8601(timestamp),
183
- :type => 'alias'
184
- })
96
+ enqueue(FieldParser.parse_for_alias(attrs))
185
97
  end
186
98
 
187
99
  # Associates a user identity with a group.
@@ -189,48 +101,13 @@ module Segment
189
101
  # @see https://segment.com/docs/sources/server/ruby/#group
190
102
  #
191
103
  # @param [Hash] attrs
192
- # @option attrs [String] :anonymous_id ID for a user when you don't know
193
- # who they are yet. (optional but you must provide either an
194
- # `anonymous_id` or `user_id`)
195
- # @option attrs [Hash] :context ({})
104
+ #
196
105
  # @option attrs [String] :group_id The ID of the group
197
- # @option attrs [Hash] :integrations What integrations this event
198
- # goes to (optional)
199
- # @option attrs [Hash] :options Options such as user traits (optional)
200
- # @option attrs [Time] :timestamp When the event occurred (optional)
201
- # @option attrs [String] :user_id The ID for the user that is part of
202
- # the group
203
- # @option attrs [String] :message_id ID that uniquely identifies a
204
- # message across the API. (optional)
106
+ # @option attrs [Hash] :traits User traits (optional)
107
+ # @macro common_attrs
205
108
  def group(attrs)
206
109
  symbolize_keys! attrs
207
- check_user_id! attrs
208
-
209
- group_id = attrs[:group_id]
210
- user_id = attrs[:user_id]
211
- traits = attrs[:traits] || {}
212
- timestamp = attrs[:timestamp] || Time.new
213
- context = attrs[:context] || {}
214
- message_id = attrs[:message_id].to_s if attrs[:message_id]
215
-
216
- raise ArgumentError, '.traits must be a hash' unless traits.is_a? Hash
217
- isoify_dates! traits
218
-
219
- check_presence! group_id, 'group_id'
220
- check_timestamp! timestamp
221
- add_context context
222
-
223
- enqueue({
224
- :groupId => group_id,
225
- :userId => user_id,
226
- :traits => traits,
227
- :integrations => attrs[:integrations],
228
- :options => attrs[:options],
229
- :context => context,
230
- :messageId => message_id,
231
- :timestamp => datetime_in_iso8601(timestamp),
232
- :type => 'group'
233
- })
110
+ enqueue(FieldParser.parse_for_group(attrs))
234
111
  end
235
112
 
236
113
  # Records a page view
@@ -238,97 +115,26 @@ module Segment
238
115
  # @see https://segment.com/docs/sources/server/ruby/#page
239
116
  #
240
117
  # @param [Hash] attrs
241
- # @option attrs [String] :anonymous_id ID for a user when you don't know
242
- # who they are yet. (optional but you must provide either an
243
- # `anonymous_id` or `user_id`)
244
- # @option attrs [String] :category The page category (optional)
245
- # @option attrs [Hash] :context ({})
246
- # @option attrs [Hash] :integrations What integrations this event
247
- # goes to (optional)
118
+ #
248
119
  # @option attrs [String] :name Name of the page
249
- # @option attrs [Hash] :options Options such as user traits (optional)
250
120
  # @option attrs [Hash] :properties Page properties (optional)
251
- # @option attrs [Time] :timestamp When the pageview occurred (optional)
252
- # @option attrs [String] :user_id The ID of the user viewing the page
253
- # @option attrs [String] :message_id ID that uniquely identifies a
254
- # message across the API. (optional)
121
+ # @macro common_attrs
255
122
  def page(attrs)
256
123
  symbolize_keys! attrs
257
- check_user_id! attrs
258
-
259
- name = attrs[:name].to_s
260
- properties = attrs[:properties] || {}
261
- timestamp = attrs[:timestamp] || Time.new
262
- context = attrs[:context] || {}
263
- message_id = attrs[:message_id].to_s if attrs[:message_id]
264
-
265
- raise ArgumentError, '.properties must be a hash' unless properties.is_a? Hash
266
- isoify_dates! properties
267
-
268
- check_timestamp! timestamp
269
- add_context context
270
-
271
- enqueue({
272
- :userId => attrs[:user_id],
273
- :anonymousId => attrs[:anonymous_id],
274
- :name => name,
275
- :category => attrs[:category],
276
- :properties => properties,
277
- :integrations => attrs[:integrations],
278
- :options => attrs[:options],
279
- :context => context,
280
- :messageId => message_id,
281
- :timestamp => datetime_in_iso8601(timestamp),
282
- :type => 'page'
283
- })
124
+ enqueue(FieldParser.parse_for_page(attrs))
284
125
  end
285
126
 
286
127
  # Records a screen view (for a mobile app)
287
128
  #
288
129
  # @param [Hash] attrs
289
- # @option attrs [String] :anonymous_id ID for a user when you don't know
290
- # who they are yet. (optional but you must provide either an
291
- # `anonymous_id` or `user_id`)
292
- # @option attrs [String] :category The screen category (optional)
293
- # @option attrs [Hash] :context ({})
294
- # @option attrs [Hash] :integrations What integrations this event
295
- # goes to (optional)
130
+ #
296
131
  # @option attrs [String] :name Name of the screen
297
- # @option attrs [Hash] :options Options such as user traits (optional)
298
- # @option attrs [Hash] :properties Page properties (optional)
299
- # @option attrs [Time] :timestamp When the pageview occurred (optional)
300
- # @option attrs [String] :user_id The ID of the user viewing the screen
301
- # @option attrs [String] :message_id ID that uniquely identifies a
302
- # message across the API. (optional)
132
+ # @option attrs [Hash] :properties Screen properties (optional)
133
+ # @option attrs [String] :category The screen category (optional)
134
+ # @macro common_attrs
303
135
  def screen(attrs)
304
136
  symbolize_keys! attrs
305
- check_user_id! attrs
306
-
307
- name = attrs[:name].to_s
308
- properties = attrs[:properties] || {}
309
- timestamp = attrs[:timestamp] || Time.new
310
- context = attrs[:context] || {}
311
- message_id = attrs[:message_id].to_s if attrs[:message_id]
312
-
313
- raise ArgumentError, '.properties must be a hash' unless properties.is_a? Hash
314
- isoify_dates! properties
315
-
316
- check_timestamp! timestamp
317
- add_context context
318
-
319
- enqueue({
320
- :userId => attrs[:user_id],
321
- :anonymousId => attrs[:anonymous_id],
322
- :name => name,
323
- :properties => properties,
324
- :category => attrs[:category],
325
- :options => attrs[:options],
326
- :integrations => attrs[:integrations],
327
- :context => context,
328
- :messageId => message_id,
329
- :timestamp => timestamp.iso8601,
330
- :type => 'screen'
331
- })
137
+ enqueue(FieldParser.parse_for_screen(attrs))
332
138
  end
333
139
 
334
140
  # @return [Fixnum] number of messages in the queue
@@ -360,53 +166,11 @@ module Segment
360
166
  end
361
167
  end
362
168
 
363
- # private: Ensures that a string is non-empty
364
- #
365
- # obj - String|Number that must be non-blank
366
- # name - Name of the validated value
367
- #
368
- def check_presence!(obj, name)
369
- if obj.nil? || (obj.is_a?(String) && obj.empty?)
370
- raise ArgumentError, "#{name} must be given"
371
- end
372
- end
373
-
374
- # private: Adds contextual information to the call
375
- #
376
- # context - Hash of call context
377
- def add_context(context)
378
- context[:library] = { :name => 'analytics-ruby', :version => Segment::Analytics::VERSION.to_s }
379
- end
380
-
381
169
  # private: Checks that the write_key is properly initialized
382
170
  def check_write_key!
383
171
  raise ArgumentError, 'Write key must be initialized' if @write_key.nil?
384
172
  end
385
173
 
386
- # private: Checks the timstamp option to make sure it is a Time.
387
- def check_timestamp!(timestamp)
388
- raise ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
389
- end
390
-
391
- def event(attrs)
392
- symbolize_keys! attrs
393
-
394
- {
395
- :userId => user_id,
396
- :name => name,
397
- :properties => properties,
398
- :context => context,
399
- :timestamp => datetime_in_iso8601(timestamp),
400
- :type => 'screen'
401
- }
402
- end
403
-
404
- def check_user_id!(attrs)
405
- unless attrs[:user_id] || attrs[:anonymous_id]
406
- raise ArgumentError, 'Must supply either user_id or anonymous_id'
407
- end
408
- end
409
-
410
174
  def ensure_worker_running
411
175
  return if worker_running?
412
176
  @worker_mutex.synchronize do
@@ -0,0 +1,184 @@
1
+ module Segment
2
+ class Analytics
3
+ # Handles parsing fields according to the Segment Spec
4
+ #
5
+ # @see https://segment.com/docs/spec/
6
+ class FieldParser
7
+ class << self
8
+ include Segment::Analytics::Utils
9
+
10
+ # In addition to the common fields, track accepts:
11
+ #
12
+ # - "event"
13
+ # - "properties"
14
+ def parse_for_track(fields)
15
+ common = parse_common_fields(fields)
16
+
17
+ event = fields[:event]
18
+ properties = fields[:properties] || {}
19
+
20
+ check_presence!(event, 'event')
21
+ check_is_hash!(properties, 'properties')
22
+
23
+ isoify_dates! properties
24
+
25
+ common.merge({
26
+ :type => 'track',
27
+ :event => event.to_s,
28
+ :properties => properties
29
+ })
30
+ end
31
+
32
+ # In addition to the common fields, identify accepts:
33
+ #
34
+ # - "traits"
35
+ def parse_for_identify(fields)
36
+ common = parse_common_fields(fields)
37
+
38
+ traits = fields[:traits] || {}
39
+ check_is_hash!(traits, 'traits')
40
+ isoify_dates! traits
41
+
42
+ common.merge({
43
+ :type => 'identify',
44
+ :traits => traits
45
+ })
46
+ end
47
+
48
+ # In addition to the common fields, alias accepts:
49
+ #
50
+ # - "previous_id"
51
+ def parse_for_alias(fields)
52
+ common = parse_common_fields(fields)
53
+
54
+ previous_id = fields[:previous_id]
55
+ check_presence!(previous_id, 'previous_id')
56
+
57
+ common.merge({
58
+ :type => 'alias',
59
+ :previousId => previous_id
60
+ })
61
+ end
62
+
63
+ # In addition to the common fields, group accepts:
64
+ #
65
+ # - "group_id"
66
+ # - "traits"
67
+ def parse_for_group(fields)
68
+ common = parse_common_fields(fields)
69
+
70
+ group_id = fields[:group_id]
71
+ traits = fields[:traits] || {}
72
+
73
+ check_presence!(group_id, 'group_id')
74
+ check_is_hash!(traits, 'traits')
75
+
76
+ isoify_dates! traits
77
+
78
+ common.merge({
79
+ :type => 'group',
80
+ :groupId => group_id,
81
+ :traits => traits
82
+ })
83
+ end
84
+
85
+ # In addition to the common fields, page accepts:
86
+ #
87
+ # - "name"
88
+ # - "properties"
89
+ def parse_for_page(fields)
90
+ common = parse_common_fields(fields)
91
+
92
+ name = fields[:name] || ''
93
+ properties = fields[:properties] || {}
94
+
95
+ check_is_hash!(properties, 'properties')
96
+
97
+ isoify_dates! properties
98
+
99
+ common.merge({
100
+ :type => 'page',
101
+ :name => name.to_s,
102
+ :properties => properties
103
+ })
104
+ end
105
+
106
+ # In addition to the common fields, screen accepts:
107
+ #
108
+ # - "name"
109
+ # - "properties"
110
+ # - "category" (Not in spec, retained for backward compatibility"
111
+ def parse_for_screen(fields)
112
+ common = parse_common_fields(fields)
113
+
114
+ name = fields[:name]
115
+ properties = fields[:properties] || {}
116
+ category = fields[:category]
117
+
118
+ check_presence!(name, 'name')
119
+ check_is_hash!(properties, 'properties')
120
+
121
+ isoify_dates! properties
122
+
123
+ common.merge({
124
+ :type => 'screen',
125
+ :name => name,
126
+ :properties => properties,
127
+ :category => category
128
+ })
129
+ end
130
+
131
+ private
132
+
133
+ def parse_common_fields(fields)
134
+ timestamp = fields[:timestamp] || Time.new
135
+ message_id = fields[:message_id].to_s if fields[:message_id]
136
+ context = fields[:context] || {}
137
+
138
+ check_user_id! fields
139
+ check_timestamp! timestamp
140
+
141
+ add_context! context
142
+
143
+ {
144
+ :anonymousId => fields[:anonymous_id],
145
+ :context => context,
146
+ :integrations => fields[:integrations],
147
+ :messageId => message_id,
148
+ :timestamp => datetime_in_iso8601(timestamp),
149
+ :userId => fields[:user_id],
150
+ :options => fields[:options] # Not in spec, retained for backward compatibility
151
+ }
152
+ end
153
+
154
+ def check_user_id!(fields)
155
+ unless fields[:user_id] || fields[:anonymous_id]
156
+ raise ArgumentError, 'Must supply either user_id or anonymous_id'
157
+ end
158
+ end
159
+
160
+ def check_timestamp!(timestamp)
161
+ raise ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
162
+ end
163
+
164
+ def add_context!(context)
165
+ context[:library] = { :name => 'analytics-ruby', :version => Segment::Analytics::VERSION.to_s }
166
+ end
167
+
168
+ # private: Ensures that a string is non-empty
169
+ #
170
+ # obj - String|Number that must be non-blank
171
+ # name - Name of the validated value
172
+ def check_presence!(obj, name)
173
+ if obj.nil? || (obj.is_a?(String) && obj.empty?)
174
+ raise ArgumentError, "#{name} must be given"
175
+ end
176
+ end
177
+
178
+ def check_is_hash!(obj, name)
179
+ raise ArgumentError, "#{name} must be a Hash" unless obj.is_a? Hash
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -1,5 +1,5 @@
1
1
  module Segment
2
2
  class Analytics
3
- VERSION = '2.2.6'
3
+ VERSION = '2.2.7'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: analytics-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.6
4
+ version: 2.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Segment.io
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-03 00:00:00.000000000 Z
11
+ date: 2019-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -136,6 +136,7 @@ files:
136
136
  - lib/segment/analytics/backoff_policy.rb
137
137
  - lib/segment/analytics/client.rb
138
138
  - lib/segment/analytics/defaults.rb
139
+ - lib/segment/analytics/field_parser.rb
139
140
  - lib/segment/analytics/logging.rb
140
141
  - lib/segment/analytics/message_batch.rb
141
142
  - lib/segment/analytics/request.rb