mixpanel_client 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -21,26 +21,46 @@ or if you use a Gemfile
21
21
  client = Mixpanel::Client.new(config)
22
22
 
23
23
  data = client.request('events/properties', {
24
- # Available options
25
- event: '["test-event"]',
26
- name: 'hello',
24
+ event: 'splash features',
25
+ name: 'feature',
27
26
  values: '["uno", "dos"]',
28
- timezone: '-8',
29
- type: 'general',
30
- unit: 'hour',
31
- interval: 24,
27
+ type: 'unique',
28
+ unit: 'day',
29
+ interval: 7,
32
30
  limit: 5,
33
- bucket: 'contents',
34
- from_date: '2011-08-11',
35
- to_date: '2011-08-12',
36
- on: 'properties["product_id"]',
37
- where: '1 in properties["product_id"]',
38
- buckets: '5',
39
- # etc.
40
31
  })
41
32
 
42
33
  puts data.inspect
43
34
 
35
+ ## Parallel
36
+
37
+ require 'rubygems'
38
+ require 'mixpanel_client'
39
+
40
+ config = {api_key: 'changeme', api_secret: 'changeme', parallel: true}
41
+ client = Mixpanel::Client.new(config)
42
+
43
+ first_request = client.request('events/properties', {
44
+ ...
45
+ })
46
+
47
+ second_request = client.request('events/properties', {
48
+ ...
49
+ })
50
+
51
+ third_request = client.request('events/properties', {
52
+ ...
53
+ })
54
+
55
+ ...
56
+
57
+ client.run_parallel_requests
58
+
59
+ puts first_request.response.handled_response
60
+ puts second_request.response.handled_response
61
+ puts third_request.response.handled_response
62
+
63
+
44
64
  ## Development
45
65
  List of rake tasks.
46
66
 
@@ -74,6 +94,10 @@ Create tag v2.0.2 and build and push mixpanel_client-2.0.2.gem to Rubygems
74
94
 
75
95
  ## Changelog
76
96
 
97
+
98
+ ### v3.1.0
99
+ * Parallel requests option.
100
+
77
101
  ### v.3.0.0
78
102
  * NOTE: This version breaks backwards compatibility.
79
103
  * Use a regular ruby hash instead of metaprogramming for mixpanel options.
@@ -13,7 +13,7 @@ module Mixpanel
13
13
  DATA_URI = 'https://data.mixpanel.com/api/2.0'
14
14
 
15
15
  attr_reader :uri
16
- attr_accessor :api_key, :api_secret
16
+ attr_accessor :api_key, :api_secret, :parallel
17
17
 
18
18
  # Configure the client
19
19
  #
@@ -25,6 +25,7 @@ module Mixpanel
25
25
  def initialize(config)
26
26
  @api_key = config[:api_key]
27
27
  @api_secret = config[:api_secret]
28
+ @parallel = config[:parallel] || false
28
29
  end
29
30
 
30
31
  # Return mixpanel data as a JSON object or CSV string
@@ -47,9 +48,41 @@ module Mixpanel
47
48
  def request(resource, options)
48
49
  @format = options[:format] || :json
49
50
  @uri = URI.mixpanel(resource, normalize_options(options))
50
- response = URI.get(@uri)
51
- response = %Q|[#{response.split("\n").join(',')}]| if resource == 'export'
52
- Utils.to_hash(response, @format)
51
+ if @parallel
52
+ parallel_request = prepare_parallel_request
53
+ hydra.queue parallel_request
54
+ parallel_request
55
+ else
56
+ response = URI.get(@uri)
57
+ response = %Q|[#{response.split("\n").join(',')}]| if resource == 'export'
58
+ Utils.to_hash(response, @format)
59
+ end
60
+ end
61
+
62
+ def prepare_parallel_request
63
+ request = ::Typhoeus::Request.new(@uri)
64
+ request.on_complete do |response|
65
+ if response.success?
66
+ Utils.to_hash(response.body, @format)
67
+ elsif response.timed_out?
68
+ raise TimeoutError
69
+ elsif response.code == 0
70
+ # Could not get an http response, something's wrong.
71
+ raise HTTPError, response.curl_error_message
72
+ else
73
+ # Received a non-successful http response.
74
+ raise HTTPError, response.body.present? ? JSON.parse(response.body)['error'] : response.code.to_s
75
+ end
76
+ end
77
+ request
78
+ end
79
+
80
+ def run_parallel_requests
81
+ hydra.run
82
+ end
83
+
84
+ def hydra
85
+ @hydra ||= ::Typhoeus::Hydra.new
53
86
  end
54
87
 
55
88
  private
@@ -10,5 +10,6 @@ module Mixpanel
10
10
  # URI related exceptions
11
11
  class Error < StandardError; end
12
12
  class HTTPError < Error; end
13
+ class TimeoutError < Error; end
13
14
  class ParseError < Error; end
14
15
  end
@@ -10,6 +10,6 @@ module Mixpanel
10
10
  # Return metrics from Mixpanel Data API
11
11
  class Client
12
12
  # Mixpanel::Client library version
13
- VERSION = '3.0.0'
13
+ VERSION = '3.1.0'
14
14
  end
15
15
  end
data/manual_test/basic.rb CHANGED
@@ -6,14 +6,13 @@ require 'yaml'
6
6
 
7
7
  config = YAML.load_file(File.dirname(__FILE__) + '/../config/mixpanel.yml')['mixpanel']
8
8
 
9
- client = Mixpanel::Client.new(config)
9
+ client = Mixpanel::Client.new({api_key: config['api_key'], api_secret: config['api_secret']})
10
10
 
11
- data = client.request do
12
- resource 'events/properties'
13
- event '["test-event"]'
14
- type 'general'
15
- unit 'hour'
16
- name 'test'
17
- end
11
+ data = client.request('events/properties', {
12
+ event: '["test-event"]',
13
+ type: 'general',
14
+ unit: 'hour',
15
+ name: 'test'
16
+ })
18
17
 
19
18
  puts data.inspect
@@ -0,0 +1,25 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'mixpanel_client'
5
+ require 'yaml'
6
+ require 'typhoeus'
7
+
8
+ config = YAML.load_file(File.dirname(__FILE__) + '/../config/mixpanel.yml')['mixpanel']
9
+
10
+ client = Mixpanel::Client.new({:api_key => config['api_key'], :api_secret => config['api_secret'], :parallel => true})
11
+
12
+ f = client.request('events/top', {
13
+ :type => 'general'
14
+ })
15
+
16
+
17
+ s = client.request('events/names', {
18
+ :type => 'general'
19
+ })
20
+
21
+ client.run_parallel_requests
22
+
23
+ puts f.response.handled_response.inspect
24
+ puts s.response.handled_response.inspect
25
+
@@ -18,11 +18,11 @@ Gem::Specification.new do |s|
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ['lib']
21
-
22
21
  s.add_runtime_dependency('json', '~> 1.6') if RUBY_VERSION < '1.9'
22
+ s.add_runtime_dependency('typhoeus', '~> 0.5.4')
23
23
  s.add_development_dependency('bundler', '>=1.2')
24
24
  s.add_development_dependency('rake', '>=0.9.2.2')
25
25
  s.add_development_dependency('rdoc', '>=3.11')
26
26
  s.add_development_dependency('rspec', '>=2.5.0')
27
- s.add_development_dependency('webmock', '>=1.6.2')
27
+ s.add_development_dependency('webmock', '>=1.9.0')
28
28
  end
@@ -10,6 +10,14 @@ describe Mixpanel::Client do
10
10
  it 'should not raise an exception if a hash is given' do
11
11
  Mixpanel::Client.new('api_key' => 'test_key', 'api_secret' => 'test_secret').should_not raise_error(ArgumentError)
12
12
  end
13
+
14
+ it 'should set a parallel option as false by default' do
15
+ Mixpanel::Client.new(:api_key => 'test_key', :api_secret => 'test_secret').parallel.should == false
16
+ end
17
+
18
+ it 'should be able to set a parallel option when passed' do
19
+ Mixpanel::Client.new(:api_key => 'test_key', :api_secret => 'test_secret', :parallel => true).parallel.should == true
20
+ end
13
21
  end
14
22
 
15
23
  context 'when making an invalid request' do
@@ -50,6 +58,76 @@ describe Mixpanel::Client do
50
58
  })
51
59
  data.should == {"events"=>[], "type"=>"general"}
52
60
  end
61
+
62
+ context "with parallel option enabled" do
63
+ before :all do
64
+ @parallel_client = Mixpanel::Client.new(:api_key => 'test_key', :api_secret => 'test_secret', :parallel => true)
65
+ end
66
+
67
+ it "should return Typhoeus::Request" do
68
+ # Stub Mixpanel request
69
+ stub_request(:get, /^#{@uri}.*/).to_return(:body => '{"legend_size": 0, "data": {"series": [], "values": {}}}')
70
+
71
+ # No endpoint
72
+ data = @parallel_client.request('events', {
73
+ :event => '["test-event"]',
74
+ :unit => 'hour',
75
+ :interval => 24
76
+ })
77
+ data.should be_a Typhoeus::Request
78
+ end
79
+
80
+ describe '#hydra' do
81
+ it 'should return a Typhoeus::Hydra object' do
82
+ @parallel_client.hydra.should be_a Typhoeus::Hydra
83
+ end
84
+ end
85
+
86
+ describe '#run_parallel_requests' do
87
+ it 'should run queued requests' do
88
+ # Stub Mixpanel request
89
+ stub_request(:any, /^#{@uri}.*/).to_return(:body => '{"legend_size": 1, "data": {"series": ["2010-05-29","2010-05-30","2010-05-31"],
90
+ "values": {
91
+ "account-page": {"2010-05-30": 1},
92
+ "splash features": {"2010-05-29": 6,
93
+ "2010-05-30": 4,
94
+ "2010-05-31": 5
95
+ }
96
+ }
97
+ }
98
+ }')
99
+
100
+
101
+ stub_request(:any, /^#{@uri}.*secondevent.*/).to_return(:body => '{"legend_size": 2, "data": {"series": ["2010-05-29","2010-05-30","2010-05-31"],
102
+ "values": {
103
+ "account-page": {"2010-05-30": 2},
104
+ "splash features": {"2010-05-29": 8,
105
+ "2010-05-30": 6,
106
+ "2010-05-31": 7
107
+ }
108
+ }
109
+ }
110
+ }')
111
+
112
+ first_request = @parallel_client.request('events', {
113
+ :event => '["firstevent"]',
114
+ :unit => 'day'
115
+ })
116
+
117
+
118
+ second_request = @parallel_client.request('events', {
119
+ :event => '["secondevent"]',
120
+ :unit => 'day'
121
+ })
122
+
123
+ @parallel_client.run_parallel_requests
124
+
125
+ first_request.response.handled_response.should == {"data"=>{"series"=>["2010-05-29", "2010-05-30", "2010-05-31"], "values"=>{"splash features"=>{"2010-05-29"=>6, "2010-05-30"=>4, "2010-05-31"=>5}, "account-page"=>{"2010-05-30"=>1}}}, "legend_size"=>1}
126
+
127
+ second_request.response.handled_response.should == {"data"=>{"series"=>["2010-05-29", "2010-05-30", "2010-05-31"], "values"=>{"splash features"=>{"2010-05-29"=>8, "2010-05-30"=>6, "2010-05-31"=>7}, "account-page"=>{"2010-05-30"=>2}}}, "legend_size"=>2}
128
+ end
129
+ end
130
+ end
53
131
  end
54
132
 
55
133
  describe '#hash_args' do
@@ -65,4 +143,5 @@ describe Mixpanel::Client do
65
143
  Mixpanel::Client::Utils.to_hash('{"a" : "ey", "b" : "bee"}', :json).should == {'a' => 'ey', 'b' => 'bee'}
66
144
  end
67
145
  end
146
+
68
147
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixpanel_client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
+ - 1
8
9
  - 0
9
- - 0
10
- version: 3.0.0
10
+ version: 3.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Keolo Keagy
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-09-22 00:00:00 Z
18
+ date: 2013-02-05 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: json
@@ -33,9 +33,25 @@ dependencies:
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
- name: bundler
36
+ name: typhoeus
37
37
  prerelease: false
38
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ - 5
47
+ - 4
48
+ version: 0.5.4
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: bundler
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
39
55
  none: false
40
56
  requirements:
41
57
  - - ">="
@@ -46,11 +62,11 @@ dependencies:
46
62
  - 2
47
63
  version: "1.2"
48
64
  type: :development
49
- version_requirements: *id002
65
+ version_requirements: *id003
50
66
  - !ruby/object:Gem::Dependency
51
67
  name: rake
52
68
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
69
+ requirement: &id004 !ruby/object:Gem::Requirement
54
70
  none: false
55
71
  requirements:
56
72
  - - ">="
@@ -63,11 +79,11 @@ dependencies:
63
79
  - 2
64
80
  version: 0.9.2.2
65
81
  type: :development
66
- version_requirements: *id003
82
+ version_requirements: *id004
67
83
  - !ruby/object:Gem::Dependency
68
84
  name: rdoc
69
85
  prerelease: false
70
- requirement: &id004 !ruby/object:Gem::Requirement
86
+ requirement: &id005 !ruby/object:Gem::Requirement
71
87
  none: false
72
88
  requirements:
73
89
  - - ">="
@@ -78,11 +94,11 @@ dependencies:
78
94
  - 11
79
95
  version: "3.11"
80
96
  type: :development
81
- version_requirements: *id004
97
+ version_requirements: *id005
82
98
  - !ruby/object:Gem::Dependency
83
99
  name: rspec
84
100
  prerelease: false
85
- requirement: &id005 !ruby/object:Gem::Requirement
101
+ requirement: &id006 !ruby/object:Gem::Requirement
86
102
  none: false
87
103
  requirements:
88
104
  - - ">="
@@ -94,23 +110,23 @@ dependencies:
94
110
  - 0
95
111
  version: 2.5.0
96
112
  type: :development
97
- version_requirements: *id005
113
+ version_requirements: *id006
98
114
  - !ruby/object:Gem::Dependency
99
115
  name: webmock
100
116
  prerelease: false
101
- requirement: &id006 !ruby/object:Gem::Requirement
117
+ requirement: &id007 !ruby/object:Gem::Requirement
102
118
  none: false
103
119
  requirements:
104
120
  - - ">="
105
121
  - !ruby/object:Gem::Version
106
- hash: 11
122
+ hash: 51
107
123
  segments:
108
124
  - 1
109
- - 6
110
- - 2
111
- version: 1.6.2
125
+ - 9
126
+ - 0
127
+ version: 1.9.0
112
128
  type: :development
113
- version_requirements: *id006
129
+ version_requirements: *id007
114
130
  description: Simple ruby client interface to the Mixpanel API.
115
131
  email:
116
132
  - keolo@dreampointmedia.com
@@ -136,6 +152,7 @@ files:
136
152
  - lib/mixpanel/version.rb
137
153
  - lib/mixpanel_client.rb
138
154
  - manual_test/basic.rb
155
+ - manual_test/parallel.rb
139
156
  - mixpanel_client.gemspec
140
157
  - spec/mixpanel_client/events_externalspec.rb
141
158
  - spec/mixpanel_client/mixpanel_client_spec.rb