mixpal 0.0.5 → 0.1.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +5 -0
  4. data/README.md +7 -11
  5. data/Rakefile +8 -1
  6. data/lib/mixpal.rb +7 -7
  7. data/lib/mixpal/event.rb +4 -4
  8. data/lib/mixpal/integration.rb +7 -7
  9. data/lib/mixpal/tracker.rb +29 -26
  10. data/lib/mixpal/user.rb +9 -7
  11. data/lib/mixpal/util.rb +3 -3
  12. data/lib/mixpal/version.rb +1 -1
  13. data/mixpanel_assistant.gemspec +1 -0
  14. data/spec/lib/mixpal/event_spec.rb +19 -17
  15. data/spec/lib/mixpal/tracker_spec.rb +127 -149
  16. data/spec/lib/mixpal/user_spec.rb +36 -30
  17. data/spec/lib/mixpal/util_spec.rb +15 -14
  18. data/spec/lib/mixpal_spec.rb +2 -2
  19. data/spec/spec_helper.rb +4 -6
  20. data/spec/support/matchers/element_matchers.rb +2 -2
  21. data/test_app/.gitignore +16 -0
  22. data/test_app/Gemfile +11 -0
  23. data/test_app/README.rdoc +28 -0
  24. data/test_app/Rakefile +6 -0
  25. data/test_app/app/assets/images/.keep +0 -0
  26. data/test_app/app/assets/javascripts/application.js +16 -0
  27. data/test_app/app/assets/stylesheets/application.css +15 -0
  28. data/test_app/app/controllers/application_controller.rb +12 -0
  29. data/test_app/app/controllers/concerns/.keep +0 -0
  30. data/test_app/app/controllers/redirects_controller.rb +10 -0
  31. data/test_app/app/helpers/application_helper.rb +2 -0
  32. data/test_app/app/mailers/.keep +0 -0
  33. data/test_app/app/models/.keep +0 -0
  34. data/test_app/app/models/concerns/.keep +0 -0
  35. data/test_app/app/views/layouts/application.html.erb +16 -0
  36. data/test_app/app/views/redirects/new.html.erb +1 -0
  37. data/test_app/bin/bundle +3 -0
  38. data/test_app/bin/rails +8 -0
  39. data/test_app/bin/rake +8 -0
  40. data/test_app/bin/spring +18 -0
  41. data/test_app/config.ru +4 -0
  42. data/test_app/config/application.rb +30 -0
  43. data/test_app/config/boot.rb +4 -0
  44. data/test_app/config/environment.rb +5 -0
  45. data/test_app/config/environments/development.rb +37 -0
  46. data/test_app/config/environments/production.rb +82 -0
  47. data/test_app/config/environments/test.rb +39 -0
  48. data/test_app/config/initializers/assets.rb +8 -0
  49. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test_app/config/initializers/cookies_serializer.rb +3 -0
  51. data/test_app/config/initializers/filter_parameter_logging.rb +4 -0
  52. data/test_app/config/initializers/inflections.rb +16 -0
  53. data/test_app/config/initializers/mime_types.rb +4 -0
  54. data/test_app/config/initializers/session_store.rb +3 -0
  55. data/test_app/config/initializers/wrap_parameters.rb +14 -0
  56. data/test_app/config/locales/en.yml +23 -0
  57. data/test_app/config/routes.rb +4 -0
  58. data/test_app/config/secrets.yml +22 -0
  59. data/test_app/db/seeds.rb +7 -0
  60. data/test_app/lib/assets/.keep +0 -0
  61. data/test_app/lib/tasks/.keep +0 -0
  62. data/test_app/log/.keep +0 -0
  63. data/test_app/public/404.html +67 -0
  64. data/test_app/public/422.html +67 -0
  65. data/test_app/public/500.html +66 -0
  66. data/test_app/public/favicon.ico +0 -0
  67. data/test_app/public/robots.txt +5 -0
  68. data/test_app/vendor/assets/javascripts/.keep +0 -0
  69. data/test_app/vendor/assets/stylesheets/.keep +0 -0
  70. metadata +67 -6
  71. data/spec/support/mock_rails.rb +0 -6
  72. data/spec/support/mock_storage.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f7b06bf4a86525182d6d44a19848532e62cc51a
4
- data.tar.gz: eb38535ae4ef5a101b61a8d30c0a4ed041c04b9d
3
+ metadata.gz: c04724d3a3e803dfd392c4635ee4480a41e959d4
4
+ data.tar.gz: 0ddb3d1b74618d3523cf32ed59ddbbbf39df457a
5
5
  SHA512:
6
- metadata.gz: 8d4079b4038dad025ca08dfaefcb1239abeacbedccb1c0c7553e1cdaa8cea64849cd03717d83cf2315ede897b85634a55d6950e6de299dbd61f3354f9d97a08d
7
- data.tar.gz: 883548ba1bb19454caa6052e2d812efe80f09680b22b1647034865f0c885042b462d1412a37ac152ca1c2786ee89e61ea827a721f6fce11331aab1346907380f
6
+ metadata.gz: 33668e11499b7a84380c2421d710213af257c858ed45cdc017c4e1aec0855277c73f65f818a323dc35ef520cc3484f8cbd320ff9dff3d9a0940dfebfbe25633f
7
+ data.tar.gz: 2ac2f904b86d599230c60b0d9a7f31327f03c3920ed60b2ce221ac1414992a556ed021951001852060bb3d88eabd38e0122697fa8d2a64a6f3d475568b47215f
@@ -0,0 +1,23 @@
1
+ Encoding:
2
+ Enabled: false
3
+
4
+ Documentation:
5
+ Enabled: false
6
+
7
+ ClassAndModuleChildren:
8
+ Enabled: false
9
+
10
+ ClassLength:
11
+ Enabled: false
12
+
13
+ MethodLength:
14
+ Enabled: false
15
+
16
+ DoubleNegation:
17
+ Enabled: false
18
+
19
+ AllCops:
20
+ Include:
21
+ - "Rakefile"
22
+ Exclude:
23
+ - "test_app/**/*"
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - 1.9.3
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Mixpal
1
+ # Mixpal [![Build Status](https://travis-ci.org/patbenatar/mixpal.svg?branch=master)](https://travis-ci.org/patbenatar/mixpal) [![Code Climate](https://codeclimate.com/github/patbenatar/mixpal/badges/gpa.svg)](https://codeclimate.com/github/patbenatar/mixpal)
2
2
 
3
3
  As the JavaScript library is Mixpanel's preferred method of usage,
4
4
  Mixpal aims to make it easier to work with from your Rails backend.
@@ -80,7 +80,7 @@ As with `register_user`, this method will also identify "special properties".
80
80
 
81
81
  ### Persistance Across Redirects
82
82
 
83
- Mixpal stores any tracked events or user data in `Rails.cache` when
83
+ Mixpal stores any tracked events or user data in the session when
84
84
  it detects a redirect so it can output the appropriate Mixpanel JS integration
85
85
  code to the client on the following render. This enables us to do cool things
86
86
  like:
@@ -104,16 +104,12 @@ class UsersController < ActionController::Base
104
104
  end
105
105
  ```
106
106
 
107
- #### Customizing the storage adapter
107
+ #### A note about `CookieStore` size limit
108
108
 
109
- You can specify a custom persistence storage adapter like so:
110
-
111
- ```ruby
112
- Mixpal::Tracker.storage = MyCustomAdapter.new
113
- ```
114
-
115
- Storage adapters must implement the following API: `write(key, value)`,
116
- `read(key)`, and `delete(key)`.
109
+ When using Rails' default `ActionDispatch::Session::CookieStore`, a 4K cookie
110
+ size limit is enforced. This cookie is shared by anything using the session.
111
+ If you anticipate tracking many events or large data sets to Mixpal,
112
+ [consider a different session store](http://guides.rubyonrails.org/action_controller_overview.html#session).
117
113
 
118
114
  ## Contributing
119
115
 
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: [:spec, :rubocop]
@@ -1,10 +1,10 @@
1
- require "mixpal/version"
2
- require "active_support/core_ext"
1
+ require 'mixpal/version'
2
+ require 'active_support/core_ext'
3
3
 
4
4
  module Mixpal
5
- autoload :Util, "mixpal/util"
6
- autoload :Tracker, "mixpal/tracker"
7
- autoload :Event, "mixpal/event"
8
- autoload :User, "mixpal/user"
9
- autoload :Integration, "mixpal/integration"
5
+ autoload :Util, 'mixpal/util'
6
+ autoload :Tracker, 'mixpal/tracker'
7
+ autoload :Event, 'mixpal/event'
8
+ autoload :User, 'mixpal/user'
9
+ autoload :Integration, 'mixpal/integration'
10
10
  end
@@ -14,13 +14,13 @@ module Mixpal
14
14
 
15
15
  def to_store
16
16
  {
17
- name: name,
18
- properties: properties,
17
+ 'name' => name,
18
+ 'properties' => properties
19
19
  }
20
20
  end
21
21
 
22
22
  def self.from_store(data)
23
- new(data[:name], data[:properties])
23
+ new(data['name'], data['properties'])
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -10,25 +10,25 @@ module Mixpal
10
10
  def self.mixpanel_identity(object_method, attribute_method)
11
11
  self.mixpanel_identity_data = {
12
12
  object_method: object_method,
13
- attribute_method: attribute_method,
13
+ attribute_method: attribute_method
14
14
  }
15
15
  end
16
16
  end
17
17
 
18
18
  def mixpanel
19
19
  @mixpanel ||= begin
20
- identity = if data = self.class.mixpanel_identity_data
21
- send(data[:object_method]).try(data[:attribute_method])
22
- end
20
+ identity = if (data = self.class.mixpanel_identity_data)
21
+ send(data[:object_method]).try(data[:attribute_method])
22
+ end
23
23
 
24
- Mixpal::Tracker.new(identity: identity)
24
+ Mixpal::Tracker.new(identity: identity).tap { |t| t.restore!(session) }
25
25
  end
26
26
  end
27
27
 
28
28
  private
29
29
 
30
30
  def store_mixpanel_if_redirecting
31
- mixpanel.store! if status == 302
31
+ mixpanel.store!(session) if status == 302
32
32
  end
33
33
  end
34
- end
34
+ end
@@ -2,16 +2,12 @@ module Mixpal
2
2
  class Tracker
3
3
  attr_reader :events, :user_updates, :identity, :alias_user
4
4
 
5
- STORAGE_KEY = "mixpal"
6
- class_attribute :storage
7
- self.storage = Rails.cache
5
+ STORAGE_KEY = 'mixpal'
8
6
 
9
- def initialize(args={})
7
+ def initialize(args = {})
10
8
  @events = []
11
9
  @user_updates = []
12
10
 
13
- restore!
14
-
15
11
  @identity = args[:identity]
16
12
  end
17
13
 
@@ -24,44 +20,51 @@ module Mixpal
24
20
  user_updates << Mixpal::User.new(properties)
25
21
  end
26
22
 
27
- def track(name, properties={})
23
+ def track(name, properties = {})
28
24
  events << Mixpal::Event.new(name, properties)
29
25
  end
30
26
 
31
27
  def render
32
- "".tap do |html|
33
- html << "<script type=\"text/javascript\">"
28
+ ''.tap do |html|
29
+ html << '<script type="text/javascript">'
34
30
  html << "mixpanel.alias(\"#{identity}\");" if alias_user
35
31
  html << "mixpanel.identify(\"#{identity}\");" if identity
36
- html << events.map(&:render).join("")
37
- html << user_updates.map(&:render).join("")
38
- html << "</script>"
32
+ html << events.map(&:render).join('')
33
+ html << user_updates.map(&:render).join('')
34
+ html << '</script>'
39
35
  end.html_safe
40
36
  end
41
37
 
42
- def store!
43
- self.class.storage.write(STORAGE_KEY, to_store)
38
+ def store!(session)
39
+ session[STORAGE_KEY] = to_store
44
40
  end
45
41
 
46
- private
42
+ def restore!(session)
43
+ data = session[STORAGE_KEY] || {}
44
+
45
+ @alias_user = data['alias_user']
46
+ @identity ||= data['identity']
47
47
 
48
- def restore!
49
- data = self.class.storage.read(STORAGE_KEY) || {}
48
+ if data['events']
49
+ @events = data['events'].map { |e| Mixpal::Event.from_store(e) }
50
+ end
50
51
 
51
- @alias_user = data[:alias_user]
52
- @identity = data[:identity]
53
- @events = data[:events].map { |e| Mixpal::Event.from_store(e) } if data[:events]
54
- @user_updates = data[:user_updates].map { |u| Mixpal::User.from_store(u) } if data[:user_updates]
52
+ if data['user_updates']
53
+ @user_updates = data['user_updates']
54
+ .map { |u| Mixpal::User.from_store(u) }
55
+ end
55
56
 
56
- self.class.storage.delete(STORAGE_KEY)
57
+ session.delete(STORAGE_KEY)
57
58
  end
58
59
 
60
+ private
61
+
59
62
  def to_store
60
63
  {
61
- alias_user: @alias_user,
62
- identity: identity,
63
- events: events.map(&:to_store),
64
- user_updates: user_updates.map(&:to_store),
64
+ 'alias_user' => alias_user,
65
+ 'identity' => identity,
66
+ 'events' => events.map(&:to_store),
67
+ 'user_updates' => user_updates.map(&:to_store)
65
68
  }
66
69
  end
67
70
  end
@@ -12,12 +12,12 @@ module Mixpal
12
12
 
13
13
  def to_store
14
14
  {
15
- properties: properties,
15
+ 'properties' => properties
16
16
  }
17
17
  end
18
18
 
19
19
  def self.from_store(data)
20
- new(data[:properties])
20
+ new(data['properties'])
21
21
  end
22
22
 
23
23
  private
@@ -29,15 +29,17 @@ module Mixpal
29
29
  # Isolate special properties and rename their keys to align with
30
30
  # Mixpanel's naming.
31
31
  def properties_for_mixpanel
32
- Hash[properties.map {|k, v| [mixpanel_special_properties_map[k] || k, v] }]
32
+ Hash[
33
+ properties.map { |k, v| [mixpanel_special_properties_map[k] || k, v] }
34
+ ]
33
35
  end
34
36
 
35
37
  def mixpanel_special_properties_map
36
38
  {
37
- name: "$name",
38
- email: "$email",
39
- created_at: "$created",
39
+ name: '$name',
40
+ email: '$email',
41
+ created_at: '$created'
40
42
  }.with_indifferent_access
41
43
  end
42
44
  end
43
- end
45
+ end
@@ -2,12 +2,12 @@ module Mixpal
2
2
  module Util
3
3
  class << self
4
4
  def hash_to_js_object_string(hash)
5
- hash.reject! { |k,v| v.nil? }
5
+ hash.reject! { |_, v| v.nil? }
6
6
 
7
- contents = hash.map do |k,v|
7
+ contents = hash.map do |k, v|
8
8
  js_value = v.is_a?(String) || v.is_a?(Time) ? "\"#{v}\"" : v
9
9
  "\"#{k}\": #{js_value}"
10
- end.join(",").html_safe
10
+ end.join(',').html_safe
11
11
 
12
12
  "{#{contents}}"
13
13
  end
@@ -1,3 +1,3 @@
1
1
  module Mixpal
2
- VERSION = "0.0.5"
2
+ VERSION = '0.1.0'
3
3
  end
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "rubocop", "~> 0.24.1"
24
25
  spec.add_development_dependency "rspec", "~> 2.14.0"
25
26
  spec.add_development_dependency "guard-rspec", "~> 3.0.3"
26
27
  spec.add_development_dependency "rb-fsevent", "~> 0.9.3"
@@ -1,48 +1,50 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
3
  describe Mixpal::Event do
4
- let(:name) { "Event 1" }
5
- let(:properties) { { title: "Awesome Product" } }
4
+ let(:name) { 'Event 1' }
5
+ let(:properties) { { title: 'Awesome Product' } }
6
6
  subject { described_class.new(name, properties) }
7
7
 
8
- describe "#render" do
9
- it "delegates to Util for js_object composition" do
8
+ describe '#render' do
9
+ it 'delegates to Util for js_object composition' do
10
10
  Mixpal::Util.should_receive(:hash_to_js_object_string).with(properties)
11
11
  subject.render
12
12
  end
13
13
 
14
- it "outputs a call to track" do
14
+ it 'outputs a call to track' do
15
15
  js_object = Mixpal::Util.hash_to_js_object_string(properties)
16
16
  expect(subject.render).to eq "mixpanel.track(\"#{name}\", #{js_object});"
17
17
  end
18
18
 
19
- it "outputs an html safe string" do
19
+ it 'outputs an html safe string' do
20
20
  expect(subject.render).to be_html_safe
21
21
  end
22
22
  end
23
23
 
24
- describe "#to_store" do
25
- it "returns a hash with its data" do
24
+ describe '#to_store' do
25
+ it 'returns a hash with its data' do
26
26
  expect(subject.to_store).to eq(
27
- name: name,
28
- properties: properties,
27
+ 'name' => name,
28
+ 'properties' => properties
29
29
  )
30
30
  end
31
31
  end
32
32
 
33
- describe ".from_store" do
34
- let(:result) { described_class.from_store(name: name, properties: properties) }
33
+ describe '.from_store' do
34
+ let(:result) do
35
+ described_class.from_store('name' => name, 'properties' => properties)
36
+ end
35
37
 
36
- it "instantiates a new instance" do
38
+ it 'instantiates a new instance' do
37
39
  expect(result).to be_an_instance_of(described_class)
38
40
  end
39
41
 
40
- it "sets its name from the data" do
42
+ it 'sets its name from the data' do
41
43
  expect(result.name).to eq name
42
44
  end
43
45
 
44
- it "sets its properties from the data" do
46
+ it 'sets its properties from the data' do
45
47
  expect(result.properties).to eq properties
46
48
  end
47
49
  end
48
- end
50
+ end
@@ -1,278 +1,256 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
3
  describe Mixpal::Tracker do
4
4
  subject { Mixpal::Tracker.new }
5
- let(:identity) { "nick" }
5
+ let(:identity) { 'nick' }
6
6
  let(:subject_with_identity) { Mixpal::Tracker.new(identity: identity) }
7
7
 
8
- describe "custom storage adapter" do
9
- before do
10
- @original_adapter = described_class.storage
11
-
12
- MyCustomStorageAdapter = Class.new(MockStorage)
13
- @adapter_instance = MyCustomStorageAdapter.new
14
-
15
- described_class.storage = @adapter_instance
16
- end
17
-
18
- after { described_class.storage = @original_adapter }
19
-
20
- it "uses the specified adapter" do
21
- @adapter_instance.should_receive :write
22
- subject.store!
23
- end
24
- end
25
-
26
- describe "#initialize" do
27
- it "creates an empty set of events" do
8
+ describe '#initialize' do
9
+ it 'creates an empty set of events' do
28
10
  expect(subject.events).to eq []
29
11
  end
30
12
 
31
- it "creates an empty set of user_updates" do
13
+ it 'creates an empty set of user_updates' do
32
14
  expect(subject.user_updates).to eq []
33
15
  end
34
16
 
35
- context "with an :identity arg" do
17
+ context 'with an :identity arg' do
36
18
  subject { subject_with_identity }
37
19
 
38
- it "sets the identity" do
39
- expect(subject.identity).to eq "nick"
40
- end
41
- end
42
-
43
- context "when data exists in storage" do
44
- let(:old_tracker) { Mixpal::Tracker.new(identity: identity) }
45
-
46
- before do
47
- old_tracker.track "Event 1"
48
- old_tracker.register_user name: "Nick Giancola"
49
- old_tracker.store!
50
- end
51
-
52
- it "restores the alias_user property" do
53
- expect(subject.alias_user).to eq true
54
- end
55
-
56
- it "restores the events" do
57
- expect(subject.events.size).to eq 1
58
- end
59
-
60
- it "delegates event restoration to the Event class" do
61
- Mixpal::Event.should_receive(:from_store).
62
- with(old_tracker.events.first.to_store)
63
-
64
- subject
65
- end
66
-
67
- it "restores the events" do
68
- expect(subject.events.size).to eq 1
69
- end
70
-
71
- context "when initialized with an identity" do
72
- subject { Mixpal::Tracker.new(identity: "Franky") }
73
-
74
- it "overrides anything from storage" do
75
- expect(subject.identity).to eq "Franky"
76
- end
20
+ it 'sets the identity' do
21
+ expect(subject.identity).to eq 'nick'
77
22
  end
78
23
  end
79
24
  end
80
25
 
81
- describe "#register_user" do
82
- it "sets the alias_user flag so we render the alias call" do
83
- subject.register_user(name: "Nick")
26
+ describe '#register_user' do
27
+ it 'sets the alias_user flag so we render the alias call' do
28
+ subject.register_user(name: 'Nick')
84
29
  expect(subject.alias_user).to be_true
85
30
  end
86
31
 
87
- it "delegates to #update_user for tracking user properties" do
88
- properties = { name: "Nick" }
32
+ it 'delegates to #update_user for tracking user properties' do
33
+ properties = { name: 'Nick' }
89
34
  subject.should_receive(:update_user).with(properties)
90
35
  subject.register_user(properties)
91
36
  end
92
37
  end
93
38
 
94
- describe "#update_user" do
95
- it "instantiates a new User object with properties" do
96
- properties = { name: "Nick" }
39
+ describe '#update_user' do
40
+ it 'instantiates a new User object with properties' do
41
+ properties = { name: 'Nick' }
97
42
  Mixpal::User.should_receive(:new).with(properties)
98
43
  subject.update_user(properties)
99
44
  end
100
45
 
101
- it "adds the User to user_updates for rendering later" do
46
+ it 'adds the User to user_updates for rendering later' do
102
47
  expect do
103
- subject.update_user(name: "Nick")
48
+ subject.update_user(name: 'Nick')
104
49
  end.to change(subject.user_updates, :size).by(1)
105
50
 
106
51
  subject.user_updates.first.should be_an_instance_of(Mixpal::User)
107
52
  end
108
53
  end
109
54
 
110
- describe "#track" do
111
- it "instantiates a new Event object with properties" do
112
- name = "Clicked Button"
113
- properties = { color: "Green" }
55
+ describe '#track' do
56
+ it 'instantiates a new Event object with properties' do
57
+ name = 'Clicked Button'
58
+ properties = { color: 'Green' }
114
59
 
115
60
  Mixpal::Event.should_receive(:new).with(name, properties)
116
61
  subject.track(name, properties)
117
62
  end
118
63
 
119
- it "adds the Event to events for rendering later" do
64
+ it 'adds the Event to events for rendering later' do
120
65
  expect do
121
- subject.track("Clicked Button", color: "Green")
66
+ subject.track('Clicked Button', color: 'Green')
122
67
  end.to change(subject.events, :size).by(1)
123
68
 
124
69
  subject.events.first.should be_an_instance_of(Mixpal::Event)
125
70
  end
126
71
  end
127
72
 
128
- describe "#render" do
129
- it "outputs script tag" do
130
- expect(subject.render).to have_tag("script")
73
+ describe '#render' do
74
+ it 'outputs script tag' do
75
+ expect(subject.render).to have_tag('script')
131
76
  end
132
77
 
133
- it "outputs an html safe string" do
78
+ it 'outputs an html safe string' do
134
79
  expect(subject.render).to be_html_safe
135
80
  end
136
81
 
137
- context "with an identity" do
82
+ context 'with an identity' do
138
83
  subject { subject_with_identity }
139
84
 
140
- it "outputs call to identify" do
85
+ it 'outputs call to identify' do
141
86
  expect(subject.render).to include "mixpanel.identify(\"#{identity}\");"
142
87
  end
143
88
 
144
- context "when user is being registered" do
145
- before { subject.register_user({ name: "Nick Giancola" }) }
89
+ context 'when user is being registered' do
90
+ before { subject.register_user(name: 'Nick Giancola') }
146
91
 
147
- it "outputs call to alias by identity" do
92
+ it 'outputs call to alias by identity' do
148
93
  expect(subject.render).to include "mixpanel.alias(\"#{identity}\");"
149
94
  end
150
95
  end
151
96
  end
152
97
 
153
- context "with no registered user" do
154
- it "does not output call to alias" do
155
- expect(subject.render).not_to include "mixpanel.alias"
98
+ context 'with no registered user' do
99
+ it 'does not output call to alias' do
100
+ expect(subject.render).not_to include 'mixpanel.alias'
156
101
  end
157
102
  end
158
103
 
159
- context "without an identity" do
160
- it "does not output call to identify" do
161
- expect(subject.render).not_to include "mixpanel.indentify"
104
+ context 'without an identity' do
105
+ it 'does not output call to identify' do
106
+ expect(subject.render).not_to include 'mixpanel.indentify'
162
107
  end
163
108
  end
164
109
 
165
- context "with tracked events" do
110
+ context 'with tracked events' do
166
111
  before do
167
- subject.track("Event 1", { color: "Green" })
168
- subject.track("Event 2", { title: "Something Awesome" })
112
+ subject.track('Event 1', color: 'Green')
113
+ subject.track('Event 2', title: 'Something Awesome')
169
114
  end
170
115
 
171
- it "delegates render to the events" do
116
+ it 'delegates render to the events' do
172
117
  subject.events.each { |event| event.should_receive :render }
173
118
  subject.render
174
119
  end
175
120
 
176
- it "joins each rendered event" do
121
+ it 'joins each rendered event' do
177
122
  joined = subject.events[0].render + subject.events[1].render
178
123
  expect(subject.render).to include joined
179
124
  end
180
125
  end
181
126
 
182
- context "with user properties" do
127
+ context 'with user properties' do
183
128
  before do
184
- subject.update_user({ name: "Hank" })
185
- subject.update_user({ location: "Los Angeles" })
129
+ subject.update_user(name: 'Hank')
130
+ subject.update_user(location: 'Los Angeles')
186
131
  end
187
132
 
188
- it "delegates render to the users" do
133
+ it 'delegates render to the users' do
189
134
  subject.user_updates.each { |user| user.should_receive :render }
190
135
  subject.render
191
136
  end
192
137
 
193
- it "joins each rendered user" do
138
+ it 'joins each rendered user' do
194
139
  joined = subject.user_updates[0].render + subject.user_updates[1].render
195
140
  expect(subject.render).to include joined
196
141
  end
197
142
  end
198
143
  end
199
144
 
200
- describe "#store!" do
201
- let(:storage) { described_class::storage }
202
-
203
- after { MockRails.cache.delete(described_class::STORAGE_KEY) }
145
+ describe '#store!' do
146
+ let(:session) { {} }
204
147
 
205
148
  def storage_should_include(hash_fragment)
206
- storage.should_receive(:write).with(
207
- described_class::STORAGE_KEY,
208
- hash_including(hash_fragment)
209
- )
210
- end
211
-
212
- it "writes to the storage adapter" do
213
- storage.should_receive(:write)
214
- subject.store!
149
+ expect(session[described_class::STORAGE_KEY]).to include hash_fragment
215
150
  end
216
151
 
217
- context "when alias_user is set" do
218
- before { subject.register_user({}) }
219
-
220
- it "stores the alias_user property" do
221
- storage_should_include(alias_user: true)
222
- subject.store!
223
- end
152
+ it 'stores the alias_user property' do
153
+ subject.register_user({})
154
+ subject.store!(session)
155
+ storage_should_include('alias_user' => true)
224
156
  end
225
157
 
226
- context "when identity is set" do
227
- subject { subject_with_identity }
228
-
229
- it "stores the identity" do
230
- storage_should_include(identity: identity)
231
- subject.store!
232
- end
158
+ it 'stores the identity' do
159
+ subject_with_identity.store!(session)
160
+ storage_should_include('identity' => identity)
233
161
  end
234
162
 
235
- context "when events have been tracked" do
163
+ context 'when events have been tracked' do
236
164
  before do
237
- subject.track("Event 1", { color: "Green" })
238
- subject.track("Event 2", { title: "Something Awesome" })
165
+ subject.track('Event 1', color: 'Green')
166
+ subject.track('Event 2', title: 'Something Awesome')
239
167
  end
240
168
 
241
- it "delegates composition to the events" do
169
+ it 'delegates composition to the events' do
242
170
  subject.events.each { |event| event.should_receive :to_store }
243
- subject.store!
171
+ subject.store!(session)
244
172
  end
245
173
 
246
- it "stores the events' composed hashes in an array" do
174
+ it 'stores the events composed hashes in an array' do
175
+ subject.store!(session)
247
176
  storage_should_include(
248
- events: [subject.events[0].to_store, subject.events[1].to_store]
177
+ 'events' => [subject.events[0].to_store, subject.events[1].to_store]
249
178
  )
250
-
251
- subject.store!
252
179
  end
253
180
  end
254
181
 
255
- context "when user properties have been updated" do
182
+ context 'when user properties have been updated' do
256
183
  before do
257
- subject.update_user({ name: "Hank" })
258
- subject.update_user({ location: "Los Angeles" })
184
+ subject.update_user(name: 'Hank')
185
+ subject.update_user(location: 'Los Angeles')
259
186
  end
260
187
 
261
- it "delegates composition to the users" do
188
+ it 'delegates composition to the users' do
262
189
  subject.user_updates.each { |user| user.should_receive :to_store }
263
- subject.store!
190
+ subject.store!(session)
264
191
  end
265
192
 
266
- it "stores the users' composed hashes in an array" do
193
+ it 'stores the users composed hashes in an array' do
194
+ subject.store!(session)
195
+
267
196
  storage_should_include(
268
- user_updates: [
197
+ 'user_updates' => [
269
198
  subject.user_updates[0].to_store,
270
199
  subject.user_updates[1].to_store
271
200
  ]
272
201
  )
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#restore!' do
207
+ let(:old_tracker) { Mixpal::Tracker.new(identity: identity) }
208
+ let(:session) { {} }
209
+
210
+ before do
211
+ old_tracker.track 'Event 1'
212
+ old_tracker.register_user name: 'Nick Giancola'
213
+ old_tracker.store!(session)
214
+ end
215
+
216
+ it 'restores the alias_user property' do
217
+ subject.restore!(session)
218
+ expect(subject.alias_user).to eq true
219
+ end
220
+
221
+ it 'restores the events' do
222
+ subject.restore!(session)
223
+ expect(subject.events.size).to eq 1
224
+ end
225
+
226
+ it 'delegates event restoration to the Event class' do
227
+ Mixpal::Event.should_receive(:from_store)
228
+ .with(old_tracker.events.first.to_store)
229
+
230
+ subject.restore!(session)
231
+ end
232
+
233
+ it 'restores the events' do
234
+ subject.restore!(session)
235
+ expect(subject.events.size).to eq 1
236
+ end
237
+
238
+ context 'with a different identity (e.g. after login)' do
239
+ subject { Mixpal::Tracker.new(identity: "#{identity}-2") }
240
+
241
+ it 'does not override identity with value in storage' do
242
+ subject.restore!(session)
243
+ expect(subject.identity).to eq "#{identity}-2"
244
+ end
245
+ end
246
+
247
+ context 'with no identity (e.g. after logout)' do
248
+ subject { Mixpal::Tracker.new(identity: nil) }
273
249
 
274
- subject.store!
250
+ it 'overrides identity with value in storage' do
251
+ subject.restore!(session)
252
+ expect(subject.identity).to eq identity
275
253
  end
276
254
  end
277
255
  end
278
- end
256
+ end