mixpanel-ruby 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.rdoc +4 -2
- data/demo/faraday_consumer.rb +40 -0
- data/demo/out_of_process_consumer.rb +1 -1
- data/lib/mixpanel-ruby/consumer.rb +56 -25
- data/lib/mixpanel-ruby/people.rb +5 -5
- data/lib/mixpanel-ruby/tracker.rb +2 -2
- data/lib/mixpanel-ruby/version.rb +1 -1
- data/spec/mixpanel-ruby/consumer_spec.rb +106 -59
- data/spec/mixpanel-ruby/events_spec.rb +3 -3
- data/spec/mixpanel-ruby/people_spec.rb +17 -17
- data/spec/mixpanel-ruby/tracker_spec.rb +10 -10
- metadata +3 -2
data/Readme.rdoc
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
= mixpanel-ruby: The official Mixpanel Ruby library
|
2
2
|
|
3
3
|
mixpanel-ruby is a library for tracking events and sending \Mixpanel profile
|
4
|
-
updates to \Mixpanel from your ruby applications.
|
5
|
-
get started sending your first events and updates:
|
4
|
+
updates to \Mixpanel from your ruby applications.
|
6
5
|
|
7
6
|
== Installation
|
8
7
|
|
@@ -38,6 +37,9 @@ For more information please visit:
|
|
38
37
|
|
39
38
|
== Changes
|
40
39
|
|
40
|
+
== 1.3.0
|
41
|
+
* Added Consumer#request method, demo with Faraday integration
|
42
|
+
|
41
43
|
== 1.2.0
|
42
44
|
* All objects with a "strftime" method will be formatted as dates in
|
43
45
|
people updates.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'mixpanel-ruby'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
# The Mixpanel library's default consumer will use the standard
|
5
|
+
# Net::HTTP library to communicate with servers, but you can extend
|
6
|
+
# your consumers to use other libraries. This example sends data using
|
7
|
+
# the Faraday library (so you'll need that library available to run it)
|
8
|
+
|
9
|
+
class FaradayConsumer < Mixpanel::Consumer
|
10
|
+
def request(endpoint, form_data)
|
11
|
+
conn = ::Faraday.new(endpoint)
|
12
|
+
response = conn.post(nil, form_data)
|
13
|
+
[response.status, response.body]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if __FILE__ == $0
|
18
|
+
# Replace this with the token from your project settings
|
19
|
+
DEMO_TOKEN = '072f77c15bd04a5d0044d3d76ced7fea'
|
20
|
+
faraday_consumer = FaradayConsumer.new
|
21
|
+
|
22
|
+
faraday_tracker = Mixpanel::Tracker.new(DEMO_TOKEN) do |type, message|
|
23
|
+
faraday_consumer.send(type, message)
|
24
|
+
end
|
25
|
+
faraday_tracker.track('ID', 'Event tracked through Faraday')
|
26
|
+
|
27
|
+
# It's also easy to delegate from a BufferedConsumer to your custom
|
28
|
+
# consumer.
|
29
|
+
|
30
|
+
buffered_faraday_consumer = Mixpanel::BufferedConsumer.new do |type, message|
|
31
|
+
faraday_consumer.send(type, message)
|
32
|
+
end
|
33
|
+
|
34
|
+
buffered_faraday_tracker = Mixpanel::Tracker.new(DEMO_TOKEN) do |type, message|
|
35
|
+
buffered_faraday_consumer.send(type, message)
|
36
|
+
end
|
37
|
+
|
38
|
+
buffered_faraday_tracker.track('ID', 'Event tracked (buffered) through faraday')
|
39
|
+
buffered_faraday_consumer.flush
|
40
|
+
end
|
@@ -8,12 +8,19 @@ module Mixpanel
|
|
8
8
|
|
9
9
|
@@init_http = nil
|
10
10
|
|
11
|
+
# This method exists for backwards compatibility. The preferred
|
12
|
+
# way to customize or configure the HTTP library of a consumer
|
13
|
+
# is to override Consumer#request.
|
14
|
+
#
|
11
15
|
# Ruby's default SSL does not verify the server certificate.
|
12
16
|
# To verify a certificate, or install a proxy, pass a block
|
13
|
-
# to Mixpanel
|
17
|
+
# to Mixpanel.config_http that configures the Net::HTTP object.
|
18
|
+
# Note: when using the Faraday adapter, the block will receive
|
19
|
+
# the Faraday::Connection object. Please refer to the Faraday
|
20
|
+
# documentation for configuration examples.
|
14
21
|
# For example, if running in Ubuntu Linux, you can run
|
15
22
|
#
|
16
|
-
# Mixpanel
|
23
|
+
# Mixpanel.config_http do |http|
|
17
24
|
# http.ca_path = '/etc/ssl/certs'
|
18
25
|
# http.ca_file = '/etc/ssl/certs/ca-certificates.crt'
|
19
26
|
# http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
@@ -36,7 +43,7 @@ module Mixpanel
|
|
36
43
|
#
|
37
44
|
# tracker = Mixpanel::Tracker.new(MY_TOKEN) do |type, message|
|
38
45
|
# # type will be one of :event, :profile_update or :import
|
39
|
-
# @kestrel.set(ANALYTICS_QUEUE, [
|
46
|
+
# @kestrel.set(ANALYTICS_QUEUE, [type, message].to_json)
|
40
47
|
# end
|
41
48
|
#
|
42
49
|
# You can also instantiate the library consumers yourself, and use
|
@@ -75,35 +82,46 @@ module Mixpanel
|
|
75
82
|
:event => @events_endpoint,
|
76
83
|
:profile_update => @update_endpoint,
|
77
84
|
:import => @import_endpoint
|
78
|
-
}[
|
85
|
+
}[type]
|
79
86
|
|
80
87
|
decoded_message = JSON.load(message)
|
81
88
|
api_key = decoded_message["api_key"]
|
82
89
|
data = Base64.encode64(decoded_message["data"].to_json).gsub("\n", '')
|
83
90
|
|
91
|
+
form_data = {"data" => data, "verbose" => 1}
|
92
|
+
form_data.merge!("api_key" => api_key) if api_key
|
93
|
+
|
94
|
+
response_code, response_body = request(endpoint, form_data)
|
95
|
+
|
96
|
+
succeeded = nil
|
97
|
+
if response_code.to_i == 200
|
98
|
+
result = JSON.load(response_body) rescue {}
|
99
|
+
succeeded = result['status'] == 1
|
100
|
+
end
|
101
|
+
|
102
|
+
if ! succeeded
|
103
|
+
raise ConnectionError.new("Could not write to Mixpanel, server responded with #{response_code} returning: '#{response_body}'")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Request takes an endpoint HTTP or HTTPS url, and a Hash of data
|
108
|
+
# to post to that url. It should return a pair of
|
109
|
+
#
|
110
|
+
# [response code, response body]
|
111
|
+
#
|
112
|
+
# as the result of the response. Response code should be nil if
|
113
|
+
# the request never recieves a response for some reason.
|
114
|
+
def request(endpoint, form_data)
|
84
115
|
uri = URI(endpoint)
|
116
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
117
|
+
request.set_form_data(form_data)
|
85
118
|
|
86
119
|
client = Net::HTTP.new(uri.host, uri.port)
|
87
120
|
client.use_ssl = true
|
88
121
|
Mixpanel.with_http(client)
|
89
122
|
|
90
|
-
form_data = { "data" => data, "verbose" => 1 }
|
91
|
-
form_data.merge!("api_key" => api_key) if api_key
|
92
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
93
|
-
request.set_form_data(form_data)
|
94
123
|
response = client.request(request)
|
95
|
-
|
96
|
-
succeeded = false
|
97
|
-
if response.code == '200'
|
98
|
-
result = JSON.load(response.body) rescue {}
|
99
|
-
succeeded = result['status'] == 1
|
100
|
-
end
|
101
|
-
|
102
|
-
if succeeded
|
103
|
-
return true
|
104
|
-
else
|
105
|
-
raise ConnectionError.new("Could not write to Mixpanel, server responded with #{response.code} returning: '#{response.body}'")
|
106
|
-
end
|
124
|
+
[response.code, response.body]
|
107
125
|
end
|
108
126
|
end
|
109
127
|
|
@@ -139,9 +157,22 @@ module Mixpanel
|
|
139
157
|
# consumer automatically sends its buffered events. The Mixpanel
|
140
158
|
# endpoints have a limit of 50 events per HTTP request, but
|
141
159
|
# you can lower the limit if your individual events are very large.
|
142
|
-
|
143
|
-
|
144
|
-
|
160
|
+
#
|
161
|
+
# By default, BufferedConsumer will use a standard Mixpanel
|
162
|
+
# consumer to send the events once the buffer is full (or on calls
|
163
|
+
# to #flush), but you can override this behavior by passing a
|
164
|
+
# block to the constructor, in the same way you might pass a block
|
165
|
+
# to the Mixpanel::Tracker constructor. If a block is passed to
|
166
|
+
# the constructor, the *_endpoint constructor arguments are
|
167
|
+
# ignored.
|
168
|
+
def initialize(events_endpoint=nil, update_endpoint=nil, import_endpoint=nil, max_buffer_length=MAX_LENGTH, &block)
|
169
|
+
@max_length = [max_buffer_length, MAX_LENGTH].min
|
170
|
+
if block
|
171
|
+
@sink = block
|
172
|
+
else
|
173
|
+
consumer = Consumer.new(events_endpoint, update_endpoint, import_endpoint)
|
174
|
+
@sink = consumer.method(:send)
|
175
|
+
end
|
145
176
|
@buffers = {
|
146
177
|
:event => [],
|
147
178
|
:profile_update => [],
|
@@ -162,7 +193,7 @@ module Mixpanel
|
|
162
193
|
flush_type(type)
|
163
194
|
end
|
164
195
|
else
|
165
|
-
@
|
196
|
+
@sink.call(type, message)
|
166
197
|
end
|
167
198
|
end
|
168
199
|
|
@@ -178,7 +209,7 @@ module Mixpanel
|
|
178
209
|
def flush_type(type)
|
179
210
|
@buffers[type].each_slice(@max_length) do |chunk|
|
180
211
|
data = chunk.map {|message| JSON.load(message)['data'] }
|
181
|
-
@
|
212
|
+
@sink.call(type, {'data' => data}.to_json)
|
182
213
|
end
|
183
214
|
@buffers[type] = []
|
184
215
|
end
|
data/lib/mixpanel-ruby/people.rb
CHANGED
@@ -111,13 +111,13 @@ module Mixpanel
|
|
111
111
|
|
112
112
|
# Convenience method- increases the value of a numeric property
|
113
113
|
# by one. Calling #plus_one(distinct_id, property_name) is the same as calling
|
114
|
-
# #increment(distinct_id, {
|
114
|
+
# #increment(distinct_id, {property_name => 1})
|
115
115
|
#
|
116
116
|
# tracker = Mixpanel::Tracker.new
|
117
117
|
# tracker.people.plus_one("12345", "Albums Released")
|
118
118
|
#
|
119
119
|
def plus_one(distinct_id, property_name, ip=nil, optional_params={})
|
120
|
-
increment(distinct_id, {
|
120
|
+
increment(distinct_id, {property_name => 1}, ip, optional_params)
|
121
121
|
end
|
122
122
|
|
123
123
|
# Appends a values to the end of list-valued properties.
|
@@ -177,7 +177,7 @@ module Mixpanel
|
|
177
177
|
def unset(distinct_id, property, ip=nil, optional_params={})
|
178
178
|
message = {
|
179
179
|
'$distinct_id' => distinct_id,
|
180
|
-
'$unset' => [
|
180
|
+
'$unset' => [property]
|
181
181
|
}.merge(optional_params)
|
182
182
|
|
183
183
|
if ip
|
@@ -202,8 +202,8 @@ module Mixpanel
|
|
202
202
|
#
|
203
203
|
def track_charge(distinct_id, amount, properties={}, ip=nil, optional_params={})
|
204
204
|
properties = fix_property_dates(properties)
|
205
|
-
charge_properties = properties.merge({
|
206
|
-
append(distinct_id, {
|
205
|
+
charge_properties = properties.merge({'$amount' => amount})
|
206
|
+
append(distinct_id, {'$transactions' => charge_properties}, ip, optional_params)
|
207
207
|
end
|
208
208
|
|
209
209
|
# Clear all charges from a \Mixpanel people profile
|
@@ -6,12 +6,12 @@ module Mixpanel
|
|
6
6
|
# To track an event, call
|
7
7
|
#
|
8
8
|
# tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
|
9
|
-
# Mixpanel::Tracker.track(a_distinct_id, an_event_name, {
|
9
|
+
# Mixpanel::Tracker.track(a_distinct_id, an_event_name, {properties})
|
10
10
|
#
|
11
11
|
# To send people updates, call
|
12
12
|
#
|
13
13
|
# tracker = Mixpanel::Tracker.new(YOUR_MIXPANEL_TOKEN)
|
14
|
-
# tracker.people.set(a_distinct_id, {
|
14
|
+
# tracker.people.set(a_distinct_id, {properties})
|
15
15
|
#
|
16
16
|
# You can find your project token in the settings dialog for your
|
17
17
|
# project, inside of the Mixpanel web application.
|
@@ -4,85 +4,132 @@ require 'base64'
|
|
4
4
|
require 'mixpanel-ruby/consumer'
|
5
5
|
|
6
6
|
describe Mixpanel::Consumer do
|
7
|
-
before
|
8
|
-
WebMock.reset!
|
9
|
-
@consumer = Mixpanel::Consumer.new
|
10
|
-
end
|
7
|
+
before { WebMock.reset! }
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
shared_examples_for 'consumer' do
|
10
|
+
it 'should send a request to api.mixpanel.com/track on events' do
|
11
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
12
|
+
subject.send(:event, {'data' => 'TEST EVENT MESSAGE'}.to_json)
|
13
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
14
|
+
with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
|
15
|
+
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
it 'should send a request to api.mixpanel.com/people on profile updates' do
|
18
|
+
stub_request(:any, 'https://api.mixpanel.com/engage').to_return({:body => '{"status": 1, "error": null}'})
|
19
|
+
subject.send(:profile_update, {'data' => 'TEST EVENT MESSAGE'}.to_json)
|
20
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/engage').
|
21
|
+
with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should send a request to api.mixpanel.com/import on event imports' do
|
25
|
+
stub_request(:any, 'https://api.mixpanel.com/import').to_return({:body => '{"status": 1, "error": null}'})
|
26
|
+
subject.send(:import, {'data' => 'TEST EVENT MESSAGE', 'api_key' => 'API_KEY','verbose' => '1' }.to_json)
|
27
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
|
28
|
+
with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'api_key' => 'API_KEY', 'verbose' => '1' })
|
29
|
+
end
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
it 'should encode long messages without newlines' do
|
32
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
33
|
+
subject.send(:event, {'data' => 'BASE64-ENCODED VERSION OF BIN. THIS METHOD COMPLIES WITH RFC 2045. LINE FEEDS ARE ADDED TO EVERY 60 ENCODED CHARACTORS. IN RUBY 1.8 WE NEED TO JUST CALL ENCODE64 AND REMOVE THE LINE FEEDS, IN RUBY 1.9 WE CALL STRIC_ENCODED64 METHOD INSTEAD'}.to_json)
|
34
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
35
|
+
with(:body => {'data' => 'IkJBU0U2NC1FTkNPREVEIFZFUlNJT04gT0YgQklOLiBUSElTIE1FVEhPRCBDT01QTElFUyBXSVRIIFJGQyAyMDQ1LiBMSU5FIEZFRURTIEFSRSBBRERFRCBUTyBFVkVSWSA2MCBFTkNPREVEIENIQVJBQ1RPUlMuIElOIFJVQlkgMS44IFdFIE5FRUQgVE8gSlVTVCBDQUxMIEVOQ09ERTY0IEFORCBSRU1PVkUgVEhFIExJTkUgRkVFRFMsIElOIFJVQlkgMS45IFdFIENBTEwgU1RSSUNfRU5DT0RFRDY0IE1FVEhPRCBJTlNURUFEIg==', 'verbose' => '1'})
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should provide thorough information in case mixpanel fails' do
|
39
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:status => 401, :body => "nutcakes"})
|
40
|
+
expect { subject.send(:event, {'data' => 'TEST EVENT MESSAGE'}.to_json) }.to raise_exception('Could not write to Mixpanel, server responded with 401 returning: \'nutcakes\'')
|
41
|
+
end
|
31
42
|
end
|
32
43
|
|
33
|
-
|
34
|
-
|
35
|
-
@consumer.send(:event, { 'data' => 'BASE64-ENCODED VERSION OF BIN. THIS METHOD COMPLIES WITH RFC 2045. LINE FEEDS ARE ADDED TO EVERY 60 ENCODED CHARACTORS. IN RUBY 1.8 WE NEED TO JUST CALL ENCODE64 AND REMOVE THE LINE FEEDS, IN RUBY 1.9 WE CALL STRIC_ENCODED64 METHOD INSTEAD' }.to_json)
|
36
|
-
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
37
|
-
with(:body => { 'data' => 'IkJBU0U2NC1FTkNPREVEIFZFUlNJT04gT0YgQklOLiBUSElTIE1FVEhPRCBDT01QTElFUyBXSVRIIFJGQyAyMDQ1LiBMSU5FIEZFRURTIEFSRSBBRERFRCBUTyBFVkVSWSA2MCBFTkNPREVEIENIQVJBQ1RPUlMuIElOIFJVQlkgMS44IFdFIE5FRUQgVE8gSlVTVCBDQUxMIEVOQ09ERTY0IEFORCBSRU1PVkUgVEhFIExJTkUgRkVFRFMsIElOIFJVQlkgMS45IFdFIENBTEwgU1RSSUNfRU5DT0RFRDY0IE1FVEhPRCBJTlNURUFEIg==', 'verbose' => '1' })
|
44
|
+
context 'raw consumer' do
|
45
|
+
it_behaves_like 'consumer'
|
38
46
|
end
|
39
47
|
|
40
|
-
|
41
|
-
|
42
|
-
|
48
|
+
context 'custom request consumer' do
|
49
|
+
subject do
|
50
|
+
ret = Mixpanel::Consumer.new
|
51
|
+
class << ret
|
52
|
+
attr_reader :called
|
53
|
+
def request(*args)
|
54
|
+
@called = true
|
55
|
+
super(*args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
ret
|
60
|
+
end
|
61
|
+
|
62
|
+
after(:each) do
|
63
|
+
subject.called.should be_true
|
64
|
+
end
|
65
|
+
|
66
|
+
it_behaves_like 'consumer'
|
43
67
|
end
|
68
|
+
|
44
69
|
end
|
45
70
|
|
46
71
|
describe Mixpanel::BufferedConsumer do
|
47
|
-
|
48
|
-
|
49
|
-
@max_length = 10
|
50
|
-
@consumer = Mixpanel::BufferedConsumer.new(nil, nil, nil, @max_length)
|
51
|
-
end
|
72
|
+
let(:max_length) { 10 }
|
73
|
+
before { WebMock.reset! }
|
52
74
|
|
53
|
-
|
54
|
-
|
55
|
-
@consumer.send(:event, {'data' => 'TEST EVENT 1'}.to_json)
|
56
|
-
WebMock.should have_not_requested(:post, 'https://api.mixpanel.com/track')
|
75
|
+
context 'Default BufferedConsumer' do
|
76
|
+
subject { Mixpanel::BufferedConsumer.new(nil, nil, nil, max_length) }
|
57
77
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
78
|
+
it 'should not send a request for a single message until flush is called' do
|
79
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
80
|
+
subject.send(:event, {'data' => 'TEST EVENT 1'}.to_json)
|
81
|
+
WebMock.should have_not_requested(:post, 'https://api.mixpanel.com/track')
|
82
|
+
|
83
|
+
subject.flush()
|
84
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
85
|
+
with(:body => {'data' => 'WyJURVNUIEVWRU5UIDEiXQ==', 'verbose' => '1' })
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should send one message when max_length events are tracked' do
|
89
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
62
90
|
|
63
|
-
|
64
|
-
|
91
|
+
max_length.times do |i|
|
92
|
+
subject.send(:event, {'data' => "x #{i}"}.to_json)
|
93
|
+
end
|
65
94
|
|
66
|
-
|
67
|
-
|
95
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
96
|
+
with(:body => {'data' => 'WyJ4IDAiLCJ4IDEiLCJ4IDIiLCJ4IDMiLCJ4IDQiLCJ4IDUiLCJ4IDYiLCJ4IDciLCJ4IDgiLCJ4IDkiXQ==', 'verbose' => '1' })
|
68
97
|
end
|
69
98
|
|
70
|
-
|
71
|
-
|
99
|
+
it 'should send one message per api key on import' do
|
100
|
+
stub_request(:any, 'https://api.mixpanel.com/import').to_return({:body => '{"status": 1, "error": null}'})
|
101
|
+
subject.send(:import, {'data' => 'TEST EVENT 1', 'api_key' => 'KEY 1'}.to_json)
|
102
|
+
subject.send(:import, {'data' => 'TEST EVENT 1', 'api_key' => 'KEY 2'}.to_json)
|
103
|
+
subject.send(:import, {'data' => 'TEST EVENT 2', 'api_key' => 'KEY 1'}.to_json)
|
104
|
+
subject.send(:import, {'data' => 'TEST EVENT 2', 'api_key' => 'KEY 2'}.to_json)
|
105
|
+
subject.flush
|
106
|
+
|
107
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
|
108
|
+
with(:body => {'data' => 'IlRFU1QgRVZFTlQgMSI=', 'api_key' => 'KEY 1', 'verbose' => '1' })
|
109
|
+
|
110
|
+
WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
|
111
|
+
with(:body => {'data' => 'IlRFU1QgRVZFTlQgMSI=', 'api_key' => 'KEY 2', 'verbose' => '1' })
|
112
|
+
end
|
72
113
|
end
|
73
114
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
115
|
+
context 'BufferedConsumer with block' do
|
116
|
+
let(:messages_seen) { [] }
|
117
|
+
subject do
|
118
|
+
Mixpanel::BufferedConsumer.new(nil, nil, nil, 3) do |type, message|
|
119
|
+
messages_seen << [type, message]
|
120
|
+
end
|
121
|
+
end
|
81
122
|
|
82
|
-
|
83
|
-
|
123
|
+
it 'should call block instead of making default requests on flush' do
|
124
|
+
3.times do |i|
|
125
|
+
subject.send(:event, {'data' => "x #{i}"}.to_json)
|
126
|
+
end
|
127
|
+
|
128
|
+
expect(messages_seen).to match_array(
|
129
|
+
[[:event, "{\"data\":[\"x 0\",\"x 1\",\"x 2\"]}"]]
|
130
|
+
)
|
131
|
+
end
|
84
132
|
|
85
|
-
WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
|
86
|
-
with(:body => {'data' => 'IlRFU1QgRVZFTlQgMSI=', 'api_key' => 'KEY 2', 'verbose' => '1' })
|
87
133
|
end
|
134
|
+
|
88
135
|
end
|
@@ -10,7 +10,7 @@ describe Mixpanel::Events do
|
|
10
10
|
|
11
11
|
@log = []
|
12
12
|
@events = Mixpanel::Events.new('TEST TOKEN') do |type, message|
|
13
|
-
@log << [
|
13
|
+
@log << [type, JSON.load(message)]
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -18,7 +18,7 @@ describe Mixpanel::Events do
|
|
18
18
|
@events.track('TEST ID', 'Test Event', {
|
19
19
|
'Circumstances' => 'During a test'
|
20
20
|
})
|
21
|
-
@log.should eq([[
|
21
|
+
@log.should eq([[:event, 'data' => {
|
22
22
|
'event' => 'Test Event',
|
23
23
|
'properties' => {
|
24
24
|
'Circumstances' => 'During a test',
|
@@ -35,7 +35,7 @@ describe Mixpanel::Events do
|
|
35
35
|
@events.import('API_KEY', 'TEST ID', 'Test Event', {
|
36
36
|
'Circumstances' => 'During a test'
|
37
37
|
})
|
38
|
-
@log.should eq([[
|
38
|
+
@log.should eq([[:import, {
|
39
39
|
'api_key' => 'API_KEY',
|
40
40
|
'data' => {
|
41
41
|
'event' => 'Test Event',
|
@@ -8,7 +8,7 @@ describe Mixpanel::People do
|
|
8
8
|
|
9
9
|
@log = []
|
10
10
|
@people = Mixpanel::People.new('TEST TOKEN') do |type, message|
|
11
|
-
@log << [
|
11
|
+
@log << [type, JSON.load(message)]
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -17,7 +17,7 @@ describe Mixpanel::People do
|
|
17
17
|
'$firstname' => 'David',
|
18
18
|
'$lastname' => 'Bowie',
|
19
19
|
})
|
20
|
-
@log.should eq([[
|
20
|
+
@log.should eq([[:profile_update, 'data' => {
|
21
21
|
'$token' => 'TEST TOKEN',
|
22
22
|
'$distinct_id' => 'TEST ID',
|
23
23
|
'$time' => @time_now.to_i * 1000,
|
@@ -32,7 +32,7 @@ describe Mixpanel::People do
|
|
32
32
|
@people.set("TEST ID", {
|
33
33
|
'created_at' => DateTime.new(2013, 1, 2, 3, 4, 5)
|
34
34
|
})
|
35
|
-
@log.should eq([[
|
35
|
+
@log.should eq([[:profile_update, 'data' => {
|
36
36
|
'$token' => 'TEST TOKEN',
|
37
37
|
'$distinct_id' => 'TEST ID',
|
38
38
|
'$time' => @time_now.to_i * 1000,
|
@@ -47,7 +47,7 @@ describe Mixpanel::People do
|
|
47
47
|
'$firstname' => 'David',
|
48
48
|
'$lastname' => 'Bowie',
|
49
49
|
})
|
50
|
-
@log.should eq([[
|
50
|
+
@log.should eq([[:profile_update, 'data' => {
|
51
51
|
'$token' => 'TEST TOKEN',
|
52
52
|
'$distinct_id' => 'TEST ID',
|
53
53
|
'$time' => @time_now.to_i * 1000,
|
@@ -59,8 +59,8 @@ describe Mixpanel::People do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'should send a well formed engage/add message' do
|
62
|
-
@people.increment("TEST ID", {
|
63
|
-
@log.should eq([[
|
62
|
+
@people.increment("TEST ID", {'Albums Released' => 10})
|
63
|
+
@log.should eq([[:profile_update, 'data' => {
|
64
64
|
'$token' => 'TEST TOKEN',
|
65
65
|
'$distinct_id' => 'TEST ID',
|
66
66
|
'$time' => @time_now.to_i * 1000,
|
@@ -72,7 +72,7 @@ describe Mixpanel::People do
|
|
72
72
|
|
73
73
|
it 'should send an engage/add message with a value of 1' do
|
74
74
|
@people.plus_one("TEST ID", 'Albums Released')
|
75
|
-
@log.should eq([[
|
75
|
+
@log.should eq([[:profile_update, 'data' => {
|
76
76
|
'$token' => 'TEST TOKEN',
|
77
77
|
'$distinct_id' => 'TEST ID',
|
78
78
|
'$time' => @time_now.to_i * 1000,
|
@@ -83,8 +83,8 @@ describe Mixpanel::People do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'should send a well formed engage/append message' do
|
86
|
-
@people.append("TEST ID", {
|
87
|
-
@log.should eq([[
|
86
|
+
@people.append("TEST ID", {'Albums' => 'Diamond Dogs'})
|
87
|
+
@log.should eq([[:profile_update, 'data' => {
|
88
88
|
'$token' => 'TEST TOKEN',
|
89
89
|
'$distinct_id' => 'TEST ID',
|
90
90
|
'$time' => @time_now.to_i * 1000,
|
@@ -95,8 +95,8 @@ describe Mixpanel::People do
|
|
95
95
|
end
|
96
96
|
|
97
97
|
it 'should send a well formed engage/union message' do
|
98
|
-
@people.union("TEST ID", {
|
99
|
-
@log.should eq([[
|
98
|
+
@people.union("TEST ID", {'Albums' => ['Diamond Dogs']})
|
99
|
+
@log.should eq([[:profile_update, 'data' => {
|
100
100
|
'$token' => 'TEST TOKEN',
|
101
101
|
'$distinct_id' => 'TEST ID',
|
102
102
|
'$time' => @time_now.to_i * 1000,
|
@@ -108,11 +108,11 @@ describe Mixpanel::People do
|
|
108
108
|
|
109
109
|
it 'should send a well formed unset message' do
|
110
110
|
@people.unset('TEST ID', 'Albums')
|
111
|
-
@log.should eq([[
|
111
|
+
@log.should eq([[:profile_update, 'data' => {
|
112
112
|
'$token' => 'TEST TOKEN',
|
113
113
|
'$distinct_id' => 'TEST ID',
|
114
114
|
'$time' => @time_now.to_i * 1000,
|
115
|
-
'$unset' => [
|
115
|
+
'$unset' => ['Albums']
|
116
116
|
}]])
|
117
117
|
end
|
118
118
|
|
@@ -121,7 +121,7 @@ describe Mixpanel::People do
|
|
121
121
|
'$time' => DateTime.new(1999,12,24,14, 02, 53),
|
122
122
|
'SKU' => '1234567'
|
123
123
|
})
|
124
|
-
@log.should eq([[
|
124
|
+
@log.should eq([[:profile_update, 'data' => {
|
125
125
|
'$token' => 'TEST TOKEN',
|
126
126
|
'$distinct_id' => 'TEST ID',
|
127
127
|
'$time' => @time_now.to_i * 1000,
|
@@ -137,17 +137,17 @@ describe Mixpanel::People do
|
|
137
137
|
|
138
138
|
it 'should send a well formed engage/unset message for $transaction' do
|
139
139
|
@people.clear_charges("TEST ID")
|
140
|
-
@log.should eq([[
|
140
|
+
@log.should eq([[:profile_update, 'data' => {
|
141
141
|
'$token' => 'TEST TOKEN',
|
142
142
|
'$distinct_id' => 'TEST ID',
|
143
143
|
'$time' => @time_now.to_i * 1000,
|
144
|
-
'$unset' => [
|
144
|
+
'$unset' => ['$transactions']
|
145
145
|
}]])
|
146
146
|
end
|
147
147
|
|
148
148
|
it 'should send a well formed engage/delete message' do
|
149
149
|
@people.delete_user("TEST ID")
|
150
|
-
@log.should eq([[
|
150
|
+
@log.should eq([[:profile_update, 'data' => {
|
151
151
|
'$token' => 'TEST TOKEN',
|
152
152
|
'$distinct_id' => 'TEST ID',
|
153
153
|
'$time' => @time_now.to_i * 1000,
|
@@ -11,21 +11,21 @@ describe Mixpanel::Tracker do
|
|
11
11
|
|
12
12
|
it 'should send an alias message to mixpanel no matter what the consumer is' do
|
13
13
|
WebMock.reset!
|
14
|
-
stub_request(:any, 'https://api.mixpanel.com/track').to_return({
|
14
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
15
15
|
mixpanel = Mixpanel::Tracker.new('TEST TOKEN') {|*args| }
|
16
16
|
mixpanel.alias('TEST ALIAS', 'TEST ID')
|
17
17
|
|
18
18
|
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
19
|
-
with(:body => {
|
19
|
+
with(:body => {:data => 'eyJldmVudCI6IiRjcmVhdGVfYWxpYXMiLCJwcm9wZXJ0aWVzIjp7ImRpc3RpbmN0X2lkIjoiVEVTVCBJRCIsImFsaWFzIjoiVEVTVCBBTElBUyIsInRva2VuIjoiVEVTVCBUT0tFTiJ9fQ==', 'verbose' => '1'})
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'should send a request to the track api with the default consumer' do
|
23
23
|
WebMock.reset!
|
24
|
-
stub_request(:any, 'https://api.mixpanel.com/track').to_return({
|
25
|
-
stub_request(:any, 'https://api.mixpanel.com/engage').to_return({
|
24
|
+
stub_request(:any, 'https://api.mixpanel.com/track').to_return({:body => '{"status": 1, "error": null}'})
|
25
|
+
stub_request(:any, 'https://api.mixpanel.com/engage').to_return({:body => '{"status": 1, "error": null}'})
|
26
26
|
mixpanel = Mixpanel::Tracker.new('TEST TOKEN')
|
27
27
|
|
28
|
-
mixpanel.track('TEST ID', 'TEST EVENT', {
|
28
|
+
mixpanel.track('TEST ID', 'TEST EVENT', {'Circumstances' => 'During test'})
|
29
29
|
|
30
30
|
body = nil
|
31
31
|
WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
|
@@ -50,12 +50,12 @@ describe Mixpanel::Tracker do
|
|
50
50
|
it 'should call a consumer block if one is given' do
|
51
51
|
messages = []
|
52
52
|
mixpanel = Mixpanel::Tracker.new('TEST TOKEN') do |type, message|
|
53
|
-
messages << [
|
53
|
+
messages << [type, JSON.load(message)]
|
54
54
|
end
|
55
55
|
mixpanel.track('ID', 'Event')
|
56
56
|
mixpanel.import('API_KEY', 'ID', 'Import')
|
57
|
-
mixpanel.people.set('ID', {
|
58
|
-
mixpanel.people.append('ID', {
|
57
|
+
mixpanel.people.set('ID', {'k' => 'v'})
|
58
|
+
mixpanel.people.append('ID', {'k' => 'v'})
|
59
59
|
|
60
60
|
expect = [
|
61
61
|
[ :event, 'data' =>
|
@@ -87,14 +87,14 @@ describe Mixpanel::Tracker do
|
|
87
87
|
{ '$token' => 'TEST TOKEN',
|
88
88
|
'$distinct_id' => 'ID',
|
89
89
|
'$time' => @time_now.to_i * 1000,
|
90
|
-
'$set' => {
|
90
|
+
'$set' => {'k' => 'v'}
|
91
91
|
}
|
92
92
|
],
|
93
93
|
[ :profile_update, 'data' =>
|
94
94
|
{ '$token' => 'TEST TOKEN',
|
95
95
|
'$distinct_id' => 'ID',
|
96
96
|
'$time' => @time_now.to_i * 1000,
|
97
|
-
'$append' => {
|
97
|
+
'$append' => {'k' => 'v'}
|
98
98
|
}
|
99
99
|
]
|
100
100
|
]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixpanel-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-03-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- LICENSE
|
72
72
|
- Rakefile
|
73
73
|
- Readme.rdoc
|
74
|
+
- demo/faraday_consumer.rb
|
74
75
|
- demo/out_of_process_consumer.rb
|
75
76
|
- demo/simple_messages.rb
|
76
77
|
- lib/mixpanel-ruby.rb
|