mixpanel 1.0.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +42 -1
- data/Rakefile +5 -4
- data/lib/mixpanel/tracker/middleware.rb +12 -5
- data/mixpanel.gemspec +5 -2
- data/spec/mixpanel/tracker/middleware_spec.rb +76 -48
- data/spec/mixpanel/tracker_spec.rb +1 -1
- metadata +31 -15
data/README.rdoc
CHANGED
@@ -28,6 +28,12 @@ If you want to use the asynchronous version of Mixpanel's javascript API
|
|
28
28
|
|
29
29
|
config.middleware.use "Mixpanel::Tracker::Middleware", "YOUR_MIXPANEL_API_TOKEN", :async => true
|
30
30
|
|
31
|
+
By default the scripts are inserted into the head of the html response. If you'd prefer the scripts to run after all rendering has completed you can set the insert_js_last flag and they'll be added at the end of the body tag. This will work whether or not you opt for the aynchronous version of the API. However, when inserting js into an ajax response it will have no effect:
|
32
|
+
|
33
|
+
Rails::Initializer.run do |config|
|
34
|
+
|
35
|
+
config.middleware.use "Mixpanel::Tracker::Middleware", "YOUR_MIXPANEL_API_TOKEN", :async => true, :insert_js_last => true
|
36
|
+
|
31
37
|
In your application_controller class add a method to instance mixpanel.
|
32
38
|
|
33
39
|
before_filter :initialize_mixpanel
|
@@ -51,6 +57,36 @@ To execute any javascript API call
|
|
51
57
|
@mixpanel.append_api("register", {:some => "property"})
|
52
58
|
@mixpanel.append_api("identify", "Unique Identifier")
|
53
59
|
|
60
|
+
== Resque and Rails example
|
61
|
+
|
62
|
+
If you don't want to use the built in Mixpanel Gem async feature bellow there is an example about how to make async calls using Resque.
|
63
|
+
|
64
|
+
{Resque is a Redis-backed Ruby library for creating background jobs}[https://github.com/defunkt/resque]
|
65
|
+
|
66
|
+
class MixpanelTrackEventJob
|
67
|
+
@queue = :slow
|
68
|
+
|
69
|
+
def mixpanel(request_env)
|
70
|
+
Mixpanel.new(MIXPANEL_TOKEN, request_env)
|
71
|
+
end
|
72
|
+
|
73
|
+
def perform(name, params, request_env)
|
74
|
+
mixpanel(request_env).track_event(name, params)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class UsersController < ApplicationController
|
79
|
+
def create
|
80
|
+
@user = User.new(params[:user])
|
81
|
+
|
82
|
+
if @user.save
|
83
|
+
MixpanelTrackEventJob.enqueue("Sign up", {:invited => params[:invited]}, request.env)
|
84
|
+
redirect_to user_root_path
|
85
|
+
else
|
86
|
+
render :new
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
54
90
|
|
55
91
|
== Notes
|
56
92
|
|
@@ -64,10 +100,15 @@ For a short term this method will be accepted but it will be deprecated soon.
|
|
64
100
|
|
65
101
|
Mixpanel.new
|
66
102
|
|
103
|
+
== Collaborations
|
104
|
+
|
105
|
+
All collaborations are welcome to this project, please fork and make a pull request.
|
106
|
+
|
67
107
|
== Collaborators and Maintainers
|
68
108
|
|
69
109
|
* {Alvaro Gil}[https://github.com/zevarito] (Author)
|
70
110
|
* {Nathan Baxter}[https://github.com/LogicWolfe]
|
71
111
|
* {Jake Mallory}[https://github.com/tinomen]
|
72
112
|
* {Logan Bowers}[https://github.com/loganb]
|
73
|
-
* {jakemack}
|
113
|
+
* {jakemack}[https://github.com/jakemack]
|
114
|
+
* {James Ferguson}[https://github.com/JamesFerguson]
|
data/Rakefile
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec/core/rake_task'
|
2
3
|
|
3
4
|
task :default => :spec
|
4
5
|
|
5
6
|
desc "Run all examples"
|
6
|
-
|
7
|
-
t.
|
8
|
-
t.
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
t.rspec_opts = ["-c -fs"]
|
9
|
+
t.pattern = 'spec/**/*_spec.rb'
|
9
10
|
end
|
@@ -7,7 +7,8 @@ module Mixpanel
|
|
7
7
|
@app = app
|
8
8
|
@token = mixpanel_token
|
9
9
|
@options = {
|
10
|
-
:async => false
|
10
|
+
:async => false,
|
11
|
+
:insert_js_last => false
|
11
12
|
}.merge(options)
|
12
13
|
end
|
13
14
|
|
@@ -16,9 +17,11 @@ module Mixpanel
|
|
16
17
|
|
17
18
|
@status, @headers, @response = @app.call(env)
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
if is_trackable_response?
|
21
|
+
update_response!
|
22
|
+
update_content_length!
|
23
|
+
delete_event_queue!
|
24
|
+
end
|
22
25
|
|
23
26
|
[@status, @headers, @response]
|
24
27
|
end
|
@@ -28,7 +31,7 @@ module Mixpanel
|
|
28
31
|
def update_response!
|
29
32
|
@response.each do |part|
|
30
33
|
if is_regular_request? && is_html_response?
|
31
|
-
insert_at = part.index('</head')
|
34
|
+
insert_at = part.index(@options[:insert_js_last] ? '</body' : '</head')
|
32
35
|
unless insert_at.nil?
|
33
36
|
part.insert(insert_at, render_event_tracking_scripts) unless queue.empty?
|
34
37
|
part.insert(insert_at, render_mixpanel_scripts) #This will insert the mixpanel initialization code before the queue of tracking events.
|
@@ -63,6 +66,10 @@ module Mixpanel
|
|
63
66
|
@headers["Content-Type"].include?("text/javascript") if @headers.has_key?("Content-Type")
|
64
67
|
end
|
65
68
|
|
69
|
+
def is_trackable_response?
|
70
|
+
is_html_response? || is_javascript_response?
|
71
|
+
end
|
72
|
+
|
66
73
|
def render_mixpanel_scripts
|
67
74
|
if @options[:async]
|
68
75
|
<<-EOT
|
data/mixpanel.gemspec
CHANGED
@@ -2,12 +2,12 @@ files = ['README.rdoc', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/*
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |s|
|
4
4
|
s.name = "mixpanel"
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.1.1"
|
6
6
|
s.rubyforge_project = "mixpanel"
|
7
7
|
s.description = "Simple lib to track events in Mixpanel service. It can be used in any rack based framework."
|
8
8
|
s.author = "Alvaro Gil"
|
9
9
|
s.email = "zevarito@gmail.com"
|
10
|
-
s.homepage = "http://
|
10
|
+
s.homepage = "http://github.com/zevarito/mixpanel"
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
12
|
s.summary = "Supports direct request api and javascript requests through a middleware."
|
13
13
|
s.files = files
|
@@ -21,4 +21,7 @@ spec = Gem::Specification.new do |s|
|
|
21
21
|
s.add_development_dependency 'rack-test'
|
22
22
|
s.add_development_dependency 'fakeweb'
|
23
23
|
s.add_development_dependency 'nokogiri'
|
24
|
+
s.add_development_dependency 'rake'
|
25
|
+
s.add_development_dependency 'ruby-debug19' if RUBY_VERSION =~ /^1\.9/
|
26
|
+
s.add_development_dependency 'ruby-debug' if RUBY_VERSION =~ /^1\.8/
|
24
27
|
end
|
@@ -29,13 +29,13 @@ describe Mixpanel::Tracker::Middleware do
|
|
29
29
|
last_response.headers["Content-Length"].should == html_document.length.to_s
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
describe "With large ajax response" do
|
34
34
|
before do
|
35
35
|
setup_rack_application(DummyApp, {:body => large_script, :headers => {"Content-Type" => "text/html"}}, {:async => true})
|
36
36
|
get "/", {}, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
it "should not append mixpanel scripts to head element" do
|
40
40
|
last_response.body.index('var mp_protocol').should be_nil
|
41
41
|
end
|
@@ -44,32 +44,46 @@ describe Mixpanel::Tracker::Middleware do
|
|
44
44
|
last_response.body.should == large_script
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
describe "With regular requests" do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
describe "With js in head" do
|
50
|
+
before do
|
51
|
+
setup_rack_application(DummyApp, {:body => html_document, :headers => {"Content-Type" => "text/html"}}, {:async => true, :insert_js_last => false})
|
52
|
+
get "/"
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
it "should append mixpanel scripts to head element" do
|
56
|
+
Nokogiri::HTML(last_response.body).search('head script').should_not be_empty
|
57
|
+
Nokogiri::HTML(last_response.body).search('body script').should be_empty
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
it "should have 1 included script" do
|
61
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 1
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
it "should use the specified token instantiating mixpanel lib" do
|
65
|
+
last_response.should =~ /mpq.push\(\["init", "#{MIX_PANEL_TOKEN}"\]\)/
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should define Content-Length if not exist" do
|
69
|
+
last_response.headers.has_key?("Content-Length").should == true
|
70
|
+
end
|
66
71
|
|
67
|
-
|
68
|
-
|
72
|
+
it "should update Content-Length in headers" do
|
73
|
+
last_response.headers["Content-Length"].should_not == html_document.length.to_s
|
74
|
+
end
|
69
75
|
end
|
70
76
|
|
71
|
-
|
72
|
-
|
77
|
+
describe "With js last" do
|
78
|
+
before do
|
79
|
+
setup_rack_application(DummyApp, {:body => html_document, :headers => {"Content-Type" => "text/html"}}, {:async => true, :insert_js_last => true})
|
80
|
+
get "/"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should append mixpanel scripts to end of body element" do
|
84
|
+
Nokogiri::HTML(last_response.body).search('head script').should be_empty
|
85
|
+
Nokogiri::HTML(last_response.body).search('body script').should_not be_empty
|
86
|
+
end
|
73
87
|
end
|
74
88
|
end
|
75
89
|
end
|
@@ -89,13 +103,13 @@ describe Mixpanel::Tracker::Middleware do
|
|
89
103
|
last_response.headers["Content-Length"].should == html_document.length.to_s
|
90
104
|
end
|
91
105
|
end
|
92
|
-
|
106
|
+
|
93
107
|
describe "With large ajax response" do
|
94
108
|
before do
|
95
109
|
setup_rack_application(DummyApp, :body => large_script, :headers => {"Content-Type" => "text/html"})
|
96
110
|
get "/", {}, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
|
97
111
|
end
|
98
|
-
|
112
|
+
|
99
113
|
it "should not append mixpanel scripts to head element" do
|
100
114
|
last_response.body.index('var mp_protocol').should be_nil
|
101
115
|
end
|
@@ -104,32 +118,46 @@ describe Mixpanel::Tracker::Middleware do
|
|
104
118
|
last_response.body.should == large_script
|
105
119
|
end
|
106
120
|
end
|
107
|
-
|
108
|
-
describe "With regular requests" do
|
109
|
-
before do
|
110
|
-
setup_rack_application(DummyApp, :body => html_document, :headers => {"Content-Type" => "text/html"})
|
111
|
-
get "/"
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should append mixpanel scripts to head element" do
|
115
|
-
Nokogiri::HTML(last_response.body).search('head script').should_not be_empty
|
116
|
-
Nokogiri::HTML(last_response.body).search('body script').should be_empty
|
117
|
-
end
|
118
|
-
|
119
|
-
it "should have 2 included scripts" do
|
120
|
-
Nokogiri::HTML(last_response.body).search('script').size.should == 2
|
121
|
-
end
|
122
|
-
|
123
|
-
it "should use the specified token instantiating mixpanel lib" do
|
124
|
-
last_response.should =~ /new MixpanelLib\('#{MIX_PANEL_TOKEN}'\)/
|
125
|
-
end
|
126
121
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
122
|
+
describe "With regular requests" do
|
123
|
+
describe "With js in head" do
|
124
|
+
before do
|
125
|
+
setup_rack_application(DummyApp, {:body => html_document, :headers => {"Content-Type" => "text/html"}}, {:insert_js_last => false})
|
126
|
+
get "/"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should append mixpanel scripts to head element" do
|
130
|
+
Nokogiri::HTML(last_response.body).search('head script').should_not be_empty
|
131
|
+
Nokogiri::HTML(last_response.body).search('body script').should be_empty
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should have 2 included scripts" do
|
135
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 2
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should use the specified token instantiating mixpanel lib" do
|
139
|
+
last_response.should =~ /new MixpanelLib\('#{MIX_PANEL_TOKEN}'\)/
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should define Content-Length if not exist" do
|
143
|
+
last_response.headers.has_key?("Content-Length").should == true
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should update Content-Length in headers" do
|
147
|
+
last_response.headers["Content-Length"].should_not == html_document.length.to_s
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "With js last" do
|
152
|
+
before do
|
153
|
+
setup_rack_application(DummyApp, {:body => html_document, :headers => {"Content-Type" => "text/html"}}, {:insert_js_last => true})
|
154
|
+
get "/"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should append mixpanel scripts to end of body element" do
|
158
|
+
Nokogiri::HTML(last_response.body).search('head script').should be_empty
|
159
|
+
Nokogiri::HTML(last_response.body).search('body script').should_not be_empty
|
160
|
+
end
|
133
161
|
end
|
134
162
|
end
|
135
163
|
end
|
@@ -7,7 +7,7 @@ describe Mixpanel::Tracker do
|
|
7
7
|
|
8
8
|
context "Initializing object" do
|
9
9
|
it "should have an instance variable for token and events" do
|
10
|
-
@mixpanel.instance_variables.should include("@token", "@env")
|
10
|
+
@mixpanel.instance_variables.map(&:to_s).should include("@token", "@env")
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixpanel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 23
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 1.1.1
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Alvaro Gil
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2011-
|
17
|
+
date: 2011-11-23 00:00:00 -02:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,7 +25,6 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
28
|
segments:
|
31
29
|
- 0
|
32
30
|
version: "0"
|
@@ -40,7 +38,6 @@ dependencies:
|
|
40
38
|
requirements:
|
41
39
|
- - ">="
|
42
40
|
- !ruby/object:Gem::Version
|
43
|
-
hash: 3
|
44
41
|
segments:
|
45
42
|
- 0
|
46
43
|
version: "0"
|
@@ -54,7 +51,6 @@ dependencies:
|
|
54
51
|
requirements:
|
55
52
|
- - ">="
|
56
53
|
- !ruby/object:Gem::Version
|
57
|
-
hash: 3
|
58
54
|
segments:
|
59
55
|
- 0
|
60
56
|
version: "0"
|
@@ -68,7 +64,6 @@ dependencies:
|
|
68
64
|
requirements:
|
69
65
|
- - ">="
|
70
66
|
- !ruby/object:Gem::Version
|
71
|
-
hash: 3
|
72
67
|
segments:
|
73
68
|
- 0
|
74
69
|
version: "0"
|
@@ -82,7 +77,6 @@ dependencies:
|
|
82
77
|
requirements:
|
83
78
|
- - ">="
|
84
79
|
- !ruby/object:Gem::Version
|
85
|
-
hash: 3
|
86
80
|
segments:
|
87
81
|
- 0
|
88
82
|
version: "0"
|
@@ -96,7 +90,6 @@ dependencies:
|
|
96
90
|
requirements:
|
97
91
|
- - ">="
|
98
92
|
- !ruby/object:Gem::Version
|
99
|
-
hash: 3
|
100
93
|
segments:
|
101
94
|
- 0
|
102
95
|
version: "0"
|
@@ -110,12 +103,37 @@ dependencies:
|
|
110
103
|
requirements:
|
111
104
|
- - ">="
|
112
105
|
- !ruby/object:Gem::Version
|
113
|
-
hash: 3
|
114
106
|
segments:
|
115
107
|
- 0
|
116
108
|
version: "0"
|
117
109
|
type: :development
|
118
110
|
version_requirements: *id007
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
prerelease: false
|
114
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
type: :development
|
123
|
+
version_requirements: *id008
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: ruby-debug19
|
126
|
+
prerelease: false
|
127
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
version: "0"
|
135
|
+
type: :development
|
136
|
+
version_requirements: *id009
|
119
137
|
description: Simple lib to track events in Mixpanel service. It can be used in any rack based framework.
|
120
138
|
email: zevarito@gmail.com
|
121
139
|
executables: []
|
@@ -139,7 +157,7 @@ files:
|
|
139
157
|
- lib/mixpanel/tracker.rb
|
140
158
|
- lib/mixpanel.rb
|
141
159
|
has_rdoc: true
|
142
|
-
homepage: http://
|
160
|
+
homepage: http://github.com/zevarito/mixpanel
|
143
161
|
licenses: []
|
144
162
|
|
145
163
|
post_install_message:
|
@@ -152,7 +170,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
170
|
requirements:
|
153
171
|
- - ">="
|
154
172
|
- !ruby/object:Gem::Version
|
155
|
-
hash: 3
|
156
173
|
segments:
|
157
174
|
- 0
|
158
175
|
version: "0"
|
@@ -161,7 +178,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
178
|
requirements:
|
162
179
|
- - ">="
|
163
180
|
- !ruby/object:Gem::Version
|
164
|
-
hash: 3
|
165
181
|
segments:
|
166
182
|
- 0
|
167
183
|
version: "0"
|