mixpanel-ruby 2.2.1 → 2.2.2

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: 51973ff0dbb444c35e3c971e1c2bea676b511795f50afa1972319ba2f35acda5
4
- data.tar.gz: 20b2c55a765a2bbfe0cdf03a94767d8ab1415abf4a7f1ac8d82b53f53c34dc38
3
+ metadata.gz: 528783e14b23218c322ec9513d2a7ba3112a41b54b53d9dd0cd2abeed7630b54
4
+ data.tar.gz: 5aded14afb1a1fca08fe5a02e386347edb665edc871677adf849a47af12658a2
5
5
  SHA512:
6
- metadata.gz: b7c80d420403a94fc63f5df839110bdb05033f208748cebb86aea6d92dc94d9edd8456978820214725040b0abe1eb58276185c4d15d352850d9bf07df1cd0254
7
- data.tar.gz: aad34a8e509085e21c89d274d0ac3a5caabaf89133891ed93c8a2b836f409e2797668a4f057d4f90a119ac792964b5fa62be0cb35bfa45db74bfe3fda46aaa47
6
+ metadata.gz: 58cdf71f0d7b8dfdcd85919fa6105694c24732a20b5f637b9e907d6fa5cb7d55c30e8f1ddd92d791708bf8425d0c886043bad13ccdf8dada91d8b2f6e328a235
7
+ data.tar.gz: 3aee5d979f1a9f27ef93a7acbf20acdf23341c653bf234b0a6fe55b619d73e57c5ef544b8e22e51b0ace0d958e48414c34c71274e18bf258b497416d48e69b0a
@@ -49,6 +49,9 @@ In particular, for Rails apps, the following projects are currently actively mai
49
49
 
50
50
  == Changes
51
51
 
52
+ == 2.2.2
53
+ * Add Group Analytics support with Mixpanel::Groups
54
+
52
55
  == 2.2.1
53
56
  * Fix buffer clearing on partially successful writes in BufferedConsumer.
54
57
 
@@ -58,9 +58,13 @@ module Mixpanel
58
58
  # they will be used instead of the default Mixpanel endpoints.
59
59
  # This can be useful for proxying, debugging, or if you prefer
60
60
  # not to use SSL for your events.
61
- def initialize(events_endpoint=nil, update_endpoint=nil, import_endpoint=nil)
61
+ def initialize(events_endpoint=nil,
62
+ update_endpoint=nil,
63
+ groups_endpoint=nil,
64
+ import_endpoint=nil)
62
65
  @events_endpoint = events_endpoint || 'https://api.mixpanel.com/track'
63
66
  @update_endpoint = update_endpoint || 'https://api.mixpanel.com/engage'
67
+ @groups_endpoint = groups_endpoint || 'https://api.mixpanel.com/groups'
64
68
  @import_endpoint = import_endpoint || 'https://api.mixpanel.com/import'
65
69
  end
66
70
 
@@ -75,6 +79,7 @@ module Mixpanel
75
79
  endpoint = {
76
80
  :event => @events_endpoint,
77
81
  :profile_update => @update_endpoint,
82
+ :group_update => @groups_endpoint,
78
83
  :import => @import_endpoint,
79
84
  }[type]
80
85
 
@@ -0,0 +1,201 @@
1
+ require 'date'
2
+ require 'json'
3
+ require 'time'
4
+
5
+ require 'mixpanel-ruby/consumer'
6
+ require 'mixpanel-ruby/error'
7
+
8
+ module Mixpanel
9
+
10
+ # Handles formatting Mixpanel group updates and
11
+ # sending them to the consumer. You will rarely need
12
+ # to instantiate this class directly- to send
13
+ # group updates, use Mixpanel::Tracker#groups
14
+ #
15
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
16
+ # tracker.groups.set(...) or .set_once(..), or .delete(...) etc.
17
+ class Groups
18
+
19
+ # You likely won't need to instantiate instances of Mixpanel::Groups
20
+ # directly. The best way to get an instance of Mixpanel::Groups is
21
+ #
22
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
23
+ # tracker.groups # An instance of Mixpanel::Groups
24
+ #
25
+ def initialize(token, error_handler=nil, &block)
26
+ @token = token
27
+ @error_handler = error_handler || ErrorHandler.new
28
+
29
+ if block
30
+ @sink = block
31
+ else
32
+ consumer = Consumer.new
33
+ @sink = consumer.method(:send!)
34
+ end
35
+ end
36
+
37
+ # Sets properties on a group record. Takes a Hash with string
38
+ # keys, and values that are strings, numbers, booleans, or
39
+ # DateTimes
40
+ #
41
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
42
+ # # Sets properties on group with id "1234"
43
+ # tracker.groups.set("GROUP KEY", "1234", {
44
+ # 'company' => 'Acme',
45
+ # 'plan' => 'Premium',
46
+ # 'Sign-Up Date' => DateTime.now
47
+ # });
48
+ #
49
+ # If you provide an ip argument, \Mixpanel will use that
50
+ # ip address for geolocation (rather than the ip of your server)
51
+ def set(group_key, group_id, properties, ip=nil, optional_params={})
52
+ properties = fix_property_dates(properties)
53
+ message = {
54
+ '$group_key' => group_key,
55
+ '$group_id' => group_id,
56
+ '$set' => properties,
57
+ }.merge(optional_params)
58
+ message['$ip'] = ip if ip
59
+
60
+ update(message)
61
+ end
62
+
63
+ # set_once works just like #set, but will only change the
64
+ # value of properties if they are not already present
65
+ # in the group. That means you can call set_once many times
66
+ # without changing an original value.
67
+ #
68
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
69
+ # tracker.groups.set_once("GROUP KEY", "1234", {
70
+ # 'First Login Date': DateTime.now
71
+ # });
72
+ #
73
+ def set_once(group_key, group_id, properties, ip=nil, optional_params={})
74
+ properties = fix_property_dates(properties)
75
+ message = {
76
+ '$group_key' => group_key,
77
+ '$group_id' => group_id,
78
+ '$set_once' => properties,
79
+ }.merge(optional_params)
80
+ message['$ip'] = ip if ip
81
+
82
+ update(message)
83
+ end
84
+
85
+ # Removes a specific value in a list property
86
+ #
87
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
88
+ #
89
+ # # removes "socks" from the "Items purchased" list property
90
+ # # for the specified group
91
+ # tracker.groups.remove("GROUP KEY", "1234", { 'Items purchased' => 'socks' })
92
+ #
93
+ def remove(group_key, group_id, properties, ip=nil, optional_params={})
94
+ properties = fix_property_dates(properties)
95
+ message = {
96
+ '$group_key' => group_key,
97
+ '$group_id' => group_id,
98
+ '$remove' => properties,
99
+ }.merge(optional_params)
100
+ message['$ip'] = ip if ip
101
+
102
+ update(message)
103
+ end
104
+
105
+ # Set union on list valued properties.
106
+ # Associates a list containing all elements of a given list,
107
+ # and all elements currently in a list associated with the given
108
+ # property. After a union, every element in the list associated
109
+ # with a property will be unique.
110
+ #
111
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
112
+ # tracker.groups.union("GROUP KEY", "1234", {
113
+ # 'Levels Completed' => ['Suffragette City']
114
+ # });
115
+ #
116
+ def union(group_key, group_id, properties, ip=nil, optional_params={})
117
+ properties = fix_property_dates(properties)
118
+ message = {
119
+ '$group_key' => group_key,
120
+ '$group_id' => group_id,
121
+ '$union' => properties,
122
+ }.merge(optional_params)
123
+ message['$ip'] = ip if ip
124
+
125
+ update(message)
126
+ end
127
+
128
+ # Removes properties and their values from a group.
129
+ #
130
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
131
+ #
132
+ # # removes a single property and its value from a group
133
+ # tracker.groups.unset("GROUP KEY", "1234", "Overdue Since")
134
+ #
135
+ # # removes multiple properties and their values from a group
136
+ # tracker.groups.unset("GROUP KEY",
137
+ # "1234",
138
+ # ["Overdue Since", "Paid Date"])
139
+ #
140
+ def unset(group_key, group_id, properties, ip=nil, optional_params={})
141
+ properties = [properties] unless properties.is_a?(Array)
142
+ message = {
143
+ '$group_key' => group_key,
144
+ '$group_id' => group_id,
145
+ '$unset' => properties,
146
+ }.merge(optional_params)
147
+ message['$ip'] = ip if ip
148
+
149
+ update(message)
150
+ end
151
+
152
+ # Permanently delete a group from \Mixpanel groups analytics (all group
153
+ # properties on events stay)
154
+ def delete_group(group_key, group_id, optional_params={})
155
+ update({
156
+ '$group_key' => group_key,
157
+ '$group_id' => group_id,
158
+ '$delete' => '',
159
+ }.merge(optional_params))
160
+ end
161
+
162
+ # Send a generic update to \Mixpanel groups analytics.
163
+ # Caller is responsible for formatting the update message, as
164
+ # documented in the \Mixpanel HTTP specification, and passing
165
+ # the message as a dict to #update. This
166
+ # method might be useful if you want to use very new
167
+ # or experimental features of groups analytics from Ruby
168
+ # The \Mixpanel HTTP tracking API is documented at
169
+ # https://mixpanel.com/help/reference/http
170
+ def update(message)
171
+ data = {
172
+ '$token' => @token,
173
+ '$time' => ((Time.now.to_f) * 1000.0).to_i,
174
+ }.merge(message)
175
+
176
+ message = {'data' => data}
177
+
178
+ ret = true
179
+ begin
180
+ @sink.call(:group_update, message.to_json)
181
+ rescue MixpanelError => e
182
+ @error_handler.handle(e)
183
+ ret = false
184
+ end
185
+
186
+ ret
187
+ end
188
+
189
+ private
190
+
191
+ def fix_property_dates(properties)
192
+ properties.inject({}) do |ret, (key, value)|
193
+ value = value.respond_to?(:new_offset) ? value.new_offset('0') : value
194
+ value = value.respond_to?(:utc) ? value.utc : value # Handle ActiveSupport::TimeWithZone
195
+
196
+ ret[key] = value.respond_to?(:strftime) ? value.strftime('%Y-%m-%dT%H:%M:%S') : value
197
+ ret
198
+ end
199
+ end
200
+ end
201
+ end
@@ -1,5 +1,6 @@
1
1
  require 'mixpanel-ruby/events.rb'
2
2
  require 'mixpanel-ruby/people.rb'
3
+ require 'mixpanel-ruby/groups.rb'
3
4
 
4
5
  module Mixpanel
5
6
  # Use Mixpanel::Tracker to track events and profile updates in your application.
@@ -13,16 +14,25 @@ module Mixpanel
13
14
  # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
14
15
  # tracker.people.set(a_distinct_id, {properties})
15
16
  #
17
+ # To send groups updates, call
18
+ #
19
+ # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
20
+ # tracker.groups.set(group_key, group_id, {properties})
21
+ #
16
22
  # You can find your project token in the settings dialog for your
17
23
  # project, inside of the Mixpanel web application.
18
24
  #
19
25
  # Mixpanel::Tracker is a subclass of Mixpanel::Events, and exposes
20
26
  # an instance of Mixpanel::People as Tracker#people
27
+ # and an instance of Mixpanel::Groups as Tracker#groups
21
28
  class Tracker < Events
22
29
  # An instance of Mixpanel::People. Use this to
23
30
  # send profile updates
24
31
  attr_reader :people
25
32
 
33
+ # An instance of Mixpanel::Groups. Use this to send groups updates
34
+ attr_reader :groups
35
+
26
36
  # Takes your Mixpanel project token, as a string.
27
37
  #
28
38
  # tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
@@ -46,6 +56,7 @@ module Mixpanel
46
56
  super(token, error_handler, &block)
47
57
  @token = token
48
58
  @people = People.new(token, error_handler, &block)
59
+ @groups = Groups.new(token, error_handler, &block)
49
60
  end
50
61
 
51
62
  # A call to #track is a report that an event has occurred. #track
@@ -1,3 +1,3 @@
1
1
  module Mixpanel
2
- VERSION = '2.2.1'
2
+ VERSION = '2.2.2'
3
3
  end
@@ -22,6 +22,13 @@ describe Mixpanel::Consumer do
22
22
  with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
23
23
  end
24
24
 
25
+ it 'should send a request to api.mixpanel.com/groups on groups updates' do
26
+ stub_request(:any, 'https://api.mixpanel.com/groups').to_return({:body => '{"status": 1, "error": null}'})
27
+ subject.send!(:group_update, {'data' => 'TEST EVENT MESSAGE'}.to_json)
28
+ expect(WebMock).to have_requested(:post, 'https://api.mixpanel.com/groups').
29
+ with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
30
+ end
31
+
25
32
  it 'should send a request to api.mixpanel.com/import on event imports' do
26
33
  stub_request(:any, 'https://api.mixpanel.com/import').to_return({:body => '{"status": 1, "error": null}'})
27
34
  subject.send!(:import, {'data' => 'TEST EVENT MESSAGE', 'api_key' => 'API_KEY','verbose' => '1' }.to_json)
@@ -0,0 +1,159 @@
1
+ require 'spec_helper'
2
+ require 'active_support/time'
3
+
4
+ require 'mixpanel-ruby/groups'
5
+
6
+ describe Mixpanel::Groups do
7
+ before(:each) do
8
+ @time_now = Time.parse('Jun 6 1972, 16:23:04')
9
+ allow(Time).to receive(:now).and_return(@time_now)
10
+
11
+ @log = []
12
+ @groups = Mixpanel::Groups.new('TEST TOKEN') do |type, message|
13
+ @log << [type, JSON.load(message)]
14
+ end
15
+ end
16
+
17
+ it 'should send a well formed groups/set message' do
18
+ @groups.set("TEST GROUP KEY", "TEST GROUP ID", {
19
+ '$groupname' => 'Mixpanel',
20
+ '$grouprevenue' => 200
21
+ })
22
+ expect(@log).to eq([[:group_update, 'data' => {
23
+ '$token' => 'TEST TOKEN',
24
+ '$group_key' => 'TEST GROUP KEY',
25
+ '$group_id' => 'TEST GROUP ID',
26
+ '$time' => @time_now.to_i * 1000,
27
+ '$set' => {
28
+ '$groupname' => 'Mixpanel',
29
+ '$grouprevenue' => 200
30
+ }
31
+ }]])
32
+ end
33
+
34
+ it 'should properly cast dates' do
35
+ @groups.set("TEST GROUP KEY", "TEST GROUP ID", {
36
+ 'created_at' => DateTime.new(2013, 1, 2, 3, 4, 5)
37
+ })
38
+ expect(@log).to eq([[:group_update, 'data' => {
39
+ '$token' => 'TEST TOKEN',
40
+ '$group_key' => 'TEST GROUP KEY',
41
+ '$group_id' => 'TEST GROUP ID',
42
+ '$time' => @time_now.to_i * 1000,
43
+ '$set' => {
44
+ 'created_at' => '2013-01-02T03:04:05'
45
+ }
46
+ }]])
47
+ end
48
+
49
+ it 'should convert offset datetimes to UTC' do
50
+ @groups.set("TEST GROUP KEY", "TEST GROUP ID", {
51
+ 'created_at' => DateTime.new(2013, 1, 1, 18, 4, 5, '-8')
52
+ })
53
+ expect(@log).to eq([[:group_update, 'data' => {
54
+ '$token' => 'TEST TOKEN',
55
+ '$group_key' => 'TEST GROUP KEY',
56
+ '$group_id' => 'TEST GROUP ID',
57
+ '$time' => @time_now.to_i * 1000,
58
+ '$set' => {
59
+ 'created_at' => '2013-01-02T02:04:05'
60
+ }
61
+ }]])
62
+ end
63
+
64
+ it 'should convert offset ActiveSupport::TimeWithZone objects to UTC' do
65
+ Time.zone = 'Pacific Time (US & Canada)'
66
+ @groups.set("TEST GROUP KEY", "TEST GROUP ID", {
67
+ 'created_at' => Time.zone.local(2013, 1, 1, 18, 4, 5)
68
+ })
69
+ expect(@log).to eq([[:group_update, 'data' => {
70
+ '$token' => 'TEST TOKEN',
71
+ '$group_key' => 'TEST GROUP KEY',
72
+ '$group_id' => 'TEST GROUP ID',
73
+ '$time' => @time_now.to_i * 1000,
74
+ '$set' => {
75
+ 'created_at' => '2013-01-02T02:04:05'
76
+ }
77
+ }]])
78
+ end
79
+
80
+ it 'should send a well formed groups/set_once message' do
81
+ @groups.set_once("TEST GROUP KEY", "TEST GROUP ID", {
82
+ '$groupname' => 'Mixpanel',
83
+ '$grouprevenue' => 200
84
+ })
85
+ expect(@log).to eq([[:group_update, 'data' => {
86
+ '$token' => 'TEST TOKEN',
87
+ '$group_key' => 'TEST GROUP KEY',
88
+ '$group_id' => 'TEST GROUP ID',
89
+ '$time' => @time_now.to_i * 1000,
90
+ '$set_once' => {
91
+ '$groupname' => 'Mixpanel',
92
+ '$grouprevenue' => 200
93
+ }
94
+ }]])
95
+ end
96
+
97
+ it 'should send a well formed groups/remove message' do
98
+ @groups.remove("TEST GROUP KEY", "TEST GROUP ID", {
99
+ 'Albums' => 'Diamond Dogs'
100
+ })
101
+ expect(@log).to eq([[:group_update, 'data' => {
102
+ '$token' => 'TEST TOKEN',
103
+ '$group_key' => 'TEST GROUP KEY',
104
+ '$group_id' => 'TEST GROUP ID',
105
+ '$time' => @time_now.to_i * 1000,
106
+ '$remove' => {
107
+ 'Albums' => 'Diamond Dogs'
108
+ }
109
+ }]])
110
+ end
111
+
112
+ it 'should send a well formed groups/union message' do
113
+ @groups.union("TEST GROUP KEY", "TEST GROUP ID", {
114
+ 'Albums' => ['Diamond Dogs']
115
+ })
116
+ expect(@log).to eq([[:group_update, 'data' => {
117
+ '$token' => 'TEST TOKEN',
118
+ '$group_key' => 'TEST GROUP KEY',
119
+ '$group_id' => 'TEST GROUP ID',
120
+ '$time' => @time_now.to_i * 1000,
121
+ '$union' => {
122
+ 'Albums' => ['Diamond Dogs']
123
+ }
124
+ }]])
125
+ end
126
+
127
+ it 'should send a well formed unset message' do
128
+ @groups.unset("TEST GROUP KEY", "TEST GROUP ID", 'Albums')
129
+ expect(@log).to eq([[:group_update, 'data' => {
130
+ '$token' => 'TEST TOKEN',
131
+ '$group_key' => 'TEST GROUP KEY',
132
+ '$group_id' => 'TEST GROUP ID',
133
+ '$time' => @time_now.to_i * 1000,
134
+ '$unset' => ['Albums']
135
+ }]])
136
+ end
137
+
138
+ it 'should send a well formed unset message with multiple properties' do
139
+ @groups.unset("TEST GROUP KEY", "TEST GROUP ID", ['Albums', 'Vinyls'])
140
+ expect(@log).to eq([[:group_update, 'data' => {
141
+ '$token' => 'TEST TOKEN',
142
+ '$group_key' => 'TEST GROUP KEY',
143
+ '$group_id' => 'TEST GROUP ID',
144
+ '$time' => @time_now.to_i * 1000,
145
+ '$unset' => ['Albums', 'Vinyls']
146
+ }]])
147
+ end
148
+
149
+ it 'should send a well formed groups/delete message' do
150
+ @groups.delete_group("TEST GROUP KEY", "TEST GROUP ID")
151
+ expect(@log).to eq([[:group_update, 'data' => {
152
+ '$token' => 'TEST TOKEN',
153
+ '$group_key' => 'TEST GROUP KEY',
154
+ '$group_id' => 'TEST GROUP ID',
155
+ '$time' => @time_now.to_i * 1000,
156
+ '$delete' => ''
157
+ }]])
158
+ end
159
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixpanel-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mixpanel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-04 00:00:00.000000000 Z
11
+ date: 2019-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -86,6 +86,7 @@ files:
86
86
  - lib/mixpanel-ruby/consumer.rb
87
87
  - lib/mixpanel-ruby/error.rb
88
88
  - lib/mixpanel-ruby/events.rb
89
+ - lib/mixpanel-ruby/groups.rb
89
90
  - lib/mixpanel-ruby/people.rb
90
91
  - lib/mixpanel-ruby/tracker.rb
91
92
  - lib/mixpanel-ruby/version.rb
@@ -93,6 +94,7 @@ files:
93
94
  - spec/mixpanel-ruby/consumer_spec.rb
94
95
  - spec/mixpanel-ruby/error_spec.rb
95
96
  - spec/mixpanel-ruby/events_spec.rb
97
+ - spec/mixpanel-ruby/groups_spec.rb
96
98
  - spec/mixpanel-ruby/people_spec.rb
97
99
  - spec/mixpanel-ruby/tracker_spec.rb
98
100
  - spec/spec_helper.rb