analytics-ruby 2.2.5 → 2.4.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.
data/Makefile DELETED
@@ -1,17 +0,0 @@
1
-
2
- # Install any tools required to build this library, e.g. Ruby, Bundler etc.
3
- bootstrap:
4
- brew install ruby
5
- gem install bundler
6
-
7
- # Install any library dependencies.
8
- dependencies:
9
- bundle install --verbose
10
-
11
- # Run all tests and checks (including linters).
12
- check:
13
- bundle exec rake
14
-
15
- # Compile the code and produce any binaries where applicable.
16
- build:
17
- gem build ./analytics-ruby.gemspec
data/README.md DELETED
@@ -1,84 +0,0 @@
1
- analytics-ruby
2
- ==============
3
-
4
- [![Build Status](https://travis-ci.org/segmentio/analytics-ruby.png?branch=master)](https://travis-ci.org/segmentio/analytics-ruby)
5
-
6
- analytics-ruby is a ruby client for [Segment](https://segment.com)
7
-
8
- ## Install
9
-
10
- Into Gemfile from rubygems.org:
11
- ```ruby
12
- gem 'analytics-ruby'
13
- ```
14
-
15
- Into environment gems from rubygems.org:
16
- ```
17
- gem install 'analytics-ruby'
18
- ```
19
-
20
- ## Usage
21
-
22
- Create an instance of the Analytics object:
23
- ```ruby
24
- analytics = Segment::Analytics.new(write_key: 'YOUR_WRITE_KEY')
25
- ```
26
-
27
- Identify the user for the people section, see more [here](https://segment.com/docs/libraries/ruby/#identify).
28
- ```ruby
29
- analytics.identify(user_id: 42,
30
- traits: {
31
- email: 'name@example.com',
32
- first_name: 'Foo',
33
- last_name: 'Bar'
34
- })
35
- ```
36
-
37
- Alias an user, see more [here](https://segment.com/docs/libraries/ruby/#alias).
38
- ```ruby
39
- analytics.alias(user_id: 41)
40
- ```
41
-
42
- Track a user event, see more [here](https://segment.com/docs/libraries/ruby/#track).
43
- ```ruby
44
- analytics.track(user_id: 42, event: 'Created Account')
45
- ```
46
-
47
- There are a few calls available, please check the documentation section.
48
-
49
- ## Documentation
50
-
51
- Documentation is available at [segment.com/docs/sources/server/ruby](https://segment.com/docs/sources/server/ruby/)
52
-
53
- ## Testing
54
-
55
- You can use the `stub` option to Segment::Analytics.new to cause all requests to be stubbed, making it easier to test with this library.
56
-
57
- ## License
58
-
59
- ```
60
- WWWWWW||WWWWWW
61
- W W W||W W W
62
- ||
63
- ( OO )__________
64
- / | \
65
- /o o| MIT \
66
- \___/||_||__||_|| *
67
- || || || ||
68
- _||_|| _||_||
69
- (__|__|(__|__|
70
- ```
71
-
72
- (The MIT License)
73
-
74
- Copyright (c) 2013 Segment Inc. <friends@segment.com>
75
-
76
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
77
-
78
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
79
-
80
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
81
-
82
-
83
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/segmentio/analytics-ruby/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
84
-
data/RELEASING.md DELETED
@@ -1,9 +0,0 @@
1
- Releasing
2
- =========
3
-
4
- 1. Verify everything works with `make check build`.
5
- 2. Bump version in [`version.rb`](https://github.com/segmentio/analytics-ruby/blob/master/lib/segment/analytics/version.rb).
6
- 3. Update [`History.md`](https://github.com/segmentio/analytics-ruby/blob/master/History.md).
7
- 4. Commit and tag `git commit -am "Release {version}" && git tag -a {version} -m "Version {version}"`.
8
- 5. Upload to Github with `git push -u origin master && git push --tags`.
9
- The tagged commit will be pushed to RubyGems via Travis.
data/Rakefile DELETED
@@ -1,23 +0,0 @@
1
- require 'rspec/core/rake_task'
2
-
3
- default_tasks = []
4
-
5
- RSpec::Core::RakeTask.new(:spec) do |spec|
6
- spec.pattern = 'spec/**/*_spec.rb'
7
- spec.rspec_opts = "--tag ~e2e" if ENV["RUN_E2E_TESTS"] != "true"
8
- end
9
-
10
- default_tasks << :spec
11
-
12
- # Rubocop doesn't support < 2.1
13
- if RUBY_VERSION >= "2.1"
14
- require 'rubocop/rake_task'
15
-
16
- RuboCop::RakeTask.new(:rubocop) do |task|
17
- task.patterns = ['lib/**/*.rb','spec/**/*.rb',]
18
- end
19
-
20
- default_tasks << :rubocop
21
- end
22
-
23
- task :default => default_tasks
@@ -1,33 +0,0 @@
1
- require File.expand_path('../lib/segment/analytics/version', __FILE__)
2
-
3
- Gem::Specification.new do |spec|
4
- spec.name = 'analytics-ruby'
5
- spec.version = Segment::Analytics::VERSION
6
- spec.files = Dir.glob('**/*')
7
- spec.require_paths = ['lib']
8
- spec.bindir = 'bin'
9
- spec.executables = ['analytics']
10
- spec.summary = 'Segment.io analytics library'
11
- spec.description = 'The Segment.io ruby analytics library'
12
- spec.authors = ['Segment.io']
13
- spec.email = 'friends@segment.io'
14
- spec.homepage = 'https://github.com/segmentio/analytics-ruby'
15
- spec.license = 'MIT'
16
-
17
- # Ruby 1.8 requires json
18
- spec.add_dependency 'json', ['~> 1.7'] if RUBY_VERSION < "1.9"
19
- spec.add_dependency 'commander', '~> 4.4'
20
-
21
- spec.add_development_dependency 'rake', '~> 10.3'
22
- spec.add_development_dependency 'rspec', '~> 3.0'
23
- spec.add_development_dependency 'tzinfo', '1.2.1'
24
- spec.add_development_dependency 'activesupport', '~> 4.1.11'
25
- spec.add_development_dependency 'faraday', '~> 0.13'
26
- spec.add_development_dependency 'pmap', '~> 1.1'
27
-
28
- if RUBY_VERSION >= "2.1"
29
- spec.add_development_dependency 'rubocop', '~> 0.51.0'
30
- end
31
-
32
- spec.add_development_dependency 'codecov', '~> 0.1.4'
33
- end
data/codecov.yml DELETED
@@ -1,2 +0,0 @@
1
- ignore:
2
- - "spec/**/*"
@@ -1,26 +0,0 @@
1
- require 'segment/analytics/defaults'
2
-
3
- module Segment
4
- class Analytics
5
- # Represents a message to be sent to the API
6
- class Message
7
- def initialize(hash)
8
- @hash = hash
9
- end
10
-
11
- def too_big?
12
- json_size > Defaults::Message::MAX_BYTES
13
- end
14
-
15
- def json_size
16
- to_json.bytesize
17
- end
18
-
19
- # Since the hash is expected to not be modified (set at initialization),
20
- # the JSON version can be cached after the first computation.
21
- def to_json(*args)
22
- @json ||= @hash.to_json(*args)
23
- end
24
- end
25
- end
26
- end
@@ -1,38 +0,0 @@
1
- require 'faraday'
2
- require 'pmap'
3
-
4
- class RunscopeClient
5
- def initialize(api_token)
6
- headers = { 'Authorization' => "Bearer #{api_token}" }
7
- @conn = Faraday.new('https://api.runscope.com', headers: headers)
8
- end
9
-
10
- def requests(bucket_key)
11
- with_retries(3) do
12
- response = @conn.get("/buckets/#{bucket_key}/messages", count: 20)
13
-
14
- raise "Runscope error. #{response.body}" unless response.status == 200
15
-
16
- message_uuids = JSON.parse(response.body)['data'].map { |message|
17
- message.fetch('uuid')
18
- }
19
-
20
- message_uuids.pmap { |uuid|
21
- response = @conn.get("/buckets/#{bucket_key}/messages/#{uuid}")
22
- raise "Runscope error. #{response.body}" unless response.status == 200
23
- JSON.parse(response.body).fetch('data').fetch('request')
24
- }
25
- end
26
- end
27
-
28
- private
29
-
30
- def with_retries(max_retries)
31
- retries ||= 0
32
- yield
33
- rescue StandardError => e
34
- retries += 1
35
- retry if retries < max_retries
36
- raise e
37
- end
38
- end
@@ -1,92 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Segment
4
- class Analytics
5
- describe BackoffPolicy do
6
- describe '#initialize' do
7
- context 'no options are given' do
8
- it 'sets default min_timeout_ms' do
9
- actual = subject.instance_variable_get(:@min_timeout_ms)
10
- expect(actual).to eq(described_class::MIN_TIMEOUT_MS)
11
- end
12
-
13
- it 'sets default max_timeout_ms' do
14
- actual = subject.instance_variable_get(:@max_timeout_ms)
15
- expect(actual).to eq(described_class::MAX_TIMEOUT_MS)
16
- end
17
-
18
- it 'sets default multiplier' do
19
- actual = subject.instance_variable_get(:@multiplier)
20
- expect(actual).to eq(described_class::MULTIPLIER)
21
- end
22
-
23
- it 'sets default randomization factor' do
24
- actual = subject.instance_variable_get(:@randomization_factor)
25
- expect(actual).to eq(described_class::RANDOMIZATION_FACTOR)
26
- end
27
- end
28
-
29
- context 'options are given' do
30
- let(:min_timeout_ms) { 1234 }
31
- let(:max_timeout_ms) { 5678 }
32
- let(:multiplier) { 24 }
33
- let(:randomization_factor) { 0.4 }
34
-
35
- let(:options) do
36
- {
37
- min_timeout_ms: min_timeout_ms,
38
- max_timeout_ms: max_timeout_ms,
39
- multiplier: multiplier,
40
- randomization_factor: randomization_factor
41
- }
42
- end
43
-
44
- subject { described_class.new(options) }
45
-
46
- it 'sets passed in min_timeout_ms' do
47
- actual = subject.instance_variable_get(:@min_timeout_ms)
48
- expect(actual).to eq(min_timeout_ms)
49
- end
50
-
51
- it 'sets passed in max_timeout_ms' do
52
- actual = subject.instance_variable_get(:@max_timeout_ms)
53
- expect(actual).to eq(max_timeout_ms)
54
- end
55
-
56
- it 'sets passed in multiplier' do
57
- actual = subject.instance_variable_get(:@multiplier)
58
- expect(actual).to eq(multiplier)
59
- end
60
-
61
- it 'sets passed in randomization_factor' do
62
- actual = subject.instance_variable_get(:@randomization_factor)
63
- expect(actual).to eq(randomization_factor)
64
- end
65
- end
66
- end
67
-
68
- describe '#next_interval' do
69
- subject {
70
- described_class.new(
71
- min_timeout_ms: 1000,
72
- max_timeout_ms: 10000,
73
- multiplier: 2,
74
- randomization_factor: 0.5
75
- )
76
- }
77
-
78
- it 'returns exponentially increasing durations' do
79
- expect(subject.next_interval).to be_within(500).of(1000)
80
- expect(subject.next_interval).to be_within(1000).of(2000)
81
- expect(subject.next_interval).to be_within(2000).of(4000)
82
- expect(subject.next_interval).to be_within(4000).of(8000)
83
- end
84
-
85
- it 'caps maximum duration at max_timeout_secs' do
86
- 10.times { subject.next_interval }
87
- expect(subject.next_interval).to eq(10000)
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,328 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Segment
4
- class Analytics
5
- describe Client do
6
- let(:client) do
7
- Client.new(:write_key => WRITE_KEY).tap { |client|
8
- # Ensure that worker doesn't consume items from the queue
9
- client.instance_variable_set(:@worker, NoopWorker.new)
10
- }
11
- end
12
- let(:queue) { client.instance_variable_get :@queue }
13
-
14
- describe '#initialize' do
15
- it 'errors if no write_key is supplied' do
16
- expect { Client.new }.to raise_error(ArgumentError)
17
- end
18
-
19
- it 'does not error if a write_key is supplied' do
20
- expect do
21
- Client.new :write_key => WRITE_KEY
22
- end.to_not raise_error
23
- end
24
-
25
- it 'does not error if a write_key is supplied as a string' do
26
- expect do
27
- Client.new 'write_key' => WRITE_KEY
28
- end.to_not raise_error
29
- end
30
- end
31
-
32
- describe '#track' do
33
- it 'errors without an event' do
34
- expect { client.track(:user_id => 'user') }.to raise_error(ArgumentError)
35
- end
36
-
37
- it 'errors without a user_id' do
38
- expect { client.track(:event => 'Event') }.to raise_error(ArgumentError)
39
- end
40
-
41
- it 'errors if properties is not a hash' do
42
- expect {
43
- client.track({
44
- :user_id => 'user',
45
- :event => 'Event',
46
- :properties => [1, 2, 3]
47
- })
48
- }.to raise_error(ArgumentError)
49
- end
50
-
51
- it 'uses the timestamp given' do
52
- time = Time.parse('1990-07-16 13:30:00.123 UTC')
53
-
54
- client.track({
55
- :event => 'testing the timestamp',
56
- :user_id => 'joe',
57
- :timestamp => time
58
- })
59
-
60
- msg = queue.pop
61
-
62
- expect(Time.parse(msg[:timestamp])).to eq(time)
63
- end
64
-
65
- it 'does not error with the required options' do
66
- expect do
67
- client.track Queued::TRACK
68
- queue.pop
69
- end.to_not raise_error
70
- end
71
-
72
- it 'does not error when given string keys' do
73
- expect do
74
- client.track Utils.stringify_keys(Queued::TRACK)
75
- queue.pop
76
- end.to_not raise_error
77
- end
78
-
79
- it 'converts time and date traits into iso8601 format' do
80
- client.track({
81
- :user_id => 'user',
82
- :event => 'Event',
83
- :properties => {
84
- :time => Time.utc(2013),
85
- :time_with_zone => Time.zone.parse('2013-01-01'),
86
- :date_time => DateTime.new(2013, 1, 1),
87
- :date => Date.new(2013, 1, 1),
88
- :nottime => 'x'
89
- }
90
- })
91
- message = queue.pop
92
-
93
- properties = message[:properties]
94
- expect(properties[:time]).to eq('2013-01-01T00:00:00.000Z')
95
- expect(properties[:time_with_zone]).to eq('2013-01-01T00:00:00.000Z')
96
- expect(properties[:date_time]).to eq('2013-01-01T00:00:00.000+00:00')
97
- expect(properties[:date]).to eq('2013-01-01')
98
- expect(properties[:nottime]).to eq('x')
99
- end
100
- end
101
-
102
- describe '#identify' do
103
- it 'errors without any user id' do
104
- expect { client.identify({}) }.to raise_error(ArgumentError)
105
- end
106
-
107
- it 'does not error with the required options' do
108
- expect do
109
- client.identify Queued::IDENTIFY
110
- queue.pop
111
- end.to_not raise_error
112
- end
113
-
114
- it 'does not error with the required options as strings' do
115
- expect do
116
- client.identify Utils.stringify_keys(Queued::IDENTIFY)
117
- queue.pop
118
- end.to_not raise_error
119
- end
120
-
121
- it 'converts time and date traits into iso8601 format' do
122
- client.identify({
123
- :user_id => 'user',
124
- :traits => {
125
- :time => Time.utc(2013),
126
- :time_with_zone => Time.zone.parse('2013-01-01'),
127
- :date_time => DateTime.new(2013, 1, 1),
128
- :date => Date.new(2013, 1, 1),
129
- :nottime => 'x'
130
- }
131
- })
132
-
133
- message = queue.pop
134
-
135
- traits = message[:traits]
136
- expect(traits[:time]).to eq('2013-01-01T00:00:00.000Z')
137
- expect(traits[:time_with_zone]).to eq('2013-01-01T00:00:00.000Z')
138
- expect(traits[:date_time]).to eq('2013-01-01T00:00:00.000+00:00')
139
- expect(traits[:date]).to eq('2013-01-01')
140
- expect(traits[:nottime]).to eq('x')
141
- end
142
- end
143
-
144
- describe '#alias' do
145
- it 'errors without from' do
146
- expect { client.alias :user_id => 1234 }.to raise_error(ArgumentError)
147
- end
148
-
149
- it 'errors without to' do
150
- expect { client.alias :previous_id => 1234 }.to raise_error(ArgumentError)
151
- end
152
-
153
- it 'does not error with the required options' do
154
- expect { client.alias ALIAS }.to_not raise_error
155
- end
156
-
157
- it 'does not error with the required options as strings' do
158
- expect do
159
- client.alias Utils.stringify_keys(ALIAS)
160
- end.to_not raise_error
161
- end
162
- end
163
-
164
- describe '#group' do
165
- it 'errors without group_id' do
166
- expect { client.group :user_id => 'foo' }.to raise_error(ArgumentError)
167
- end
168
-
169
- it 'errors without user_id' do
170
- expect { client.group :group_id => 'foo' }.to raise_error(ArgumentError)
171
- end
172
-
173
- it 'does not error with the required options' do
174
- client.group Queued::GROUP
175
- end
176
-
177
- it 'does not error with the required options as strings' do
178
- client.group Utils.stringify_keys(Queued::GROUP)
179
- end
180
-
181
- it 'converts time and date traits into iso8601 format' do
182
- client.identify({
183
- :user_id => 'user',
184
- :group_id => 'group',
185
- :traits => {
186
- :time => Time.utc(2013),
187
- :time_with_zone => Time.zone.parse('2013-01-01'),
188
- :date_time => DateTime.new(2013, 1, 1),
189
- :date => Date.new(2013, 1, 1),
190
- :nottime => 'x'
191
- }
192
- })
193
-
194
- message = queue.pop
195
-
196
- traits = message[:traits]
197
- expect(traits[:time]).to eq('2013-01-01T00:00:00.000Z')
198
- expect(traits[:time_with_zone]).to eq('2013-01-01T00:00:00.000Z')
199
- expect(traits[:date_time]).to eq('2013-01-01T00:00:00.000+00:00')
200
- expect(traits[:date]).to eq('2013-01-01')
201
- expect(traits[:nottime]).to eq('x')
202
- end
203
- end
204
-
205
- describe '#page' do
206
- it 'errors without user_id' do
207
- expect { client.page :name => 'foo' }.to raise_error(ArgumentError)
208
- end
209
-
210
- it 'does not error with the required options' do
211
- expect { client.page Queued::PAGE }.to_not raise_error
212
- end
213
-
214
- it 'does not error with the required options as strings' do
215
- expect do
216
- client.page Utils.stringify_keys(Queued::PAGE)
217
- end.to_not raise_error
218
- end
219
- end
220
-
221
- describe '#screen' do
222
- it 'errors without user_id' do
223
- expect { client.screen :name => 'foo' }.to raise_error(ArgumentError)
224
- end
225
-
226
- it 'does not error with the required options' do
227
- expect { client.screen Queued::SCREEN }.to_not raise_error
228
- end
229
-
230
- it 'does not error with the required options as strings' do
231
- expect do
232
- client.screen Utils.stringify_keys(Queued::SCREEN)
233
- end.to_not raise_error
234
- end
235
- end
236
-
237
- describe '#flush' do
238
- let(:client_with_worker) { Client.new(:write_key => WRITE_KEY) }
239
-
240
- it 'waits for the queue to finish on a flush' do
241
- client_with_worker.identify Queued::IDENTIFY
242
- client_with_worker.track Queued::TRACK
243
- client_with_worker.flush
244
-
245
- expect(client_with_worker.queued_messages).to eq(0)
246
- end
247
-
248
- unless defined? JRUBY_VERSION
249
- it 'completes when the process forks' do
250
- client_with_worker.identify Queued::IDENTIFY
251
-
252
- Process.fork do
253
- client_with_worker.track Queued::TRACK
254
- client_with_worker.flush
255
- expect(client_with_worker.queued_messages).to eq(0)
256
- end
257
-
258
- Process.wait
259
- end
260
- end
261
- end
262
-
263
- context 'common' do
264
- check_property = proc { |msg, k, v| msg[k] && msg[k] == v }
265
-
266
- let(:data) { { :user_id => 1, :group_id => 2, :previous_id => 3, :anonymous_id => 4, :message_id => 5, :event => 'coco barked', :name => 'coco' } }
267
-
268
- it 'does not convert ids given as fixnums to strings' do
269
- [:track, :screen, :page, :identify].each do |s|
270
- client.send(s, data)
271
- message = queue.pop(true)
272
-
273
- expect(check_property.call(message, :userId, 1)).to eq(true)
274
- expect(check_property.call(message, :anonymousId, 4)).to eq(true)
275
- end
276
- end
277
-
278
- it 'returns false if queue is full' do
279
- client.instance_variable_set(:@max_queue_size, 1)
280
-
281
- [:track, :screen, :page, :group, :identify, :alias].each do |s|
282
- expect(client.send(s, data)).to eq(true)
283
- expect(client.send(s, data)).to eq(false) # Queue is full
284
- queue.pop(true)
285
- end
286
- end
287
-
288
- it 'converts message id to string' do
289
- [:track, :screen, :page, :group, :identify, :alias].each do |s|
290
- client.send(s, data)
291
- message = queue.pop(true)
292
-
293
- expect(check_property.call(message, :messageId, '5')).to eq(true)
294
- end
295
- end
296
-
297
- context 'group' do
298
- it 'does not convert ids given as fixnums to strings' do
299
- client.group(data)
300
- message = queue.pop(true)
301
-
302
- expect(check_property.call(message, :userId, 1)).to eq(true)
303
- expect(check_property.call(message, :groupId, 2)).to eq(true)
304
- end
305
- end
306
-
307
- context 'alias' do
308
- it 'does not convert ids given as fixnums to strings' do
309
- client.alias(data)
310
- message = queue.pop(true)
311
-
312
- expect(check_property.call(message, :userId, 1)).to eq(true)
313
- expect(check_property.call(message, :previousId, 3)).to eq(true)
314
- end
315
- end
316
-
317
- it 'sends integrations' do
318
- [:track, :screen, :page, :group, :identify, :alias].each do |s|
319
- client.send s, :integrations => { :All => true, :Salesforce => false }, :user_id => 1, :group_id => 2, :previous_id => 3, :anonymous_id => 4, :event => 'coco barked', :name => 'coco'
320
- message = queue.pop(true)
321
- expect(message[:integrations][:All]).to eq(true)
322
- expect(message[:integrations][:Salesforce]).to eq(false)
323
- end
324
- end
325
- end
326
- end
327
- end
328
- end