mixpanel 2.2.0 → 3.0.1

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.
@@ -0,0 +1,41 @@
1
+ module Mixpanel::Person
2
+ PERSON_PROPERTIES = %w{email created first_name last_name last_login username country_code}
3
+ PERSON_URL = 'http://api.mixpanel.com/engage/'
4
+
5
+ def set(distinct_id, properties={}, options={})
6
+ engage :set, distinct_id, properties, options
7
+ end
8
+
9
+ def increment(distinct_id, properties={}, options={})
10
+ engage :add, distinct_id, properties, options
11
+ end
12
+
13
+ def append_set(properties={})
14
+ append 'people.set', properties_hash(properties, PERSON_PROPERTIES)
15
+ end
16
+
17
+ def append_increment(property, increment=1)
18
+ append 'people.increment', property, increment
19
+ end
20
+
21
+ def append_register(properties={})
22
+ append 'register', properties_hash(properties, PERSON_PROPERTIES)
23
+ end
24
+
25
+ def append_identify(distinct_id)
26
+ append 'identify', distinct_id
27
+ end
28
+
29
+ protected
30
+
31
+ def engage(action, distinct_id, properties, options)
32
+ options.reverse_merge! :async => @async, :url => PERSON_URL
33
+ data = build_person action, distinct_id, properties
34
+ url = "#{options[:url]}?data=#{encoded_data(data)}"
35
+ parse_response request(url, options[:async])
36
+ end
37
+
38
+ def build_person(action, distinct_id, properties)
39
+ { "$#{action}".to_sym => properties_hash(properties, PERSON_PROPERTIES), :$token => @token, :$distinct_id => distinct_id }
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ require 'open-uri'
2
+ require 'thread'
3
+
4
+ module Mixpanel
5
+ class Subprocess
6
+ Q = Queue.new
7
+ ENDMARKER = Object.new
8
+
9
+ Thread.abort_on_exception = true
10
+ producer = Thread.new do
11
+ STDIN.each_line() do |url|
12
+ STDERR.puts("Dropped: #{url}") && next if Q.length > 10000
13
+ Q << url
14
+ end
15
+ Q << ENDMARKER
16
+ end
17
+
18
+ loop do
19
+ url = Q.pop
20
+ break if(url == ENDMARKER)
21
+ url.chomp!
22
+ next if(url.empty?) #for testing
23
+ open(url).read
24
+ end
25
+ producer.join
26
+ end
27
+ end
@@ -2,171 +2,74 @@ require "open-uri"
2
2
  require 'base64'
3
3
  require 'json'
4
4
  require 'thread'
5
- require 'mixpanel/tracker/middleware'
6
5
 
7
6
  module Mixpanel
8
7
  class Tracker
8
+ require 'mixpanel/async'
9
+ require 'mixpanel/event'
10
+ require 'mixpanel/person'
11
+
12
+ extend Mixpanel::Async
13
+ include Mixpanel::Event
14
+ include Mixpanel::Person
15
+
16
+ def initialize(token, options={})
17
+ @token = token
18
+ @async = !!options.fetch(:async, false)
19
+ @persist = !!options.fetch(:persist, false)
20
+ @env = options.fetch :env, {}
21
+ @api_key = options.fetch :api_key, nil
9
22
 
10
- MIXPANEL_API_URL = 'http://api.mixpanel.com'.freeze
11
- TRACK_ENDPOINT = '/track/?data='.freeze
12
- ENGAGE_ENDPOINT = '/engage/?data='.freeze
13
- IMPORT_ENDPOINT = '/import/?data='.freeze
14
-
15
- PERSON_PROPERTIES = %w(email first_name last_name created last_login username country_code).freeze
16
-
17
- def initialize(token, env, options = {})
18
- @token = token
19
- @api_key = options.fetch(:api_key, "")
20
- @env = env
21
- @async = options.fetch(:async, false)
22
- @import = options.fetch(:import, false)
23
- @url = options.fetch(:url, MIXPANEL_API_URL)
24
- @persist = options.fetch(:persist, false)
25
-
23
+ # Make sure queue object is instantiated to an array. If not persisted, set queue object to empty array.
26
24
  if @persist
27
- @env["rack.session"]["mixpanel_events"] ||= []
28
- else
29
- clear_queue
30
- end
31
- end
32
-
33
- def append_event(event, properties = {})
34
- append_api('track', event, properties)
35
- end
36
-
37
- def append_person_event(properties = {})
38
- append_api('people.set', person_properties(properties))
39
- end
40
-
41
- def append_person_increment_event(property, increment=1)
42
- append_api('people.increment', property, increment)
43
- end
44
-
45
- def append_api(type, *args)
46
- queue << [type, args.map {|arg| arg.to_json}]
47
- end
48
-
49
- def track_event(event, properties = {})
50
- options = { :time => Time.now.utc.to_i, :ip => ip }
51
- options.merge!( :token => @token ) if @token
52
- parse_response request(:track,
53
- :event => event,
54
- :properties => options.merge(properties)
55
- )
56
- end
57
-
58
- def engage(action, distinct_id, properties = {})
59
- options = { }
60
- options.merge!( :$token => @token ) if @token
61
- parse_response request(:engage, options.merge(
62
- :$distinct_id => distinct_id,
63
- "$#{action}".to_sym => person_properties(properties)
64
- ))
65
- end
66
-
67
- def engage_set(distinct_id, properties = {})
68
- engage(:set, distinct_id, properties)
69
- end
70
-
71
- def engage_add(distinct_id, properties = {})
72
- engage(:add, distinct_id, properties)
73
- end
74
-
75
- def ip
76
- if @env.has_key?("HTTP_X_FORWARDED_FOR")
77
- @env["HTTP_X_FORWARDED_FOR"].split(",").last
78
- elsif @env.has_key?("REMOTE_ADDR")
79
- @env["REMOTE_ADDR"]
25
+ @env['rack.session'] ||= {}
26
+ @env['rack.session']['mixpanel_events'] ||= []
80
27
  else
81
- ""
28
+ @env['mixpanel_events'] = []
82
29
  end
83
30
  end
84
-
31
+
85
32
  def queue
86
- if @persist
87
- return @env["rack.session"]["mixpanel_events"]
88
- else
89
- return @env["mixpanel_events"]
33
+ @persist ? @env['rack.session']['mixpanel_events'] : @env['mixpanel_events']
34
+ end
35
+
36
+ def append(type, *args)
37
+ queue << [type, args.collect {|arg| arg.to_json}]
38
+ end
39
+
40
+ protected
41
+
42
+ # Walk through each property and see if it is in the special_properties. If so, change the key to have a $ in front of it.
43
+ def properties_hash(properties, special_properties)
44
+ properties.inject({}) do |props, (key, value)|
45
+ key = "$#{key}" if special_properties.include?(key.to_s)
46
+ props[key.to_sym] = value
47
+ props
90
48
  end
91
49
  end
92
-
93
- def clear_queue
94
- if @persist
95
- @env["rack.session"]["mixpanel_events"] = []
96
- else
97
- @env["mixpanel_events"] = []
98
- end
50
+
51
+ def encoded_data(parameters)
52
+ Base64.encode64(JSON.generate(parameters)).gsub(/\n/,'')
99
53
  end
100
-
101
- class << self
102
- WORKER_MUTEX = Mutex.new
103
-
104
- def worker
105
- WORKER_MUTEX.synchronize do
106
- @worker || (@worker = IO.popen(self.cmd, 'w'))
107
- end
108
- end
109
-
110
- def dispose_worker(w)
111
- WORKER_MUTEX.synchronize do
112
- if(@worker == w)
113
- @worker = nil
114
- w.close
115
- end
116
- end
117
- end
118
-
119
- def cmd
120
- @cmd || begin
121
- require 'escape'
122
- require 'rbconfig'
123
- interpreter = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) + RbConfig::CONFIG["EXEEXT"]
124
- subprocess = File.join(File.dirname(__FILE__), 'tracker/subprocess.rb')
125
- @cmd = Escape.shell_command([interpreter, subprocess])
126
- end
127
- end
128
- end
129
-
130
- private
131
-
132
- def person_properties(properties = {})
133
- properties.inject({}) do |out, (k, v)|
134
- if PERSON_PROPERTIES.member?(k.to_s)
135
- out["$#{k}".to_sym] = v
136
- else
137
- out[k] = v
138
- end
139
- out
140
- end
54
+
55
+ def request(url, async)
56
+ async ? send_async(url) : open(url).read
141
57
  end
142
-
58
+
143
59
  def parse_response(response)
144
- response == "1" ? true : false
145
- end
146
-
147
- def request(mode, params)
148
- data = Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
149
-
150
- mode = :import if @import
151
- endpoint = case mode
152
- when :track then TRACK_ENDPOINT
153
- when :engage then ENGAGE_ENDPOINT
154
- when :import then IMPORT_ENDPOINT
155
- end
156
- url = "#{@url}#{endpoint}#{data}"
157
- url += "&api_key=#{@api_key}" if mode == :import
158
-
159
- if(@async)
160
- w = Tracker.worker
161
- begin
162
- url << "\n"
163
- w.write(url)
164
- rescue Errno::EPIPE => e
165
- Tracker.dispose_worker(w)
166
- end
167
- else
168
- open(url).read
60
+ response.to_i == 1
61
+ end
62
+
63
+ def send_async(url)
64
+ w = Mixpanel::Tracker.worker
65
+ begin
66
+ url << "\n"
67
+ w.write url
68
+ 1
69
+ rescue Errno::EPIPE => e
70
+ Mixpanel::Tracker.dispose_worker w
71
+ 0
169
72
  end
170
73
  end
171
74
  end
172
- end
75
+ end
data/lib/mixpanel.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'mixpanel/tracker'
2
+ require 'mixpanel/middleware'
2
3
 
3
4
  module Mixpanel
4
5
  end
data/mixpanel.gemspec CHANGED
@@ -2,7 +2,7 @@ files = ['README.md', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/**/
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
4
  s.name = "mixpanel"
5
- s.version = "2.2.0"
5
+ s.version = "3.0.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"
@@ -17,6 +17,7 @@ spec = Gem::Specification.new do |s|
17
17
  s.add_dependency 'json'
18
18
  s.add_dependency 'rack'
19
19
  s.add_dependency 'escape'
20
+ s.add_development_dependency 'active_support'
20
21
  s.add_development_dependency 'rspec'
21
22
  s.add_development_dependency 'rack-test'
22
23
  s.add_development_dependency 'fakeweb'
@@ -1,15 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  def exec_default_appends_on(mixpanel)
4
- mixpanel.append_event("Visit", {:article => 1})
5
- mixpanel.append_event("Sign in")
6
- mixpanel.append_person_event(:first_name => "foo", :last_name => "bar", :username => "foobar")
7
- mixpanel.append_person_increment_event(:sign_in_rate)
4
+ mixpanel.append_track("Visit", {:article => 1})
5
+ mixpanel.append_track("Sign in")
6
+ mixpanel.append_set(:first_name => "foo", :last_name => "bar", :username => "foobar")
7
+ mixpanel.append_increment(:sign_in_rate)
8
8
  end
9
9
 
10
10
  def check_for_default_appends_on(txt)
11
- txt.should =~ /mixpanel\.track\("Visit",\s?\{"article":1\}\)/
12
- txt.should =~ /mixpanel\.track\("Sign in",\s?\{\}\)/
11
+ txt.should =~ /mixpanel\.track\("Visit",\s?\{.*"article":1[\{|,]/
12
+ txt.should =~ /mixpanel\.track\("Sign in",\s?\{.*"time":.*\}/
13
13
  txt.should =~ /mixpanel\.people\.set\(.*\);\nmixpanel.people.increment\(\"sign_in_rate\",\s?1\);/
14
14
  match = txt.match(/mixpanel\.people\.set\((.*\));/)
15
15
  match[1].should =~ /\"\$first_name\":\"foo\"/
@@ -18,9 +18,9 @@ def check_for_default_appends_on(txt)
18
18
  txt.should =~ /mixpanel\.people\.increment\(\"sign_in_rate\"\s?,\s?1\)/
19
19
  end
20
20
 
21
- describe Mixpanel::Tracker::Middleware do
21
+ describe Mixpanel::Middleware do
22
22
  include Rack::Test::Methods
23
-
23
+
24
24
  describe "Dummy apps, no text/html" do
25
25
  before do
26
26
  setup_rack_application(DummyApp, :body => html_document, :headers => {})
@@ -198,7 +198,7 @@ describe Mixpanel::Tracker::Middleware do
198
198
 
199
199
  describe "Tracking async appended events" do
200
200
  before do
201
- @mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, {})
201
+ @mixpanel = Mixpanel::Tracker.new MIX_PANEL_TOKEN
202
202
  exec_default_appends_on @mixpanel
203
203
  end
204
204
 
@@ -266,7 +266,7 @@ describe Mixpanel::Tracker::Middleware do
266
266
 
267
267
  describe "Tracking appended events" do
268
268
  before do
269
- @mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, {})
269
+ @mixpanel = Mixpanel::Tracker.new MIX_PANEL_TOKEN
270
270
  exec_default_appends_on @mixpanel
271
271
  end
272
272
 
@@ -2,20 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  describe Mixpanel::Tracker do
4
4
  before(:each) do
5
- @mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, @env = {"REMOTE_ADDR" => "127.0.0.1"})
5
+ @mixpanel = Mixpanel::Tracker.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.map(&:to_s).should include("@token", "@env")
10
+ @mixpanel.instance_variables.map(&:to_s).should include('@token', '@async', '@persist', '@env')
11
11
  end
12
12
  end
13
13
 
14
14
  context "Cleaning appended events" do
15
15
  it "should clear the queue" do
16
- @mixpanel.append_event("Sign up")
16
+ @mixpanel.append_track("Sign up")
17
17
  @mixpanel.queue.size.should == 1
18
- @mixpanel.clear_queue
18
+ @mixpanel.queue.clear
19
19
  @mixpanel.queue.size.should == 0
20
20
  end
21
21
  end
@@ -23,60 +23,31 @@ describe Mixpanel::Tracker do
23
23
  context "Accessing Mixpanel through direct request" do
24
24
  context "Tracking events" do
25
25
  it "should track simple events" do
26
- @mixpanel.track_event("Sign up").should == true
26
+ @mixpanel.track("Sign up").should == true
27
27
  end
28
-
29
- it "should call request method with token, time value and ip address" do
30
- params = {:event => "Sign up", :properties => {:token => MIX_PANEL_TOKEN, :time => Time.now.utc.to_i, :ip => "127.0.0.1"}}
31
-
32
- @mixpanel.should_receive(:request).with(:track, params).and_return("1")
33
- @mixpanel.track_event("Sign up").should == true
34
- end
35
-
36
- it "should call request method with token, and send ip address from HTTP_X_FORWARDED_FOR" do
37
- @mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, @env = {"HTTP_X_FORWARDED_FOR" => "10.1.0.2"})
38
-
39
- params = {:event => "Sign up", :properties => {:token => MIX_PANEL_TOKEN, :time => Time.now.utc.to_i, :ip => "10.1.0.2"}}
40
-
41
- @mixpanel.should_receive(:request).with(:track, params).and_return("1")
42
- @mixpanel.track_event("Sign up")
28
+
29
+ it "should track events with properties" do
30
+ @mixpanel.track('Sign up', { :likeable => true }, { :api_key => 'asdf' }).should == true
43
31
  end
44
32
  end
45
33
 
46
- context "Managing People" do
47
- it "should set person data" do
48
- @mixpanel.engage_set(DISTINCT_ID, :$email => 'test@example.com').should == true
34
+ context "Importing events" do
35
+ it "should import simple events" do
36
+ @mixpanel.import('Sign up').should == true
49
37
  end
50
38
 
51
- it "should add person data" do
52
- @mixpanel.engage_add(DISTINCT_ID, :custom => 99).should == true
39
+ it "should import events with properties" do
40
+ @mixpanel.import('Sign up', { :likeable => true }, { :api_key => 'asdf' }).should == true
53
41
  end
54
-
55
- it "should be able to call engage method directly" do
56
- @mixpanel.engage(:set, DISTINCT_ID, :$email => 'test@example.com').should == true
57
- end
58
-
59
- it "should call request method for setting" do
60
- params = {
61
- :$token => MIX_PANEL_TOKEN,
62
- :$distinct_id => DISTINCT_ID,
63
- :$set => {
64
- :$email => 'test@example.com',
65
- :custom => 'test'
66
- }}
67
- @mixpanel.should_receive(:request).with(:engage, params).and_return("1")
68
- @mixpanel.engage(:set, DISTINCT_ID, :email => 'test@example.com', :custom => 'test')
42
+ end
43
+
44
+ context "Engaging people" do
45
+ it "should set attributes" do
46
+ @mixpanel.set('person-a', { :email => 'me@domain.com', :likeable => false }).should == true
69
47
  end
70
48
 
71
- it "should call request method for adding" do
72
- params = {
73
- :$token => MIX_PANEL_TOKEN,
74
- :$distinct_id => DISTINCT_ID,
75
- :$add => {
76
- :custom => 99
77
- }}
78
- @mixpanel.should_receive(:request).with(:engage, params).and_return("1")
79
- @mixpanel.engage(:add, DISTINCT_ID, :custom => 99)
49
+ it "should increment attributes" do
50
+ @mixpanel.increment('person-a', { :tokens => 3, :money => -1 }).should == true
80
51
  end
81
52
  end
82
53
  end
@@ -84,47 +55,39 @@ describe Mixpanel::Tracker do
84
55
  context "Accessing Mixpanel through javascript API" do
85
56
  context "Appending events" do
86
57
  it "should store the event under the appropriate key" do
87
- @mixpanel.append_event("Sign up")
88
- @env.has_key?("mixpanel_events").should == true
58
+ @mixpanel.instance_variable_get(:@env).has_key?("mixpanel_events").should == true
89
59
  end
90
60
 
91
61
  it "should be the same the queue than env['mixpanel_events']" do
92
- @env['mixpanel_events'].object_id.should == @mixpanel.queue.object_id
62
+ @mixpanel.instance_variable_get(:@env)['mixpanel_events'].object_id.should == @mixpanel.queue.object_id
93
63
  end
94
64
 
95
65
  it "should append simple events" do
96
- @mixpanel.append_event("Sign up")
97
- mixpanel_queue_should_include(@mixpanel, "track", "Sign up", {})
66
+ props = { :time => Time.now, :ip => 'ASDF' }
67
+ @mixpanel.append_track "Sign up", props
68
+ mixpanel_queue_should_include(@mixpanel, "track", "Sign up", props)
98
69
  end
99
70
 
100
71
  it "should append events with properties" do
101
- @mixpanel.append_event("Sign up", {:referer => 'http://example.com'})
102
- mixpanel_queue_should_include(@mixpanel, "track", "Sign up", {:referer => 'http://example.com'})
72
+ props = { :referer => 'http://example.com', :time => Time.now, :ip => 'ASDF' }
73
+ @mixpanel.append_track "Sign up", props
74
+ mixpanel_queue_should_include(@mixpanel, "track", "Sign up", props)
103
75
  end
104
76
 
105
77
  it "should give direct access to queue" do
106
- @mixpanel.append_event("Sign up", {:referer => 'http://example.com'})
78
+ @mixpanel.append_track("Sign up", {:referer => 'http://example.com'})
107
79
  @mixpanel.queue.size.should == 1
108
80
  end
109
81
 
110
- it "should provide direct access to the JS api" do
111
- @mixpanel.append_api('track', "Sign up", {:referer => 'http://example.com'})
112
- mixpanel_queue_should_include(@mixpanel, "track", "Sign up", {:referer => 'http://example.com'})
113
- end
114
-
115
- it "should allow identify to be called through the JS api" do
116
- @mixpanel.append_api('identify', "some@one.com")
117
- mixpanel_queue_should_include(@mixpanel, "identify", "some@one.com")
118
- end
119
-
120
82
  it "should allow identify to be called through the JS api" do
121
- @mixpanel.append_api('identify', "some@one.com")
83
+ @mixpanel.append_identify "some@one.com"
122
84
  mixpanel_queue_should_include(@mixpanel, "identify", "some@one.com")
123
85
  end
124
86
 
125
87
  it "should allow the tracking of super properties in JS" do
126
- @mixpanel.append_api('register', {:user_id => 12345, :email => "some@one.com"})
127
- mixpanel_queue_should_include(@mixpanel, 'register', {:user_id => 12345, :email => "some@one.com"})
88
+ props = {:user_id => 12345, :gender => 'male'}
89
+ @mixpanel.append_register props
90
+ mixpanel_queue_should_include(@mixpanel, 'register', props)
128
91
  end
129
92
  end
130
93
  end
@@ -156,24 +119,4 @@ describe Mixpanel::Tracker do
156
119
  w2.should_not == w
157
120
  end
158
121
  end
159
-
160
- context "Request modes" do
161
- it "should use the track URL" do
162
- @mixpanel.track_event("Sign up")
163
- FakeWeb.last_request.path.to_s.include?(Mixpanel::Tracker::TRACK_ENDPOINT).should == true
164
- end
165
-
166
- it "should use the engage URL" do
167
- @mixpanel.engage(:set, DISTINCT_ID, :email => 'test@example.com')
168
- FakeWeb.last_request.path.to_s.include?(Mixpanel::Tracker::ENGAGE_ENDPOINT).should == true
169
- end
170
-
171
- it "should use the import URL" do
172
- @mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, @env = {"REMOTE_ADDR" => "127.0.0.1"}, { :import => true, :api_key => "ABCDEFG" })
173
- @mixpanel.track_event("Sign up")
174
- path = FakeWeb.last_request.path.to_s
175
- path.include?(Mixpanel::Tracker::IMPORT_ENDPOINT).should == true
176
- path.include?("&api_key=ABCDEFG").should == true
177
- end
178
- end
179
122
  end
data/spec/spec_helper.rb CHANGED
@@ -3,18 +3,28 @@ require File.join(File.dirname(__FILE__), "../lib", "mixpanel")
3
3
  require 'rack/test'
4
4
  require 'fakeweb'
5
5
  require 'nokogiri'
6
+ require 'active_support/core_ext/hash'
7
+
6
8
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
7
9
 
8
10
  MIX_PANEL_TOKEN = "e2d8b0bea559147844ffab3d607d26a6"
9
- DISTINCT_ID = "abcd1234"
11
+
10
12
 
11
13
  def mixpanel_queue_should_include(mixpanel, type, *arguments)
12
14
  mixpanel.queue.each do |event_type, event_arguments|
13
- event_arguments.should == arguments.map{|arg| arg.to_json}
14
- event_type.should == type
15
+ # hashes store keys in an undetermined order. convert to json and back and compare hash to hash, not json to json
16
+ unjsonify(event_arguments).should == json_and_back(arguments)
15
17
  end
16
18
  end
17
19
 
20
+ def json_and_back array
21
+ unjsonify array.collect { |arg| arg.to_json }
22
+ end
23
+
24
+ def unjsonify array
25
+ array.collect { |arg| JSON.parse(arg) rescue arg }
26
+ end
27
+
18
28
  # Fakeweb
19
29
  FakeWeb.allow_net_connect = false
20
30
  FakeWeb.register_uri(:any, /http:\/\/api\.mixpanel\.com.*/, :body => "1")
@@ -1,5 +1,5 @@
1
1
  def setup_rack_application(application, options = {}, mixpanel_options = {})
2
- stub!(:app).and_return(Mixpanel::Tracker::Middleware.new(application.new(options), MIX_PANEL_TOKEN, mixpanel_options))
2
+ stub!(:app).and_return(Mixpanel::Middleware.new(application.new(options), MIX_PANEL_TOKEN, mixpanel_options))
3
3
  end
4
4
 
5
5
  def html_document