mixpanel-ruby-batch 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 01d0067c75afe5144f31ff9315f920fd737cbf42
4
+ data.tar.gz: b98a606445b7c3fd100686bfa4b8e12c43b569ca
5
+ SHA512:
6
+ metadata.gz: 12bd6258cae973a89ebc793ee392ae2a22b9653d594fdb0d94c8a71daf3054d0ff91af227dc500921c97efb9ab0388153f02cb7825919e25a3711b951eaf5702
7
+ data.tar.gz: c5224def9562c7f2b825ebbd06d79fa9b9756c5c746e8e48d45154f6a5ec136339608c4d5c4f7d70105a41d485f154b0729182cfc0cf4400b954fb9d4de0defa
@@ -0,0 +1,5 @@
1
+ *~
2
+ Gemfile.lock
3
+ html
4
+ mixpanel-ruby*.gem
5
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,190 @@
1
+ Copyright 2015 HealthTeacher, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this work except in compliance with the License.
5
+ You may obtain a copy of the License below, or at:
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+ Apache License
16
+ Version 2.0, January 2004
17
+ http://www.apache.org/licenses/
18
+
19
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
20
+
21
+ 1. Definitions.
22
+
23
+ "License" shall mean the terms and conditions for use, reproduction,
24
+ and distribution as defined by Sections 1 through 9 of this document.
25
+
26
+ "Licensor" shall mean the copyright owner or entity authorized by
27
+ the copyright owner that is granting the License.
28
+
29
+ "Legal Entity" shall mean the union of the acting entity and all
30
+ other entities that control, are controlled by, or are under common
31
+ control with that entity. For the purposes of this definition,
32
+ "control" means (i) the power, direct or indirect, to cause the
33
+ direction or management of such entity, whether by contract or
34
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
35
+ outstanding shares, or (iii) beneficial ownership of such entity.
36
+
37
+ "You" (or "Your") shall mean an individual or Legal Entity
38
+ exercising permissions granted by this License.
39
+
40
+ "Source" form shall mean the preferred form for making modifications,
41
+ including but not limited to software source code, documentation
42
+ source, and configuration files.
43
+
44
+ "Object" form shall mean any form resulting from mechanical
45
+ transformation or translation of a Source form, including but
46
+ not limited to compiled object code, generated documentation,
47
+ and conversions to other media types.
48
+
49
+ "Work" shall mean the work of authorship, whether in Source or
50
+ Object form, made available under the License, as indicated by a
51
+ copyright notice that is included in or attached to the work
52
+ (an example is provided in the Appendix below).
53
+
54
+ "Derivative Works" shall mean any work, whether in Source or Object
55
+ form, that is based on (or derived from) the Work and for which the
56
+ editorial revisions, annotations, elaborations, or other modifications
57
+ represent, as a whole, an original work of authorship. For the purposes
58
+ of this License, Derivative Works shall not include works that remain
59
+ separable from, or merely link (or bind by name) to the interfaces of,
60
+ the Work and Derivative Works thereof.
61
+
62
+ "Contribution" shall mean any work of authorship, including
63
+ the original version of the Work and any modifications or additions
64
+ to that Work or Derivative Works thereof, that is intentionally
65
+ submitted to Licensor for inclusion in the Work by the copyright owner
66
+ or by an individual or Legal Entity authorized to submit on behalf of
67
+ the copyright owner. For the purposes of this definition, "submitted"
68
+ means any form of electronic, verbal, or written communication sent
69
+ to the Licensor or its representatives, including but not limited to
70
+ communication on electronic mailing lists, source code control systems,
71
+ and issue tracking systems that are managed by, or on behalf of, the
72
+ Licensor for the purpose of discussing and improving the Work, but
73
+ excluding communication that is conspicuously marked or otherwise
74
+ designated in writing by the copyright owner as "Not a Contribution."
75
+
76
+ "Contributor" shall mean Licensor and any individual or Legal Entity
77
+ on behalf of whom a Contribution has been received by Licensor and
78
+ subsequently incorporated within the Work.
79
+
80
+ 2. Grant of Copyright License. Subject to the terms and conditions of
81
+ this License, each Contributor hereby grants to You a perpetual,
82
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
83
+ copyright license to reproduce, prepare Derivative Works of,
84
+ publicly display, publicly perform, sublicense, and distribute the
85
+ Work and such Derivative Works in Source or Object form.
86
+
87
+ 3. Grant of Patent License. Subject to the terms and conditions of
88
+ this License, each Contributor hereby grants to You a perpetual,
89
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
90
+ (except as stated in this section) patent license to make, have made,
91
+ use, offer to sell, sell, import, and otherwise transfer the Work,
92
+ where such license applies only to those patent claims licensable
93
+ by such Contributor that are necessarily infringed by their
94
+ Contribution(s) alone or by combination of their Contribution(s)
95
+ with the Work to which such Contribution(s) was submitted. If You
96
+ institute patent litigation against any entity (including a
97
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
98
+ or a Contribution incorporated within the Work constitutes direct
99
+ or contributory patent infringement, then any patent licenses
100
+ granted to You under this License for that Work shall terminate
101
+ as of the date such litigation is filed.
102
+
103
+ 4. Redistribution. You may reproduce and distribute copies of the
104
+ Work or Derivative Works thereof in any medium, with or without
105
+ modifications, and in Source or Object form, provided that You
106
+ meet the following conditions:
107
+
108
+ (a) You must give any other recipients of the Work or
109
+ Derivative Works a copy of this License; and
110
+
111
+ (b) You must cause any modified files to carry prominent notices
112
+ stating that You changed the files; and
113
+
114
+ (c) You must retain, in the Source form of any Derivative Works
115
+ that You distribute, all copyright, patent, trademark, and
116
+ attribution notices from the Source form of the Work,
117
+ excluding those notices that do not pertain to any part of
118
+ the Derivative Works; and
119
+
120
+ (d) If the Work includes a "NOTICE" text file as part of its
121
+ distribution, then any Derivative Works that You distribute must
122
+ include a readable copy of the attribution notices contained
123
+ within such NOTICE file, excluding those notices that do not
124
+ pertain to any part of the Derivative Works, in at least one
125
+ of the following places: within a NOTICE text file distributed
126
+ as part of the Derivative Works; within the Source form or
127
+ documentation, if provided along with the Derivative Works; or,
128
+ within a display generated by the Derivative Works, if and
129
+ wherever such third-party notices normally appear. The contents
130
+ of the NOTICE file are for informational purposes only and
131
+ do not modify the License. You may add Your own attribution
132
+ notices within Derivative Works that You distribute, alongside
133
+ or as an addendum to the NOTICE text from the Work, provided
134
+ that such additional attribution notices cannot be construed
135
+ as modifying the License.
136
+
137
+ You may add Your own copyright statement to Your modifications and
138
+ may provide additional or different license terms and conditions
139
+ for use, reproduction, or distribution of Your modifications, or
140
+ for any such Derivative Works as a whole, provided Your use,
141
+ reproduction, and distribution of the Work otherwise complies with
142
+ the conditions stated in this License.
143
+
144
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
145
+ any Contribution intentionally submitted for inclusion in the Work
146
+ by You to the Licensor shall be under the terms and conditions of
147
+ this License, without any additional terms or conditions.
148
+ Notwithstanding the above, nothing herein shall supersede or modify
149
+ the terms of any separate license agreement you may have executed
150
+ with Licensor regarding such Contributions.
151
+
152
+ 6. Trademarks. This License does not grant permission to use the trade
153
+ names, trademarks, service marks, or product names of the Licensor,
154
+ except as required for reasonable and customary use in describing the
155
+ origin of the Work and reproducing the content of the NOTICE file.
156
+
157
+ 7. Disclaimer of Warranty. Unless required by applicable law or
158
+ agreed to in writing, Licensor provides the Work (and each
159
+ Contributor provides its Contributions) on an "AS IS" BASIS,
160
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
161
+ implied, including, without limitation, any warranties or conditions
162
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
163
+ PARTICULAR PURPOSE. You are solely responsible for determining the
164
+ appropriateness of using or redistributing the Work and assume any
165
+ risks associated with Your exercise of permissions under this License.
166
+
167
+ 8. Limitation of Liability. In no event and under no legal theory,
168
+ whether in tort (including negligence), contract, or otherwise,
169
+ unless required by applicable law (such as deliberate and grossly
170
+ negligent acts) or agreed to in writing, shall any Contributor be
171
+ liable to You for damages, including any direct, indirect, special,
172
+ incidental, or consequential damages of any character arising as a
173
+ result of this License or out of the use or inability to use the
174
+ Work (including but not limited to damages for loss of goodwill,
175
+ work stoppage, computer failure or malfunction, or any and all
176
+ other commercial damages or losses), even if such Contributor
177
+ has been advised of the possibility of such damages.
178
+
179
+ 9. Accepting Warranty or Additional Liability. While redistributing
180
+ the Work or Derivative Works thereof, You may choose to offer,
181
+ and charge a fee for, acceptance of support, warranty, indemnity,
182
+ or other liability obligations and/or rights consistent with this
183
+ License. However, in accepting such obligations, You may act only
184
+ on Your own behalf and on Your sole responsibility, not on behalf
185
+ of any other Contributor, and only if You agree to indemnify,
186
+ defend, and hold each Contributor harmless for any liability
187
+ incurred by, or claims asserted against, such Contributor by reason
188
+ of your accepting any such warranty or additional liability.
189
+
190
+ END OF TERMS AND CONDITIONS
@@ -0,0 +1,103 @@
1
+ # mixpanel-ruby-batch
2
+
3
+ Simple batch operations using mixpanel-ruby
4
+
5
+ *mixpanel-ruby-batch* adds a simple interface for performing batch operations
6
+ using the mixpanel-ruby[https://github.com/mixpanel/mixpanel-ruby] gem.
7
+
8
+ mixpanel-ruby[https://github.com/mixpanel/mixpanel-ruby] already provides a BufferedConsumer class to
9
+ facilitate batch operations:
10
+
11
+ ```ruby
12
+ buffered_consumer = Mixpanel::BufferedConsumer.new
13
+ begin
14
+ tracker = Mixpanel::Tracker.new(YOUR_TOKEN) do |type, message|
15
+ buffered_consumer.send(type, message)
16
+ end
17
+
18
+ tracker.track("Signup Begin")
19
+ tracker.track("Signup Complete", {'User Sign-up Cohort' => 'July 2013'})
20
+ tracker.track("Welcome Email Sent", {
21
+ 'Email Template' => 'Pretty Pink Welcome',
22
+ 'User Sign-up Cohort' => 'July 2013'
23
+ })
24
+
25
+ ensure
26
+ buffered_consumer.flush
27
+ end
28
+ ```
29
+
30
+ *mixpanel-ruby-batch* adds a slightly higher-level API by adding the
31
+ `Mixpanel::Events#track_batch` and `Mixpanel::People#batch` methods.
32
+
33
+ ## Installation
34
+
35
+ ```ruby
36
+ gem install mixpanel-ruby-batch
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ```ruby
42
+ # Tracks a batch of events for a single distinct_id.
43
+ # Events should be passed as an array, with each element either a
44
+ # Hash or a string. Each Hash element should have a single key (the event name,
45
+ # as a string) with the value a Hash of properties. Each string element
46
+ # will be interpreted as an event name with no properties.
47
+
48
+ tracker = Mixpanel::Tracker.new
49
+
50
+ tracker.track_batch("12345", [
51
+ "Signup Begin",
52
+ {
53
+ "Signup Complete" => {
54
+ "User Sign-up Cohort" => "July 2013"
55
+ }
56
+ },
57
+ {
58
+ "Welcome Email Sent" => {
59
+ "Email Template" => "Pretty Pink Welcome",
60
+ "User Sign-up Cohort" => "July 2013"
61
+ }
62
+ }])
63
+
64
+
65
+ # Send a generic batch update to \Mixpanel people analytics.
66
+ # The profile updates should be passed as an array of Hash objects.
67
+ # Each has should have a single string key that is the distinct id
68
+ # on which the perform the updates. The value should be a Hash with valid
69
+ # operation names (e.g. "$set", "$unset") as keys and the appropriate data
70
+ # for each operation as values. For details about the operations and their
71
+ # expected data, see the documentation at # https://mixpanel.com/help/reference/http
72
+
73
+ tracker = Mixpanel::Tracker.new
74
+
75
+ tracker.people.batch([
76
+ {
77
+ "12345" => {
78
+ "$set" => {
79
+ "$firstname" => "David"
80
+ },
81
+ "$unset" => ["Levels Completed"]
82
+ }
83
+ },
84
+ {
85
+ "67890" => {
86
+ "$set" => {
87
+ "$firstname" => "Mick"
88
+ },
89
+ "$unset" => ["Levels Completed"]
90
+ }
91
+ }
92
+ ])
93
+ ```
94
+
95
+ Both methods handle slicing the data into 50-message chunks, so it is safe to
96
+ pass as many messages to either message as memory will allow.
97
+
98
+ ## Additional Information
99
+
100
+ For more information please visit:
101
+
102
+ * Mixpanel Ruby API Integration page[https://mixpanel.com/help/reference/ruby#introduction]
103
+ * mixpanel-ruby documentation[http://mixpanel.github.io/mixpanel-ruby/]
@@ -0,0 +1,7 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec) do |spec|
4
+ spec.pattern = 'spec/**/*_spec.rb'
5
+ end
6
+
7
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ require 'mixpanel-ruby-batch/events.rb'
2
+ require 'mixpanel-ruby-batch/people.rb'
3
+ require 'mixpanel-ruby-batch/version.rb'
@@ -0,0 +1,67 @@
1
+ require 'mixpanel-ruby/events'
2
+ require 'time'
3
+
4
+ module MixpanelRubyBatch
5
+
6
+ module Events
7
+
8
+ # Tracks a batch of events for a single distinct_id.
9
+ # Events should be passed as an array, with each element either a
10
+ # Hash or a string. Each Hash element should have a single key (the event name,
11
+ # as a string) with the value a Hash of properties. Each string element
12
+ # will be interpreted as an event name with no properties.
13
+ #
14
+ # tracker = Mixpanel::Tracker.new
15
+ #
16
+ # tracker.track_batch("12345", [
17
+ # "Signup Begin",
18
+ # {
19
+ # "Signup Complete" => {
20
+ # "User Sign-up Cohort" => "July 2013"
21
+ # }
22
+ # },
23
+ # {
24
+ # "Welcome Email Sent" => {
25
+ # "Email Template" => "Pretty Pink Welcome",
26
+ # "User Sign-up Cohort" => "July 2013"
27
+ # }
28
+ # }])
29
+ def track_batch(distinct_id, events, ip=nil)
30
+ data = events.map do |event_name_or_hash|
31
+ event = event_name_or_hash
32
+ properties = {}
33
+
34
+ if event_name_or_hash.is_a?(Hash)
35
+ event_data = event_name_or_hash.flatten
36
+ event = event_data[0]
37
+ properties = event_data[1]
38
+ end
39
+
40
+ properties = {
41
+ "distinct_id" => distinct_id,
42
+ "token" => @token,
43
+ "time" => Time.now.to_i,
44
+ "mp_lib" => "ruby",
45
+ "$lib_version" => Mixpanel::VERSION
46
+ }.merge(properties)
47
+
48
+ properties["ip"] = ip if ip
49
+
50
+ {
51
+ "event" => event,
52
+ "properties" => properties
53
+ }
54
+ end
55
+
56
+ data.each_slice(50) do |slice|
57
+ message = { "data" => slice }
58
+
59
+ @sink.call(:event, message.to_json)
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ Mixpanel::Events.send(:include, MixpanelRubyBatch::Events)
@@ -0,0 +1,84 @@
1
+ require 'mixpanel-ruby/people'
2
+ require 'json'
3
+ require 'date'
4
+ require 'time'
5
+
6
+ module MixpanelRubyBatch
7
+ module People
8
+
9
+ VALID_OPERATIONS = [
10
+ "$set", "$set_once", "$add", "$append", "$union", "$unset", "$delete"
11
+ ]
12
+ ADDITIVE_OPERATIONS = [
13
+ "$set", "$set_once", "$increment", "$append", "$union", "$track_charge"
14
+ ]
15
+
16
+ # Send a generic batch update to \Mixpanel people analytics.
17
+ # The profile updates should be passed as an array of Hash objects.
18
+ # Each has should have a single string key that is the distinct id
19
+ # on which the perform the updates. The value should be a Hash with valid
20
+ # operation names (e.g. "$set", "$unset") as keys and the appropriate data
21
+ # for each operation as values. For details about the operations and their
22
+ # expected data, see the documentation at # https://mixpanel.com/help/reference/http
23
+ #
24
+ # tracker = Mixpanel::Tracker.new
25
+ #
26
+ # tracker.people.batch([
27
+ # {
28
+ # "12345" => {
29
+ # "$set" => {
30
+ # "$firstname" => "David"
31
+ # },
32
+ # "$unset" => ["Levels Completed"]
33
+ # }
34
+ # },
35
+ # {
36
+ # "67890" => {
37
+ # "$set" => {
38
+ # "$firstname" => "Mick"
39
+ # },
40
+ # "$unset" => ["Levels Completed"]
41
+ # }
42
+ # }
43
+ # ])
44
+ def batch(profile_updates, ip=nil, optional_params={})
45
+ messages = []
46
+ profile_updates.each do |profile_update|
47
+ profile_update.each_pair do |distinct_id, updates|
48
+ updates.select! { |key, value| VALID_OPERATIONS.include?(key) }
49
+ updates.each_pair do |operation, data|
50
+ data = fix_property_dates(data) if ADDITIVE_OPERATIONS.include?(operation)
51
+
52
+ message = {
53
+ "$distinct_id" => distinct_id,
54
+ operation => data
55
+ }.merge(optional_params)
56
+
57
+ message["$ip"] = ip if ip
58
+
59
+ messages << message
60
+ end
61
+ end
62
+ end
63
+
64
+ messages.each_slice(50) { |slice| batch_update(slice) }
65
+ end
66
+
67
+ private
68
+
69
+ def batch_update(messages)
70
+ data = messages.map do |message|
71
+ {
72
+ "$token" => @token,
73
+ "$time" => ((Time.now.to_f) * 1000.0).to_i
74
+ }.merge(message)
75
+ end
76
+
77
+ message = { "data" => data }
78
+
79
+ @sink.call(:profile_update, message.to_json)
80
+ end
81
+ end
82
+ end
83
+
84
+ Mixpanel::People.send(:include, MixpanelRubyBatch::People)
@@ -0,0 +1,3 @@
1
+ module MixpanelRubyBatch
2
+ VERSION = '0.1'
3
+ end
@@ -0,0 +1,19 @@
1
+ require File.join(File.dirname(__FILE__), 'lib/mixpanel-ruby-batch/version.rb')
2
+
3
+ spec = Gem::Specification.new do |spec|
4
+ spec.name = 'mixpanel-ruby-batch'
5
+ spec.version = MixpanelRubyBatch::VERSION
6
+ spec.files = Dir.glob(`git ls-files`.split("\n"))
7
+ spec.require_paths = ['lib']
8
+ spec.summary = 'Simple batch interface for the official mixpanel-ruby gem'
9
+ spec.description = 'Simple batch interface for the official mixpanel-ruby gem'
10
+ spec.authors = [ 'Mark Wise' ]
11
+ spec.email = 'markmediadude@gmail.com'
12
+ spec.homepage = 'https://github.com/HealthTeacher/mixpanel-ruby-batch'
13
+ spec.license = 'Apache License 2.0'
14
+ spec.add_runtime_dependency 'mixpanel-ruby', '~> 1.7.0'
15
+
16
+ spec.add_development_dependency 'rake'
17
+ spec.add_development_dependency 'rspec', '~> 3.0.0'
18
+ spec.add_development_dependency 'webmock', '~> 1.18.0'
19
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ require 'mixpanel-ruby-batch/events.rb'
3
+ require 'mixpanel-ruby/version.rb'
4
+ require 'time'
5
+
6
+ describe Mixpanel::Events 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
+ @events = Mixpanel::Events.new('TEST TOKEN') do |type, message|
13
+ @log << [type, JSON.load(message)]
14
+ end
15
+ end
16
+
17
+ it 'should send a well formed batch track/ message' do
18
+ events = [
19
+ { 'Test Event' => {
20
+ 'Circumstances' => 'During a test'
21
+ }},
22
+ { 'Other Event' => {
23
+ 'Circumstances' => 'During a different test'
24
+ }},
25
+ "Event Without Properties"
26
+ ]
27
+ @events.track_batch('TEST ID', events)
28
+
29
+ expect(@log).to eq([[:event, 'data' => [
30
+ {
31
+ 'event' => 'Test Event',
32
+ 'properties' => {
33
+ 'distinct_id' => 'TEST ID',
34
+ 'token' => 'TEST TOKEN',
35
+ 'time' => @time_now.to_i,
36
+ 'mp_lib' => 'ruby',
37
+ '$lib_version' => Mixpanel::VERSION,
38
+ 'Circumstances' => 'During a test',
39
+ }
40
+ },
41
+ {
42
+ 'event' => 'Other Event',
43
+ 'properties' => {
44
+ 'distinct_id' => 'TEST ID',
45
+ 'token' => 'TEST TOKEN',
46
+ 'time' => @time_now.to_i,
47
+ 'mp_lib' => 'ruby',
48
+ '$lib_version' => Mixpanel::VERSION,
49
+ 'Circumstances' => 'During a different test',
50
+ }
51
+ },
52
+ {
53
+ 'event' => 'Event Without Properties',
54
+ 'properties' => {
55
+ 'distinct_id' => 'TEST ID',
56
+ 'token' => 'TEST TOKEN',
57
+ 'time' => @time_now.to_i,
58
+ 'mp_lib' => 'ruby',
59
+ '$lib_version' => Mixpanel::VERSION
60
+ }
61
+ }
62
+ ]]])
63
+ end
64
+
65
+ it 'should send track/ messages in batches of 50' do
66
+ events = Array.new(75, "Some Event")
67
+ batches = 75.times.map do |i|
68
+ {
69
+ 'event' => 'Some Event',
70
+ 'properties' => {
71
+ 'distinct_id' => 'TEST ID',
72
+ 'token' => 'TEST TOKEN',
73
+ 'time' => @time_now.to_i,
74
+ 'mp_lib' => 'ruby',
75
+ '$lib_version' => Mixpanel::VERSION
76
+ }
77
+ }
78
+ end
79
+
80
+ @events.track_batch('TEST ID', events)
81
+ expect(@log).to eq([
82
+ [:event, { 'data' => batches[0, 50] }],
83
+ [:event, { 'data' => batches[50, 25] }]
84
+ ])
85
+ end
86
+
87
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'mixpanel-ruby-batch/people'
3
+
4
+ describe Mixpanel::People do
5
+ before(:each) do
6
+ @time_now = Time.parse('Jun 6 1972, 16:23:04')
7
+ allow(Time).to receive(:now).and_return(@time_now)
8
+
9
+ @log = []
10
+ @people = Mixpanel::People.new('TEST TOKEN') do |type, message|
11
+ @log << [type, JSON.load(message)]
12
+ end
13
+ end
14
+
15
+ it 'should send a well formed batch engage/set message' do
16
+ @people.batch([{
17
+ "TEST ID" => {
18
+ '$set' => {
19
+ '$firstname' => 'David',
20
+ '$lastname' => 'Bowie',
21
+ },
22
+ '$unset' => ['Levels Completed']
23
+ }
24
+ }])
25
+ expect(@log).to eq([
26
+ [:profile_update, 'data' => [
27
+ {
28
+ '$token' => 'TEST TOKEN',
29
+ '$time' => @time_now.to_i * 1000,
30
+ '$distinct_id' => 'TEST ID',
31
+ '$set' => {
32
+ '$firstname' => 'David',
33
+ '$lastname' => 'Bowie'
34
+ }
35
+ },
36
+ {
37
+ '$token' => 'TEST TOKEN',
38
+ '$time' => @time_now.to_i * 1000,
39
+ '$distinct_id' => 'TEST ID',
40
+ '$unset' => ['Levels Completed']
41
+ },
42
+ ]
43
+ ]])
44
+ end
45
+
46
+ it 'should send batch engage/ message in batches of 50' do
47
+ profile_updates = 75.times.map do |i|
48
+ { "TEST ID" => { '$set' => { "prop_#{i}" => 'David' } } }
49
+ end
50
+
51
+ batches = 75.times.map do |i|
52
+ {
53
+ '$token' => 'TEST TOKEN',
54
+ '$distinct_id' => 'TEST ID',
55
+ '$time' => @time_now.to_i * 1000,
56
+ '$set' => { "prop_#{i}" => 'David' }
57
+ }
58
+ end
59
+
60
+ @people.batch(profile_updates)
61
+ expect(@log).to eq([
62
+ [:profile_update, 'data' => batches[0, 50]],
63
+ [:profile_update, 'data' => batches[50, 25]]
64
+ ])
65
+ end
66
+
67
+ it 'should reject invalid operations' do
68
+ @people.batch([{
69
+ 'TEST ID' => {
70
+ '$set' => {
71
+ '$firstname' => 'David',
72
+ '$lastname' => 'Bowie',
73
+ },
74
+ '$foo' => {
75
+ '$bar' => 'baz',
76
+ }
77
+ }
78
+ }])
79
+ expect(@log).to eq([[:profile_update, 'data' => [{
80
+ '$token' => 'TEST TOKEN',
81
+ '$distinct_id' => 'TEST ID',
82
+ '$time' => @time_now.to_i * 1000,
83
+ '$set' => {
84
+ '$firstname' => 'David',
85
+ '$lastname' => 'Bowie'
86
+ }
87
+ }]]])
88
+ end
89
+
90
+ end
@@ -0,0 +1,15 @@
1
+ require 'json'
2
+ require 'webmock/rspec'
3
+
4
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
5
+ RSpec.configure do |config|
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+ config.raise_errors_for_deprecations!
9
+
10
+ # Run specs in random order to surface order dependencies. If you find an
11
+ # order dependency and want to debug it, you can fix the order by providing
12
+ # the seed, which is printed after each run.
13
+ # --seed 1234
14
+ config.order = 'random'
15
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mixpanel-ruby-batch
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Mark Wise
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mixpanel-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.7.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.7.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.18.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.18.0
69
+ description: Simple batch interface for the official mixpanel-ruby gem
70
+ email: markmediadude@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - .gitignore
76
+ - .rspec
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - lib/mixpanel-ruby-batch.rb
82
+ - lib/mixpanel-ruby-batch/events.rb
83
+ - lib/mixpanel-ruby-batch/people.rb
84
+ - lib/mixpanel-ruby-batch/version.rb
85
+ - mixpanel-ruby.gemspec
86
+ - spec/mixpanel-ruby/events_spec.rb
87
+ - spec/mixpanel-ruby/people_spec.rb
88
+ - spec/spec_helper.rb
89
+ homepage: https://github.com/HealthTeacher/mixpanel-ruby-batch
90
+ licenses:
91
+ - Apache License 2.0
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.2.2
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Simple batch interface for the official mixpanel-ruby gem
113
+ test_files: []