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.
@@ -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. It's straightforward to
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
@@ -39,7 +39,7 @@ class OutOfProcessExample
39
39
 
40
40
  100.times do |i|
41
41
  event = 'Tick'
42
- mixpanel_tracker.track(distinct_id, event, { 'Tick Number' => i })
42
+ mixpanel_tracker.track(distinct_id, event, {'Tick Number' => i})
43
43
  puts "tick #{i}"
44
44
  end
45
45
 
@@ -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::use_ssl that configures the Net::HTTP object.
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::use_ssl do |http|
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, [ type, message ].to_json)
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
- }[ type ]
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
- def initialize(events_endpoint=nil, update_endpoint=nil, import_endpoint=nil, max_buffer_length=MAX_LENGTH)
143
- @max_length = [ max_buffer_length, MAX_LENGTH ].min
144
- @consumer = Consumer.new(events_endpoint, update_endpoint, import_endpoint)
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
- @consumer.send(type, message)
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
- @consumer.send(type, {'data' => data}.to_json)
212
+ @sink.call(type, {'data' => data}.to_json)
182
213
  end
183
214
  @buffers[type] = []
184
215
  end
@@ -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, { property_name => 1 })
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, { property_name => 1 }, ip, optional_params)
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' => [ property ]
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({ '$amount' => amount })
206
- append(distinct_id, { '$transactions' => charge_properties }, ip, optional_params)
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, { properties })
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, { properties })
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.
@@ -1,3 +1,3 @@
1
1
  module Mixpanel
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -4,85 +4,132 @@ require 'base64'
4
4
  require 'mixpanel-ruby/consumer'
5
5
 
6
6
  describe Mixpanel::Consumer do
7
- before(:each) do
8
- WebMock.reset!
9
- @consumer = Mixpanel::Consumer.new
10
- end
7
+ before { WebMock.reset! }
11
8
 
12
- it 'should send a request to api.mixpanel.com/track on events' do
13
- stub_request(:any, 'https://api.mixpanel.com/track').to_return({ :body => '{"status": 1, "error": null}' })
14
- @consumer.send(:event, {'data' => 'TEST EVENT MESSAGE'}.to_json)
15
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
16
- with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
17
- end
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
- it 'should send a request to api.mixpanel.com/people on profile updates' do
20
- stub_request(:any, 'https://api.mixpanel.com/engage').to_return({ :body => '{"status": 1, "error": null}' })
21
- @consumer.send(:profile_update, {'data' => 'TEST EVENT MESSAGE'}.to_json)
22
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/engage').
23
- with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'verbose' => '1' })
24
- end
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
- it 'should send a request to api.mixpanel.com/import on event imports' do
27
- stub_request(:any, 'https://api.mixpanel.com/import').to_return({ :body => '{"status": 1, "error": null}' })
28
- @consumer.send(:import, {'data' => 'TEST EVENT MESSAGE', 'api_key' => 'API_KEY','verbose' => '1' }.to_json)
29
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
30
- with(:body => {'data' => 'IlRFU1QgRVZFTlQgTUVTU0FHRSI=', 'api_key' => 'API_KEY', 'verbose' => '1' })
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
- it 'should encode long messages without newlines' do
34
- stub_request(:any, 'https://api.mixpanel.com/track').to_return({ :body => '{"status": 1, "error": null}' })
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
- it 'should provide thorough information in case mixpanel fails' do
41
- stub_request(:any, 'https://api.mixpanel.com/track').to_return({ :status => 401, :body => "nutcakes" })
42
- expect { @consumer.send(:event, {'data' => 'TEST EVENT MESSAGE'}.to_json) }.to raise_exception('Could not write to Mixpanel, server responded with 401 returning: \'nutcakes\'')
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
- before(:each) do
48
- WebMock.reset!
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
- it 'should not send a request for a single message until flush is called' do
54
- stub_request(:any, 'https://api.mixpanel.com/track').to_return({ :body => '{"status": 1, "error": null}' })
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
- @consumer.flush()
59
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
60
- with(:body => {'data' => 'WyJURVNUIEVWRU5UIDEiXQ==', 'verbose' => '1' })
61
- end
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
- it 'should send one message when max_length events are tracked' do
64
- stub_request(:any, 'https://api.mixpanel.com/track').to_return({ :body => '{"status": 1, "error": null}' })
91
+ max_length.times do |i|
92
+ subject.send(:event, {'data' => "x #{i}"}.to_json)
93
+ end
65
94
 
66
- @max_length.times do |i|
67
- @consumer.send(:event, {'data' => "x #{i}"}.to_json)
95
+ WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
96
+ with(:body => {'data' => 'WyJ4IDAiLCJ4IDEiLCJ4IDIiLCJ4IDMiLCJ4IDQiLCJ4IDUiLCJ4IDYiLCJ4IDciLCJ4IDgiLCJ4IDkiXQ==', 'verbose' => '1' })
68
97
  end
69
98
 
70
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/track').
71
- with(:body => {'data' => 'WyJ4IDAiLCJ4IDEiLCJ4IDIiLCJ4IDMiLCJ4IDQiLCJ4IDUiLCJ4IDYiLCJ4IDciLCJ4IDgiLCJ4IDkiXQ==', 'verbose' => '1' })
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
- it 'should send one message per api key on import' do
75
- stub_request(:any, 'https://api.mixpanel.com/import').to_return({ :body => '{"status": 1, "error": null}' })
76
- @consumer.send(:import, {'data' => 'TEST EVENT 1', 'api_key' => 'KEY 1'}.to_json)
77
- @consumer.send(:import, {'data' => 'TEST EVENT 1', 'api_key' => 'KEY 2'}.to_json)
78
- @consumer.send(:import, {'data' => 'TEST EVENT 2', 'api_key' => 'KEY 1'}.to_json)
79
- @consumer.send(:import, {'data' => 'TEST EVENT 2', 'api_key' => 'KEY 2'}.to_json)
80
- @consumer.flush
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
- WebMock.should have_requested(:post, 'https://api.mixpanel.com/import').
83
- with(:body => {'data' => 'IlRFU1QgRVZFTlQgMSI=', 'api_key' => 'KEY 1', 'verbose' => '1' })
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 << [ type, JSON.load(message) ]
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([[ :event, 'data' => {
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([[ :import, {
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 << [ type, JSON.load(message) ]
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([[ :profile_update, 'data' => {
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([[ :profile_update, 'data' => {
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([[ :profile_update, 'data' => {
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", { 'Albums Released' => 10 })
63
- @log.should eq([[ :profile_update, 'data' => {
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([[ :profile_update, 'data' => {
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", { 'Albums' => 'Diamond Dogs' })
87
- @log.should eq([[ :profile_update, 'data' => {
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", { 'Albums' => ['Diamond Dogs'] })
99
- @log.should eq([[ :profile_update, 'data' => {
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([[ :profile_update, 'data' => {
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' => [ 'Albums' ]
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([[ :profile_update, 'data' => {
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([[ :profile_update, 'data' => {
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' => [ '$transactions' ]
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([[ :profile_update, 'data' => {
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({ :body => '{"status": 1, "error": null}' })
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 => { :data => 'eyJldmVudCI6IiRjcmVhdGVfYWxpYXMiLCJwcm9wZXJ0aWVzIjp7ImRpc3RpbmN0X2lkIjoiVEVTVCBJRCIsImFsaWFzIjoiVEVTVCBBTElBUyIsInRva2VuIjoiVEVTVCBUT0tFTiJ9fQ==', 'verbose' => '1' })
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({ :body => '{"status": 1, "error": null}' })
25
- stub_request(:any, 'https://api.mixpanel.com/engage').to_return({ :body => '{"status": 1, "error": null}' })
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', { 'Circumstances' => 'During test' })
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 << [ type, JSON.load(message) ]
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', { 'k' => 'v' })
58
- mixpanel.people.append('ID', { 'k' => 'v' })
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' => { 'k' => 'v' }
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' => { 'k' => 'v' }
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.2.0
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: 2013-10-23 00:00:00.000000000 Z
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