mixpanel-mail 0.1.1 → 0.1.2

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/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in mixpanel-mail.gemspec
4
4
  gemspec
@@ -10,4 +10,5 @@ gem 'rake'
10
10
  group :development do
11
11
  gem "rspec", "~> 2.6.0"
12
12
  gem "webmock", "~> 1.7.4"
13
+ gem 'actionmailer', '~> 3.1.0'
13
14
  end
@@ -1,16 +1,55 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mixpanel-mail (0.1.0)
4
+ mixpanel-mail (0.1.2)
5
5
  multi_json
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
+ actionmailer (3.1.0)
11
+ actionpack (= 3.1.0)
12
+ mail (~> 2.3.0)
13
+ actionpack (3.1.0)
14
+ activemodel (= 3.1.0)
15
+ activesupport (= 3.1.0)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ i18n (~> 0.6)
19
+ rack (~> 1.3.2)
20
+ rack-cache (~> 1.0.3)
21
+ rack-mount (~> 0.8.2)
22
+ rack-test (~> 0.6.1)
23
+ sprockets (~> 2.0.0)
24
+ activemodel (3.1.0)
25
+ activesupport (= 3.1.0)
26
+ bcrypt-ruby (~> 3.0.0)
27
+ builder (~> 3.0.0)
28
+ i18n (~> 0.6)
29
+ activesupport (3.1.0)
30
+ multi_json (~> 1.0)
10
31
  addressable (2.2.6)
32
+ bcrypt-ruby (3.0.1)
33
+ builder (3.0.0)
11
34
  crack (0.3.1)
12
35
  diff-lcs (1.1.3)
36
+ erubis (2.7.0)
37
+ hike (1.2.1)
38
+ i18n (0.6.0)
39
+ mail (2.3.0)
40
+ i18n (>= 0.4.0)
41
+ mime-types (~> 1.16)
42
+ treetop (~> 1.4.8)
43
+ mime-types (1.16)
13
44
  multi_json (1.0.3)
45
+ polyglot (0.3.2)
46
+ rack (1.3.3)
47
+ rack-cache (1.0.3)
48
+ rack (>= 0.4)
49
+ rack-mount (0.8.3)
50
+ rack (>= 1.0.0)
51
+ rack-test (0.6.1)
52
+ rack (>= 1.0)
14
53
  rake (0.9.2)
15
54
  rspec (2.6.0)
16
55
  rspec-core (~> 2.6.0)
@@ -20,6 +59,14 @@ GEM
20
59
  rspec-expectations (2.6.0)
21
60
  diff-lcs (~> 1.1.2)
22
61
  rspec-mocks (2.6.0)
62
+ sprockets (2.0.0)
63
+ hike (~> 1.2)
64
+ rack (~> 1.0)
65
+ tilt (!= 1.3.0, ~> 1.1)
66
+ tilt (1.3.3)
67
+ treetop (1.4.10)
68
+ polyglot
69
+ polyglot (>= 0.3.1)
23
70
  webmock (1.7.6)
24
71
  addressable (> 2.2.5, ~> 2.2)
25
72
  crack (>= 0.1.7)
@@ -28,6 +75,7 @@ PLATFORMS
28
75
  ruby
29
76
 
30
77
  DEPENDENCIES
78
+ actionmailer (~> 3.1.0)
31
79
  mixpanel-mail!
32
80
  rake
33
81
  rspec (~> 2.6.0)
@@ -7,7 +7,8 @@ require 'digest/md5'
7
7
 
8
8
  module ActionMailer
9
9
  class MixpanelInterceptor
10
- cattr_accessor :token
10
+ cattr_accessor :token, :logger
11
+ self.logger = Rails.logger if defined?(Rails)
11
12
 
12
13
  class << self
13
14
  def activate!(token)
@@ -16,35 +17,36 @@ module ActionMailer
16
17
  end
17
18
 
18
19
  def delivering_email(mail)
19
- # Skip Mixpanel if the campaign is not specified
20
- return unless mail.header['mp_campaign']
21
-
22
- # Skip Mixpanel if we don't have HTML
23
- html = mail.html_part ? mail.html_part.body : nil
24
- return unless html.present?
25
-
26
- # Convert header options to mixpanel options
20
+ # Remove all the Mixpanel headers from the email
27
21
  opts = ::Mixpanel::Mail::OPTIONS.inject({}) do |sum, key|
28
- if value = pop_mp_header(mail, key)
29
- sum[key] = value
22
+ if field = pop_mp_header(mail, key)
23
+ sum[key] = field.value
30
24
  end
31
25
  sum
32
26
  end
33
27
 
28
+ # Skip Mixpanel if the campaign is not specified
29
+ return unless opts['campaign']
30
+
31
+ # Skip Mixpanel if we don't have HTML
32
+ html = mail.html_part ? mail.html_part.decoded : nil
33
+ return unless html.present?
34
+
34
35
  # Generate email distinct_id for Mixpanel
35
36
  id = Digest::MD5.hexdigest(mail.header['To'].to_s)
36
37
 
37
38
  begin
38
39
  mail.html_part.body = mp_mail.add_tracking(id, html, opts)
39
40
  rescue => e
40
- Rails.logger.warn("Failed to Mixpanelize Mail: #{e}")
41
41
  mail.html_part.body = html
42
+ logger.warn("Failed to Mixpanelize Mail: #{e}")
43
+ logger.debug(e.backtrace.join("\n"))
42
44
  end
43
45
  end
44
46
 
45
47
  private
46
48
  def mp_mail
47
- @mixpanel_mail ||= Mixpanel::Mail.new(token, 'default')
49
+ @mixpanel_mail ||= Mixpanel::Mail.new(token)
48
50
  end
49
51
 
50
52
  def pop_mp_header(mail, key)
@@ -13,13 +13,14 @@ module Mixpanel
13
13
  ENDPOINT = 'http://api.mixpanel.com/email'
14
14
  ENDPOINT_URI = URI.parse(ENDPOINT)
15
15
  OPTIONS = %w(campaign type properties redirect_host click_tracking)
16
+ DEFAULT_CAMPAIGN = 'default'
16
17
 
17
18
  attr_accessor :params
18
19
 
19
- def initialize(token, campaign, options = {})
20
+ def initialize(token, options = {})
20
21
  @params = {}
21
22
  params['token'] = token
22
- params['campaign'] = campaign
23
+ params['campaign'] = DEFAULT_CAMPAIGN
23
24
  params.merge!(groom_options(options))
24
25
  end
25
26
 
@@ -1,5 +1,5 @@
1
1
  module Mixpanel
2
2
  class Mail
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+ require 'logger'
3
+ require 'mail'
4
+ require 'action_mailer'
5
+ require 'action_mailer/mixpanel_interceptor'
6
+
7
+ describe ActionMailer::MixpanelInterceptor do
8
+ MI = ActionMailer::MixpanelInterceptor
9
+ TOKEN = 'abcd123'
10
+ TO_ADDY = 'test@gemfury.com'
11
+ HTML_BODY = '<h1>HTML</h1>'
12
+
13
+ before do
14
+ MI.token = TOKEN
15
+ MI.logger = Logger.new($stdout)
16
+ end
17
+
18
+ describe '::delivering_email' do
19
+ before do
20
+ @mail = Mail::Message.new do
21
+ to TO_ADDY
22
+ body 'Hello World!'
23
+ end
24
+ end
25
+
26
+ it 'should ignore mails without any MP options' do
27
+ MI.delivering_email(@mail)
28
+ a_post.should_not have_been_made
29
+ end
30
+
31
+ ### Shared Examples for All Emails ###
32
+ shared_examples_for 'all emails' do
33
+ it 'should remove all Mixpanel headers' do
34
+ MI.delivering_email(@mail)
35
+ default_headers.keys do |key|
36
+ @mail.header[key].should be_nil
37
+ end
38
+ end
39
+ end
40
+
41
+ ### Shared Examples for Emails for non-Mixpanel emails ###
42
+ shared_examples_for 'ignored Mixpanel email' do
43
+ it_should_behave_like 'all emails'
44
+ it 'should not make a Mixpanel request' do
45
+ MI.delivering_email(@mail)
46
+ a_post.should_not have_been_made
47
+ end
48
+ end
49
+
50
+ describe 'with MP headers without mp_campaign' do
51
+ before do
52
+ apply_headers(@mail, default_headers(:campaign => nil))
53
+ @mail.html_part { body(HTML_BODY) }
54
+ end
55
+
56
+ it_should_behave_like 'ignored Mixpanel email'
57
+ end
58
+
59
+ describe 'with Mixpanel headers' do
60
+ before do
61
+ apply_headers(@mail, default_headers)
62
+ end
63
+
64
+ describe 'without HTML email part' do
65
+ it_should_behave_like 'ignored Mixpanel email'
66
+ end
67
+
68
+ describe 'with HTML email part' do
69
+ before do
70
+ @mail.html_part { body(HTML_BODY) }
71
+ stub_post
72
+ end
73
+
74
+ it_should_behave_like 'all emails'
75
+
76
+ it 'should make a request to Mixpanel' do
77
+ params = Mixpanel::Mail.new(TOKEN, default_params).params
78
+ params['distinct_id'] = Digest::MD5.hexdigest(TO_ADDY)
79
+ params['body'] = HTML_BODY
80
+
81
+ verify_mixpanel_requests(params) do
82
+ MI.delivering_email(@mail)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+ def apply_headers(mail, headers)
91
+ headers.each { |k, v| mail.header[k] = v }
92
+ end
93
+
94
+ def default_headers(headers = {})
95
+ out = {}
96
+ default_params(headers).each do |key, value|
97
+ out["mp_#{key}".to_sym] = value
98
+ end
99
+ out
100
+ end
101
+
102
+ def default_params(headers = {})
103
+ { :campaign => 'my-test-campaign',
104
+ :properties => { :foo => :bar },
105
+ :redirect_host => 'mp.testhost.com',
106
+ :type => 'text' }.merge(headers)
107
+ end
108
+ end
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mixpanel::Mail do
4
- TOKEN, CAMPAIGN = 'abcd123', 'my-email'
4
+ TOKEN, CAMPAIGN = 'abcd123', Mixpanel::Mail::DEFAULT_CAMPAIGN
5
5
 
6
- it 'should intialize token & campaign' do
6
+ it 'should intialize token & default campaign' do
7
7
  lambda {
8
8
  mail = mp_mail
9
9
  mail.params['token'].should eq(TOKEN)
@@ -88,7 +88,7 @@ describe Mixpanel::Mail do
88
88
 
89
89
  private
90
90
  def mp_mail(options = {})
91
- ::Mixpanel::Mail.new(TOKEN, CAMPAIGN, options)
91
+ ::Mixpanel::Mail.new(TOKEN, options)
92
92
  end
93
93
 
94
94
  def mp_option_check(key, value_expectations = {})
@@ -99,14 +99,15 @@ private
99
99
  end
100
100
 
101
101
  def verify_request_with_options(options = {}, expectations = {})
102
- stub_post
103
- mp_mail(options).add_tracking('my-dist-id', 'Hello World!')
104
- mp_mail.add_tracking('my-dist-id', 'Hello World!', options)
105
- a_post.with(:body => expectations.merge(
106
- 'token' => TOKEN,
107
- 'campaign' => CAMPAIGN,
108
- 'distinct_id' => 'my-dist-id',
109
- 'body' => 'Hello World!'
110
- )).should have_been_made.twice
102
+ expectations = expectations.merge(
103
+ 'token' => TOKEN,
104
+ 'campaign' => CAMPAIGN,
105
+ 'distinct_id' => 'my-dist-id',
106
+ 'body' => 'Hello World!')
107
+
108
+ verify_mixpanel_requests(expectations, 2) do
109
+ mp_mail(options).add_tracking('my-dist-id', 'Hello World!')
110
+ mp_mail.add_tracking('my-dist-id', 'Hello World!', options)
111
+ end
111
112
  end
112
113
  end
@@ -7,4 +7,11 @@
7
7
  self.class.send(:define_method, "stub_#{method}") do
8
8
  stub_request(method, Mixpanel::Mail::ENDPOINT)
9
9
  end
10
+ end
11
+
12
+ # Allow to set expectations for a mixpanel request
13
+ def verify_mixpanel_requests(body = {}, num = 1, &block)
14
+ stub_post
15
+ block && block.call
16
+ a_post.with(:body => body).should have_been_made.times(num)
10
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixpanel-mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-27 00:00:00.000000000Z
12
+ date: 2011-09-28 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
- requirement: &70109454407540 !ruby/object:Gem::Requirement
16
+ requirement: &70185098031860 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70109454407540
24
+ version_requirements: *70185098031860
25
25
  description: Helpers for Mixpanel Tracking in Emails
26
26
  email:
27
27
  - mrykov@gmail.com
@@ -40,6 +40,7 @@ files:
40
40
  - lib/mixpanel_mail/vendor/active_support/core_ext/hash/slice.rb
41
41
  - lib/mixpanel_mail/version.rb
42
42
  - mixpanel-mail.gemspec
43
+ - spec/action_mailer/mixpanel_interceptor_spec.rb
43
44
  - spec/mixpanel/mail_spec.rb
44
45
  - spec/spec_helper.rb
45
46
  - spec/support/webmock.rb
@@ -68,6 +69,7 @@ signing_key:
68
69
  specification_version: 3
69
70
  summary: Helpers for Mixpanel Tracking in Emails
70
71
  test_files:
72
+ - spec/action_mailer/mixpanel_interceptor_spec.rb
71
73
  - spec/mixpanel/mail_spec.rb
72
74
  - spec/spec_helper.rb
73
75
  - spec/support/webmock.rb