mixpanel 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +26 -9
- data/lib/mixpanel.rb +2 -42
- data/lib/mixpanel/mixpanel.rb +49 -0
- data/lib/mixpanel/mixpanel_middleware.rb +95 -0
- data/mixpanel.gemspec +9 -13
- data/spec/mixpanel/mixpanel_middleware_spec.rb +134 -0
- data/spec/mixpanel/mixpanel_spec.rb +21 -12
- data/spec/spec_helper.rb +6 -2
- data/spec/support/rack_apps.rb +27 -0
- metadata +58 -13
- data/.gitignore +0 -2
data/README.rdoc
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
== What is Mixpanel (the service) ?
|
2
2
|
|
3
|
-
|
3
|
+
Mixpanel is a real-time analytics service that helps companies understand how users interact with web applications.
|
4
4
|
http://mixpanel.com
|
5
5
|
|
6
6
|
== What does this Gem?
|
7
7
|
|
8
|
-
* Track events with properties directly from your backend
|
8
|
+
* Track events with properties directly from your backend.
|
9
|
+
* Track events with properties through javascript using a rack middleware.
|
9
10
|
|
10
11
|
|
11
12
|
== How to install?
|
@@ -13,13 +14,29 @@ http://mixpanel.com
|
|
13
14
|
gem install mixpanel
|
14
15
|
|
15
16
|
|
16
|
-
== How to use?
|
17
|
+
== How to use it with a Rails application?
|
17
18
|
|
18
|
-
|
19
|
+
In your application_controller class add a method to instance mixpanel.
|
19
20
|
|
20
|
-
|
21
|
+
before_filer :initialize_mixpanel
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def initialize_mixpanel
|
24
|
+
@mixpanel = Mixpanel.new("YOUR_MIXPANEL_API_TOKEN", request.env)
|
25
|
+
end
|
26
|
+
|
27
|
+
Then in each request you want to track some event you can use:
|
28
|
+
|
29
|
+
To track events directly from your backend...
|
30
|
+
|
31
|
+
@mixpanel.track_event("Sign in", {:some => "property"})
|
32
|
+
|
33
|
+
To track events after response with javascript...
|
34
|
+
|
35
|
+
@mixpanel.append_event("Sign in", {:some => "property"})
|
36
|
+
|
37
|
+
|
38
|
+
== Notes
|
39
|
+
|
40
|
+
It is strongly recommended to call Mixpanel#track_event using an async lib
|
41
|
+
like delayed job or similar, otherwise you will delay your server responses
|
42
|
+
with mixpanel responses.
|
data/lib/mixpanel.rb
CHANGED
@@ -1,42 +1,2 @@
|
|
1
|
-
require
|
2
|
-
require '
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
class Mixpanel
|
6
|
-
attr_reader :events
|
7
|
-
|
8
|
-
def initialize(token, options = {})
|
9
|
-
@token = token
|
10
|
-
@events = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def append_event(event, properties = {})
|
14
|
-
@events << build_event(event, properties)
|
15
|
-
end
|
16
|
-
|
17
|
-
def track_event(event, properties = {})
|
18
|
-
params = build_event(event, properties.merge(:token => @token, :time => Time.now.utc.to_i))
|
19
|
-
parse_response request(params)
|
20
|
-
end
|
21
|
-
|
22
|
-
def clean_queue
|
23
|
-
@events = []
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def parse_response(response)
|
29
|
-
response == "1" ? true : false
|
30
|
-
end
|
31
|
-
|
32
|
-
def request(params)
|
33
|
-
data = Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
|
34
|
-
url = "http://api.mixpanel.com/track/?data=#{data}"
|
35
|
-
|
36
|
-
open(url).read
|
37
|
-
end
|
38
|
-
|
39
|
-
def build_event(event, properties)
|
40
|
-
{:event => event, :properties => properties}
|
41
|
-
end
|
42
|
-
end
|
1
|
+
require 'mixpanel/mixpanel'
|
2
|
+
require 'mixpanel/mixpanel_middleware'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require 'base64'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class Mixpanel
|
6
|
+
def initialize(token, env)
|
7
|
+
@token = token
|
8
|
+
@env = env
|
9
|
+
clear_queue
|
10
|
+
end
|
11
|
+
|
12
|
+
def append_event(event, properties = {})
|
13
|
+
queue << build_event(event, properties)
|
14
|
+
end
|
15
|
+
|
16
|
+
def track_event(event, properties = {})
|
17
|
+
params = build_event(event, properties.merge(:token => @token, :time => Time.now.utc.to_i, :ip => ip))
|
18
|
+
parse_response request(params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def ip
|
22
|
+
@env.has_key?("REMOTE_ADDR") ? @env["REMOTE_ADDR"] : ""
|
23
|
+
end
|
24
|
+
|
25
|
+
def queue
|
26
|
+
@env["mixpanel_events"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear_queue
|
30
|
+
@env["mixpanel_events"] = []
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_response(response)
|
36
|
+
response == "1" ? true : false
|
37
|
+
end
|
38
|
+
|
39
|
+
def request(params)
|
40
|
+
data = Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
|
41
|
+
url = "http://api.mixpanel.com/track/?data=#{data}"
|
42
|
+
|
43
|
+
open(url).read
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_event(event, properties)
|
47
|
+
{:event => event, :properties => properties}
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
class MixpanelMiddleware
|
4
|
+
def initialize(app, mixpanel_token)
|
5
|
+
@app = app
|
6
|
+
@token = mixpanel_token
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@env = env
|
11
|
+
|
12
|
+
@status, @headers, @response = @app.call(env)
|
13
|
+
|
14
|
+
update_response!
|
15
|
+
update_content_length!
|
16
|
+
delete_event_queue!
|
17
|
+
|
18
|
+
[@status, @headers, @response]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def update_response!
|
24
|
+
@response.each do |part|
|
25
|
+
if is_regular_request? && is_html_response?
|
26
|
+
part.gsub!("</head>", "#{render_mixpanel_scripts}</head>")
|
27
|
+
part.gsub!("</head>", "#{render_event_tracking_scripts}</head>")
|
28
|
+
elsif is_ajax_request? && is_html_response?
|
29
|
+
part.gsub!(part, render_event_tracking_scripts + part)
|
30
|
+
elsif is_ajax_request? && is_javascript_response?
|
31
|
+
part.gsub!(part, render_event_tracking_scripts(false) + part)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_content_length!
|
37
|
+
new_size = 0
|
38
|
+
@response.each{|part| new_size += part.bytesize}
|
39
|
+
@headers.merge!("Content-Length" => new_size.to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_regular_request?
|
43
|
+
!is_ajax_request?
|
44
|
+
end
|
45
|
+
|
46
|
+
def is_ajax_request?
|
47
|
+
@env.has_key?("HTTP_X_REQUESTED_WITH") && @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
|
48
|
+
end
|
49
|
+
|
50
|
+
def is_html_response?
|
51
|
+
@headers["Content-Type"].include?("text/html") if @headers.has_key?("Content-Type")
|
52
|
+
end
|
53
|
+
|
54
|
+
def is_javascript_response?
|
55
|
+
@headers["Content-Type"].include?("text/javascript") if @headers.has_key?("Content-Type")
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_mixpanel_scripts
|
59
|
+
<<-EOT
|
60
|
+
<script type='text/javascript'>
|
61
|
+
var mp_protocol = (('https:' == document.location.protocol) ? 'https://' : 'http://');
|
62
|
+
document.write(unescape('%3Cscript src="' + mp_protocol + 'api.mixpanel.com/site_media/js/api/mixpanel.js" type="text/javascript"%3E%3C/script%3E'));
|
63
|
+
</script>
|
64
|
+
<script type='text/javascript'>
|
65
|
+
try {
|
66
|
+
var mpmetrics = new MixpanelLib('#{@token}');
|
67
|
+
} catch(err) {
|
68
|
+
null_fn = function () {};
|
69
|
+
var mpmetrics = {
|
70
|
+
track: null_fn, track_funnel: null_fn, register: null_fn, register_once: null_fn, register_funnel: null_fn
|
71
|
+
};
|
72
|
+
}
|
73
|
+
</script>
|
74
|
+
EOT
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete_event_queue!
|
78
|
+
@env.delete('mixpanel_events')
|
79
|
+
end
|
80
|
+
|
81
|
+
def queue
|
82
|
+
return [] if !@env.has_key?('mixpanel_events') || @env['mixpanel_events'].empty?
|
83
|
+
@env['mixpanel_events']
|
84
|
+
end
|
85
|
+
|
86
|
+
def render_event_tracking_scripts(include_script_tag=true)
|
87
|
+
return "" if queue.empty?
|
88
|
+
|
89
|
+
output = queue.map {|event| %(mpmetrics.track("#{event[:event]}", #{event[:properties].to_json});) }.join("\n")
|
90
|
+
|
91
|
+
output = "try {#{output}} catch(err) {}"
|
92
|
+
|
93
|
+
include_script_tag ? "<script type='text/javascript'>#{output}</script>" : output
|
94
|
+
end
|
95
|
+
end
|
data/mixpanel.gemspec
CHANGED
@@ -1,27 +1,23 @@
|
|
1
|
+
files = ['README.rdoc', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/**/*'].map {|f| Dir[f]}.flatten
|
2
|
+
|
1
3
|
spec = Gem::Specification.new do |s|
|
2
4
|
s.name = "mixpanel"
|
3
|
-
s.version = "0.
|
5
|
+
s.version = "0.6.0"
|
4
6
|
s.rubyforge_project = "mixpanel"
|
5
|
-
s.description = "Simple lib to track events in Mixpanel service."
|
7
|
+
s.description = "Simple lib to track events in Mixpanel service. It can be used in any rack based framework."
|
6
8
|
s.author = "Alvaro Gil"
|
7
9
|
s.email = "zevarito@gmail.com"
|
8
10
|
s.homepage = "http://cuboxsa.com"
|
9
11
|
s.platform = Gem::Platform::RUBY
|
10
|
-
s.summary = "Supports direct request api and javascript requests."
|
11
|
-
s.files =
|
12
|
-
.gitignore
|
13
|
-
README.rdoc
|
14
|
-
LICENSE
|
15
|
-
Rakefile
|
16
|
-
mixpanel.gemspec
|
17
|
-
lib/mixpanel.rb
|
18
|
-
spec/spec_helper.rb
|
19
|
-
spec/mixpanel/mixpanel_spec.rb
|
20
|
-
]
|
12
|
+
s.summary = "Supports direct request api and javascript requests through a middleware."
|
13
|
+
s.files = files
|
21
14
|
s.require_path = "lib"
|
22
15
|
s.has_rdoc = false
|
23
16
|
s.extra_rdoc_files = ["README.rdoc"]
|
24
17
|
s.add_dependency 'json'
|
18
|
+
s.add_dependency 'rack'
|
25
19
|
s.add_development_dependency 'rspec'
|
20
|
+
s.add_development_dependency 'rack-test'
|
26
21
|
s.add_development_dependency 'fakeweb'
|
22
|
+
s.add_development_dependency 'nokogiri'
|
27
23
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MixpanelMiddleware do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
describe "Dummy apps, no text/html" do
|
7
|
+
before do
|
8
|
+
setup_rack_application(DummyApp, :body => html_document, :headers => {})
|
9
|
+
get "/"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should pass through if the document is not text/html content type" do
|
13
|
+
last_response.body.should == html_document
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Appending mixpanel scripts" do
|
18
|
+
describe "With ajax requests" do
|
19
|
+
before do
|
20
|
+
setup_rack_application(DummyApp, :body => html_document, :headers => {"Content-Type" => "text/html"})
|
21
|
+
get "/", {}, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not append mixpanel scripts to head element" do
|
25
|
+
Nokogiri::HTML(last_response.body).search('script').should be_empty
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not update Content-Length in headers" do
|
29
|
+
last_response.headers["Content-Length"].should == html_document.length.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "With regular requests" do
|
34
|
+
before do
|
35
|
+
setup_rack_application(DummyApp, :body => html_document, :headers => {"Content-Type" => "text/html"})
|
36
|
+
get "/"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should append mixpanel scripts to head element" do
|
40
|
+
Nokogiri::HTML(last_response.body).search('head script').should_not be_empty
|
41
|
+
Nokogiri::HTML(last_response.body).search('body script').should be_empty
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have 2 included scripts" do
|
45
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should use the specified token instantiating mixpanel lib" do
|
49
|
+
last_response.should =~ /new MixpanelLib\('#{MIX_PANEL_TOKEN}'\)/
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should define Content-Length if not exist" do
|
53
|
+
last_response.headers.has_key?("Content-Length").should == true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should update Content-Length in headers" do
|
57
|
+
last_response.headers["Content-Length"].should_not == html_document.length.to_s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "Tracking appended events" do
|
63
|
+
before do
|
64
|
+
@mixpanel = Mixpanel.new(MIX_PANEL_TOKEN, {})
|
65
|
+
@mixpanel.append_event("Visit", {:article => 1})
|
66
|
+
@mixpanel.append_event("Sign in")
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "With ajax requests and text/html response" do
|
70
|
+
before do
|
71
|
+
setup_rack_application(DummyApp, :body => "<p>response</p>", :headers => {"Content-Type" => "text/html"})
|
72
|
+
|
73
|
+
get "/", {}, {"mixpanel_events" => @mixpanel.queue, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should render only one script tag" do
|
77
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 1
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should be tracking the correct events inside a script tag" do
|
81
|
+
script = Nokogiri::HTML(last_response.body).search('script')
|
82
|
+
script.inner_html.should =~ /try\s?\{(.*)\}\s?catch/m
|
83
|
+
script.inner_html.should =~ /mpmetrics\.track\("Visit",\s?\{"article":1\}\)/
|
84
|
+
script.inner_html.should =~ /mpmetrics\.track\("Sign in",\s?\{\}\)/
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should delete events queue after use it" do
|
88
|
+
last_request.env.has_key?("mixpanel_events").should == false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "With ajax requests and text/javascript response" do
|
93
|
+
before do
|
94
|
+
setup_rack_application(DummyApp, :body => "alert('response')", :headers => {"Content-Type" => "text/javascript"})
|
95
|
+
get "/", {}, {"mixpanel_events" => @mixpanel.queue, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not render a script tag" do
|
99
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 0
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should be tracking the correct events inside a try/catch" do
|
103
|
+
script = last_response.body.match(/try\s?\{(.*)\}\s?catch/m)[1]
|
104
|
+
script.should =~ /mpmetrics\.track\("Visit",\s?\{"article":1\}\)/
|
105
|
+
script.should =~ /mpmetrics\.track\("Sign in",\s?\{\}\)/
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should delete events queue after use it" do
|
109
|
+
last_request.env.has_key?("mixpanel_events").should == false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "With regular requests" do
|
114
|
+
before do
|
115
|
+
setup_rack_application(DummyApp, :body => html_document, :headers => {"Content-Type" => "text/html"})
|
116
|
+
|
117
|
+
get "/", {}, {"mixpanel_events" => @mixpanel.queue}
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should render 3 script tags" do
|
121
|
+
Nokogiri::HTML(last_response.body).search('script').size.should == 3
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should be tracking the correct events" do
|
125
|
+
last_response.body.should =~ /mpmetrics\.track\("Visit",\s?\{"article":1\}\)/
|
126
|
+
last_response.body.should =~ /mpmetrics\.track\("Sign in",\s?\{\}\)/
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should delete events queue after use it" do
|
130
|
+
last_request.env.has_key?("mixpanel_events").should == false
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -2,21 +2,21 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Mixpanel do
|
4
4
|
before do
|
5
|
-
@mixpanel = Mixpanel.new(MIX_PANEL_TOKEN)
|
5
|
+
@mixpanel = Mixpanel.new(MIX_PANEL_TOKEN, @env = {"REMOTE_ADDR" => "127.0.0.1"})
|
6
6
|
end
|
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", "@
|
10
|
+
@mixpanel.instance_variables.should include("@token", "@env")
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
context "Cleaning events" do
|
15
|
-
it "should
|
14
|
+
context "Cleaning appended events" do
|
15
|
+
it "should clear the queue" do
|
16
16
|
@mixpanel.append_event("Sign up")
|
17
|
-
@mixpanel.
|
18
|
-
@mixpanel.
|
19
|
-
@mixpanel.
|
17
|
+
@mixpanel.queue.size.should == 1
|
18
|
+
@mixpanel.clear_queue
|
19
|
+
@mixpanel.queue.size.should == 0
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -27,7 +27,7 @@ describe Mixpanel do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should call request method with token and time value" do
|
30
|
-
params = {:event => "Sign up", :properties => {:token => MIX_PANEL_TOKEN, :time => Time.now.utc.to_i}}
|
30
|
+
params = {:event => "Sign up", :properties => {:token => MIX_PANEL_TOKEN, :time => Time.now.utc.to_i, :ip => "127.0.0.1"}}
|
31
31
|
|
32
32
|
@mixpanel.should_receive(:request).with(params).and_return("1")
|
33
33
|
@mixpanel.track_event("Sign up").should == true
|
@@ -37,19 +37,28 @@ describe Mixpanel do
|
|
37
37
|
|
38
38
|
context "Accessing Mixpanel through javascript API" do
|
39
39
|
context "Appending events" do
|
40
|
+
it "should store the event under the appropriate key" do
|
41
|
+
@mixpanel.append_event("Sign up")
|
42
|
+
@env.has_key?("mixpanel_events").should == true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should be the same the queue than env['mixpanel_events']" do
|
46
|
+
@env['mixpanel_events'].object_id.should == @mixpanel.queue.object_id
|
47
|
+
end
|
48
|
+
|
40
49
|
it "should append simple events" do
|
41
50
|
@mixpanel.append_event("Sign up")
|
42
|
-
|
51
|
+
mixpanel_queue_should_include(@mixpanel, "Sign up", {})
|
43
52
|
end
|
44
53
|
|
45
54
|
it "should append events with properties" do
|
46
55
|
@mixpanel.append_event("Sign up", {:referer => 'http://example.com'})
|
47
|
-
|
56
|
+
mixpanel_queue_should_include(@mixpanel, "Sign up", {:referer => 'http://example.com'})
|
48
57
|
end
|
49
58
|
|
50
|
-
it "should give direct access to
|
59
|
+
it "should give direct access to queue" do
|
51
60
|
@mixpanel.append_event("Sign up", {:referer => 'http://example.com'})
|
52
|
-
@mixpanel.
|
61
|
+
@mixpanel.queue.size.should == 1
|
53
62
|
end
|
54
63
|
end
|
55
64
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
require 'ruby-debug'
|
1
2
|
require File.join(File.dirname(__FILE__), "../lib", "mixpanel")
|
3
|
+
require 'rack/test'
|
2
4
|
require 'fakeweb'
|
5
|
+
require 'nokogiri'
|
6
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
3
7
|
|
4
8
|
MIX_PANEL_TOKEN = "e2d8b0bea559147844ffab3d607d26a6"
|
5
9
|
|
6
|
-
def
|
7
|
-
mixpanel.
|
10
|
+
def mixpanel_queue_should_include(mixpanel, event, properties)
|
11
|
+
mixpanel.queue.each do |event_hash|
|
8
12
|
event_hash[:event].should == event
|
9
13
|
event_hash[:properties].should == properties if properties
|
10
14
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
def setup_rack_application(application, options = {})
|
2
|
+
stub!(:app).and_return(MixpanelMiddleware.new(application.new(options), MIX_PANEL_TOKEN))
|
3
|
+
end
|
4
|
+
|
5
|
+
def html_document
|
6
|
+
<<-EOT
|
7
|
+
<html>
|
8
|
+
<head>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
</body>
|
12
|
+
</html>
|
13
|
+
EOT
|
14
|
+
end
|
15
|
+
|
16
|
+
class DummyApp
|
17
|
+
def initialize(options)
|
18
|
+
@response_with = {}
|
19
|
+
@response_with[:status] = options[:status] || "200"
|
20
|
+
@response_with[:headers] = options[:headers] || {}
|
21
|
+
@response_with[:body] = options[:body] || ""
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(env)
|
25
|
+
[@response_with[:status], @response_with[:headers], [@response_with[:body]]]
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixpanel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 6
|
9
|
+
- 0
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alvaro Gil
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07-
|
18
|
+
date: 2010-07-16 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
36
|
+
name: rack
|
37
37
|
prerelease: false
|
38
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
segments:
|
45
45
|
- 0
|
46
46
|
version: "0"
|
47
|
-
type: :
|
47
|
+
type: :runtime
|
48
48
|
version_requirements: *id002
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
50
|
+
name: rspec
|
51
51
|
prerelease: false
|
52
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
@@ -60,7 +60,49 @@ dependencies:
|
|
60
60
|
version: "0"
|
61
61
|
type: :development
|
62
62
|
version_requirements: *id003
|
63
|
-
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rack-test
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: fakeweb
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: nokogiri
|
93
|
+
prerelease: false
|
94
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
type: :development
|
104
|
+
version_requirements: *id006
|
105
|
+
description: Simple lib to track events in Mixpanel service. It can be used in any rack based framework.
|
64
106
|
email: zevarito@gmail.com
|
65
107
|
executables: []
|
66
108
|
|
@@ -69,14 +111,17 @@ extensions: []
|
|
69
111
|
extra_rdoc_files:
|
70
112
|
- README.rdoc
|
71
113
|
files:
|
72
|
-
- .gitignore
|
73
114
|
- README.rdoc
|
74
115
|
- LICENSE
|
75
116
|
- Rakefile
|
76
117
|
- mixpanel.gemspec
|
77
|
-
-
|
78
|
-
- spec/spec_helper.rb
|
118
|
+
- spec/mixpanel/mixpanel_middleware_spec.rb
|
79
119
|
- spec/mixpanel/mixpanel_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/support/rack_apps.rb
|
122
|
+
- lib/mixpanel/mixpanel.rb
|
123
|
+
- lib/mixpanel/mixpanel_middleware.rb
|
124
|
+
- lib/mixpanel.rb
|
80
125
|
has_rdoc: true
|
81
126
|
homepage: http://cuboxsa.com
|
82
127
|
licenses: []
|
@@ -110,6 +155,6 @@ rubyforge_project: mixpanel
|
|
110
155
|
rubygems_version: 1.3.7
|
111
156
|
signing_key:
|
112
157
|
specification_version: 3
|
113
|
-
summary: Supports direct request api and javascript requests.
|
158
|
+
summary: Supports direct request api and javascript requests through a middleware.
|
114
159
|
test_files: []
|
115
160
|
|
data/.gitignore
DELETED