amplitude-api 0.1.1 → 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 +4 -4
- data/.rubocop.yml +19 -1
- data/.travis.yml +2 -4
- data/Changelog.md +11 -1
- data/Gemfile +9 -7
- data/Gemfile.lock +10 -8
- data/Rakefile +7 -5
- data/amplitude-api.gemspec +17 -15
- data/lib/amplitude-api.rb +3 -4
- data/lib/amplitude_api.rb +48 -37
- data/lib/amplitude_api/config.rb +25 -4
- data/lib/amplitude_api/event.rb +75 -15
- data/lib/amplitude_api/identification.rb +3 -1
- data/lib/amplitude_api/version.rb +3 -1
- data/readme.md +4 -4
- data/spec/lib/amplitude_api/event_spec.rb +193 -112
- data/spec/lib/amplitude_api/identification_spec.rb +19 -17
- data/spec/lib/amplitude_api_spec.rb +265 -213
- data/spec/spec_helper.rb +7 -5
- metadata +8 -8
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AmplitudeAPI
|
2
4
|
# AmplitudeAPI::Identification
|
3
5
|
class Identification
|
@@ -16,7 +18,7 @@ class AmplitudeAPI
|
|
16
18
|
# @param [ String ] user_id a user_id to associate with the identification
|
17
19
|
# @param [ String ] device_id a device_id to associate with the identification
|
18
20
|
# @param [ Hash ] user_properties various properties to attach to the user identification
|
19
|
-
def initialize(user_id:
|
21
|
+
def initialize(user_id: "", device_id: nil, user_properties: {})
|
20
22
|
self.user_id = user_id
|
21
23
|
self.device_id = device_id if device_id
|
22
24
|
self.user_properties = user_properties
|
data/readme.md
CHANGED
@@ -19,7 +19,7 @@ AmplitudeAPI.config.api_key = "abcdef123456"
|
|
19
19
|
|
20
20
|
|
21
21
|
event = AmplitudeAPI::Event.new({
|
22
|
-
user_id: "
|
22
|
+
user_id: "12345",
|
23
23
|
event_type: "clicked on home",
|
24
24
|
time: Time.now,
|
25
25
|
insert_id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
|
@@ -42,12 +42,12 @@ AmplitudeAPI.config.api_key = "abcdef123456"
|
|
42
42
|
# Configure your Amplitude Secret Key
|
43
43
|
AmplitudeAPI.config.secret_key = "secretMcSecret"
|
44
44
|
|
45
|
-
AmplitudeAPI.delete(user_ids: [
|
45
|
+
AmplitudeAPI.delete(user_ids: ["12345"],
|
46
46
|
requester: "privacy@example.com"
|
47
47
|
)
|
48
48
|
```
|
49
49
|
|
50
|
-
Currently, we are using this in Rails and using ActiveJob to dispatch events asynchronously. I plan on moving
|
50
|
+
Currently, we are using this in Rails and using ActiveJob to dispatch events asynchronously. I plan on moving
|
51
51
|
background/asynchronous support into this gem.
|
52
52
|
|
53
53
|
## What's Next
|
@@ -56,7 +56,7 @@ background/asynchronous support into this gem.
|
|
56
56
|
* Configurable default account to use when no `user_id` present
|
57
57
|
|
58
58
|
## Other useful resources
|
59
|
-
* [Amplitude HTTP Api Documentation](https://amplitude.
|
59
|
+
* [Amplitude HTTP API V2 Api Documentation](https://developers.amplitude.com/docs/http-api-v2)
|
60
60
|
* [Segment.io Amplitude integration](https://segment.com/docs/integrations/amplitude/)
|
61
61
|
|
62
62
|
## Contributing
|
@@ -1,277 +1,318 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
2
4
|
|
3
5
|
describe AmplitudeAPI::Event do
|
4
6
|
user = Struct.new(:id)
|
5
7
|
|
6
|
-
context
|
7
|
-
describe
|
8
|
+
context "with a user object" do
|
9
|
+
describe "#body" do
|
8
10
|
it "populates with the user's id" do
|
9
11
|
event = described_class.new(
|
10
12
|
user_id: user.new(123),
|
11
|
-
event_type:
|
13
|
+
event_type: "clicked on home"
|
12
14
|
)
|
13
15
|
expect(event.to_hash[:user_id]).to eq(123)
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
context
|
19
|
-
describe
|
20
|
+
context "with a user id" do
|
21
|
+
describe "#body" do
|
20
22
|
it "populates with the user's id" do
|
21
23
|
event = described_class.new(
|
22
24
|
user_id: 123,
|
23
|
-
event_type:
|
25
|
+
event_type: "clicked on home"
|
24
26
|
)
|
25
27
|
expect(event.to_hash[:user_id]).to eq(123)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
context
|
31
|
-
describe
|
32
|
-
it
|
32
|
+
context "without a user" do
|
33
|
+
describe "#body" do
|
34
|
+
it "populates with the unknown user" do
|
33
35
|
event = described_class.new(
|
34
36
|
user_id: nil,
|
35
|
-
event_type:
|
37
|
+
event_type: "clicked on home"
|
36
38
|
)
|
37
39
|
expect(event.to_hash[:user_id]).to eq(AmplitudeAPI::USER_WITH_NO_ACCOUNT)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
|
-
describe
|
43
|
-
context
|
44
|
-
it
|
44
|
+
describe "init" do
|
45
|
+
context "attributes" do
|
46
|
+
it "accepts string attributes" do
|
45
47
|
time = Time.at(1_451_606_400_000 / 1_000)
|
46
48
|
event = described_class.new(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
"user_id" => 123,
|
50
|
+
"device_id" => "abcd",
|
51
|
+
"event_type" => "sausage",
|
52
|
+
"event_properties" => { "a" => "b" },
|
53
|
+
"user_properties" => { "c" => "d" },
|
54
|
+
"time" => time,
|
55
|
+
"ip" => "127.0.0.1",
|
56
|
+
"platform" => "Web",
|
57
|
+
"country" => "United States",
|
58
|
+
"insert_id" => "bestId"
|
57
59
|
)
|
58
60
|
|
59
|
-
expect(event.to_hash).to eq(event_type:
|
61
|
+
expect(event.to_hash).to eq(event_type: "sausage",
|
60
62
|
user_id: 123,
|
61
|
-
device_id:
|
62
|
-
event_properties: {
|
63
|
-
user_properties: {
|
63
|
+
device_id: "abcd",
|
64
|
+
event_properties: { "a" => "b" },
|
65
|
+
user_properties: { "c" => "d" },
|
64
66
|
time: 1_451_606_400_000,
|
65
|
-
ip:
|
66
|
-
platform:
|
67
|
-
country:
|
68
|
-
insert_id:
|
67
|
+
ip: "127.0.0.1",
|
68
|
+
platform: "Web",
|
69
|
+
country: "United States",
|
70
|
+
insert_id: "bestId")
|
69
71
|
end
|
70
72
|
|
71
|
-
it
|
73
|
+
it "accepts symbol attributes" do
|
72
74
|
time = Time.at(1_451_606_400_000 / 1_000)
|
73
75
|
event = described_class.new(
|
74
76
|
user_id: 123,
|
75
|
-
device_id:
|
76
|
-
event_type:
|
77
|
-
event_properties: {
|
78
|
-
user_properties: {
|
77
|
+
device_id: "abcd",
|
78
|
+
event_type: "sausage",
|
79
|
+
event_properties: { "a" => "b" },
|
80
|
+
user_properties: { "c" => "d" },
|
79
81
|
time: time,
|
80
|
-
ip:
|
81
|
-
platform:
|
82
|
-
country:
|
83
|
-
insert_id:
|
82
|
+
ip: "127.0.0.1",
|
83
|
+
platform: "Web",
|
84
|
+
country: "United States",
|
85
|
+
insert_id: "bestId"
|
84
86
|
)
|
85
87
|
|
86
|
-
expect(event.to_hash).to eq(event_type:
|
88
|
+
expect(event.to_hash).to eq(event_type: "sausage",
|
87
89
|
user_id: 123,
|
88
|
-
device_id:
|
89
|
-
event_properties: {
|
90
|
-
user_properties: {
|
90
|
+
device_id: "abcd",
|
91
|
+
event_properties: { "a" => "b" },
|
92
|
+
user_properties: { "c" => "d" },
|
91
93
|
time: 1_451_606_400_000,
|
92
|
-
ip:
|
93
|
-
platform:
|
94
|
-
country:
|
95
|
-
insert_id:
|
94
|
+
ip: "127.0.0.1",
|
95
|
+
platform: "Web",
|
96
|
+
country: "United States",
|
97
|
+
insert_id: "bestId")
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
|
-
context
|
100
|
-
it
|
101
|
+
context "the user sends a revenue_type or a product_id" do
|
102
|
+
it "raises an error if there is not a price neither a revenue" do
|
101
103
|
expect do
|
102
104
|
described_class.new(
|
103
105
|
user_id: 123,
|
104
|
-
event_type:
|
105
|
-
product_id:
|
106
|
+
event_type: "bad event",
|
107
|
+
product_id: "hopscotch.4lyfe"
|
106
108
|
)
|
107
|
-
end.to raise_error
|
109
|
+
end.to raise_error ArgumentError, /You must provide a price or a revenue/
|
110
|
+
|
111
|
+
expect do
|
112
|
+
described_class.new(
|
113
|
+
user_id: 123,
|
114
|
+
event_type: "bad event",
|
115
|
+
revenue_type: "whatever"
|
116
|
+
)
|
117
|
+
end.to raise_error ArgumentError, /You must provide a price or a revenue/
|
108
118
|
end
|
109
119
|
|
110
|
-
it
|
120
|
+
it "does not raise an error if there is a price" do
|
111
121
|
expect do
|
112
122
|
described_class.new(
|
113
123
|
user_id: 123,
|
114
|
-
event_type:
|
115
|
-
|
124
|
+
event_type: "bad event",
|
125
|
+
product_id: "hopscotch.4lyfe",
|
126
|
+
price: 10.2
|
116
127
|
)
|
117
|
-
end.
|
128
|
+
end.not_to raise_error
|
129
|
+
|
130
|
+
expect do
|
131
|
+
described_class.new(
|
132
|
+
user_id: 123,
|
133
|
+
event_type: "bad event",
|
134
|
+
revenue_type: "whatever",
|
135
|
+
price: 10.2
|
136
|
+
)
|
137
|
+
end.not_to raise_error
|
138
|
+
end
|
139
|
+
|
140
|
+
it "does not raise an error if there is a revenue" do
|
141
|
+
expect do
|
142
|
+
described_class.new(
|
143
|
+
user_id: 123,
|
144
|
+
event_type: "bad event",
|
145
|
+
product_id: "hopscotch.4lyfe",
|
146
|
+
revenue: 100.1
|
147
|
+
)
|
148
|
+
end.not_to raise_error
|
149
|
+
|
150
|
+
expect do
|
151
|
+
described_class.new(
|
152
|
+
user_id: 123,
|
153
|
+
event_type: "bad event",
|
154
|
+
revenue_type: "whatever",
|
155
|
+
revenue: 100.1
|
156
|
+
)
|
157
|
+
end.not_to raise_error
|
118
158
|
end
|
119
159
|
end
|
120
160
|
end
|
121
161
|
|
122
|
-
describe
|
123
|
-
it
|
162
|
+
describe "#to_hash" do
|
163
|
+
it "includes the event type" do
|
124
164
|
event = described_class.new(
|
125
165
|
user_id: 123,
|
126
|
-
event_type:
|
166
|
+
event_type: "clicked on home"
|
127
167
|
)
|
128
|
-
expect(event.to_hash[:event_type]).to eq(
|
168
|
+
expect(event.to_hash[:event_type]).to eq("clicked on home")
|
129
169
|
end
|
130
170
|
|
131
|
-
it
|
171
|
+
it "includes arbitrary properties" do
|
132
172
|
event = described_class.new(
|
133
173
|
user_id: 123,
|
134
|
-
event_type:
|
174
|
+
event_type: "clicked on home",
|
135
175
|
event_properties: { abc: :def }
|
136
176
|
)
|
137
177
|
expect(event.to_hash[:event_properties]).to eq(abc: :def)
|
138
178
|
end
|
139
179
|
|
140
|
-
describe
|
141
|
-
it
|
180
|
+
describe "time" do
|
181
|
+
it "includes a time for the event" do
|
142
182
|
time = Time.at(1_451_606_400_000 / 1_000)
|
143
183
|
event = described_class.new(
|
144
184
|
user_id: 123,
|
145
|
-
event_type:
|
185
|
+
event_type: "clicked on home",
|
146
186
|
time: time
|
147
187
|
)
|
148
188
|
expect(event.to_hash[:time]).to eq(1_451_606_400_000)
|
149
189
|
end
|
150
190
|
|
151
|
-
it
|
191
|
+
it "does not include time if it is not set" do
|
152
192
|
event = described_class.new(
|
153
193
|
user_id: 123,
|
154
|
-
event_type:
|
194
|
+
event_type: "clicked on home"
|
155
195
|
)
|
156
196
|
expect(event.to_hash).not_to have_key(:time)
|
157
197
|
end
|
158
198
|
end
|
159
199
|
|
160
|
-
describe
|
161
|
-
it
|
200
|
+
describe "insert_id" do
|
201
|
+
it "includes an insert_id for the event" do
|
162
202
|
event = described_class.new(
|
163
203
|
user_id: 123,
|
164
|
-
event_type:
|
165
|
-
insert_id:
|
204
|
+
event_type: "clicked on home",
|
205
|
+
insert_id: "foo-bar"
|
166
206
|
)
|
167
|
-
expect(event.to_hash[:insert_id]).to eq(
|
207
|
+
expect(event.to_hash[:insert_id]).to eq("foo-bar")
|
168
208
|
end
|
169
209
|
|
170
|
-
it
|
210
|
+
it "does not include insert_id if it is not set" do
|
171
211
|
event = described_class.new(
|
172
212
|
user_id: 123,
|
173
|
-
event_type:
|
213
|
+
event_type: "clicked on home"
|
174
214
|
)
|
175
215
|
expect(event.to_hash).not_to have_key(:insert_id)
|
176
216
|
end
|
177
217
|
end
|
178
218
|
|
179
|
-
describe
|
180
|
-
it
|
219
|
+
describe "platform" do
|
220
|
+
it "includes the platform for the event" do
|
181
221
|
event = described_class.new(
|
182
222
|
user_id: 123,
|
183
|
-
event_type:
|
184
|
-
platform:
|
223
|
+
event_type: "clicked on home",
|
224
|
+
platform: "Web"
|
185
225
|
)
|
186
|
-
expect(event.to_hash[:platform]).to eq(
|
226
|
+
expect(event.to_hash[:platform]).to eq("Web")
|
187
227
|
end
|
188
228
|
|
189
|
-
it
|
229
|
+
it "does not include the platform if it is not set" do
|
190
230
|
event = described_class.new(
|
191
231
|
user_id: 123,
|
192
|
-
event_type:
|
232
|
+
event_type: "clicked on home"
|
193
233
|
)
|
194
234
|
expect(event.to_hash).not_to have_key(:platform)
|
195
235
|
end
|
196
236
|
end
|
197
237
|
|
198
|
-
describe
|
199
|
-
it
|
238
|
+
describe "country" do
|
239
|
+
it "includes the country for the event" do
|
200
240
|
event = described_class.new(
|
201
241
|
user_id: 123,
|
202
|
-
event_type:
|
203
|
-
country:
|
242
|
+
event_type: "clicked on home",
|
243
|
+
country: "United States"
|
204
244
|
)
|
205
|
-
expect(event.to_hash[:country]).to eq(
|
245
|
+
expect(event.to_hash[:country]).to eq("United States")
|
206
246
|
end
|
207
247
|
|
208
|
-
it
|
248
|
+
it "does not include the country if it is not set" do
|
209
249
|
event = described_class.new(
|
210
250
|
user_id: 123,
|
211
|
-
event_type:
|
251
|
+
event_type: "clicked on home"
|
212
252
|
)
|
213
253
|
expect(event.to_hash).not_to have_key(:country)
|
214
254
|
end
|
215
255
|
end
|
216
256
|
|
217
|
-
describe
|
218
|
-
it
|
257
|
+
describe "revenue params" do
|
258
|
+
it "includes the price if it is set" do
|
219
259
|
price = 100_000.99
|
220
260
|
event = described_class.new(
|
221
261
|
user_id: 123,
|
222
|
-
event_type:
|
262
|
+
event_type: "clicked on home",
|
223
263
|
price: price
|
224
264
|
)
|
225
265
|
expect(event.to_hash[:price]).to eq(price)
|
226
266
|
end
|
227
267
|
|
228
|
-
it
|
229
|
-
|
268
|
+
it "includes the quantity if it is set" do
|
269
|
+
quantity = 100
|
230
270
|
event = described_class.new(
|
231
271
|
user_id: 123,
|
232
|
-
event_type:
|
233
|
-
|
272
|
+
event_type: "clicked on home",
|
273
|
+
quantity: quantity,
|
274
|
+
price: 10.99
|
234
275
|
)
|
235
|
-
expect(event.to_hash[:quantity]).to eq(
|
276
|
+
expect(event.to_hash[:quantity]).to eq(quantity)
|
236
277
|
end
|
237
278
|
|
238
|
-
it
|
239
|
-
|
279
|
+
it "includes the revenue if it is set" do
|
280
|
+
revenue = 100
|
240
281
|
event = described_class.new(
|
241
282
|
user_id: 123,
|
242
|
-
event_type:
|
243
|
-
quantity:
|
244
|
-
|
283
|
+
event_type: "clicked on home",
|
284
|
+
quantity: 456,
|
285
|
+
revenue: revenue
|
245
286
|
)
|
246
|
-
expect(event.to_hash[:
|
287
|
+
expect(event.to_hash[:revenue]).to eq(revenue)
|
247
288
|
end
|
248
289
|
|
249
|
-
it
|
250
|
-
product_id =
|
290
|
+
it "includes the productID if set" do
|
291
|
+
product_id = "hopscotch.subscriptions.rule"
|
251
292
|
event = described_class.new(
|
252
293
|
user_id: 123,
|
253
|
-
event_type:
|
294
|
+
event_type: "clicked on home",
|
254
295
|
price: 199.99,
|
255
296
|
product_id: product_id
|
256
297
|
)
|
257
298
|
expect(event.to_hash[:productId]).to eq(product_id)
|
258
299
|
end
|
259
300
|
|
260
|
-
it
|
261
|
-
revenue_type =
|
301
|
+
it "includes the revenueType if set" do
|
302
|
+
revenue_type = "income"
|
262
303
|
event = described_class.new(
|
263
304
|
user_id: 123,
|
264
|
-
event_type:
|
305
|
+
event_type: "clicked on home",
|
265
306
|
price: 199.99,
|
266
307
|
revenue_type: revenue_type
|
267
308
|
)
|
268
309
|
expect(event.to_hash[:revenueType]).to eq(revenue_type)
|
269
310
|
end
|
270
311
|
|
271
|
-
it
|
312
|
+
it "does not include revenue params if they are not set" do
|
272
313
|
event = described_class.new(
|
273
314
|
user_id: 123,
|
274
|
-
event_type:
|
315
|
+
event_type: "clicked on home"
|
275
316
|
)
|
276
317
|
expect(event.to_hash).not_to have_key(:quantity)
|
277
318
|
expect(event.to_hash).not_to have_key(:revenueType)
|
@@ -280,4 +321,44 @@ describe AmplitudeAPI::Event do
|
|
280
321
|
end
|
281
322
|
end
|
282
323
|
end
|
324
|
+
|
325
|
+
describe "arbitrary properties" do
|
326
|
+
# We need to create a class for each test because the methods we are calling
|
327
|
+
# in this test group are modifying the class
|
328
|
+
let(:klass) { Class.new described_class }
|
329
|
+
|
330
|
+
let(:event) {
|
331
|
+
klass.new(
|
332
|
+
user_id: 123,
|
333
|
+
event_type: "bad event"
|
334
|
+
)
|
335
|
+
}
|
336
|
+
|
337
|
+
it "creates arbitrary properties when assigning values" do
|
338
|
+
event.arbitrary_property = "arbitrary value"
|
339
|
+
|
340
|
+
expect(event.arbitrary_property).to eq "arbitrary value"
|
341
|
+
end
|
342
|
+
|
343
|
+
it "responds_to? arbitrary properties" do
|
344
|
+
event.arbitrary_property = "arbitrary value"
|
345
|
+
|
346
|
+
expect(event.respond_to?(:arbitrary_property)).to be true
|
347
|
+
expect(event.respond_to?(:arbitrary_property=)).to be true
|
348
|
+
end
|
349
|
+
|
350
|
+
it "do not accepts blocks when assigning values to create properties" do
|
351
|
+
expect do
|
352
|
+
event.arbitrary_property { puts "whatever" }
|
353
|
+
end.to raise_error NoMethodError
|
354
|
+
end
|
355
|
+
|
356
|
+
it "includes arbitrary properties in the generated hash" do
|
357
|
+
event.arbitrary_property = "arbitrary value"
|
358
|
+
|
359
|
+
hash = event.to_hash
|
360
|
+
|
361
|
+
expect(hash).to include(arbitrary_property: "arbitrary value")
|
362
|
+
end
|
363
|
+
end
|
283
364
|
end
|