test_track_rails_client 3.0.1 → 4.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: de83b3a3626b4f8852627295f9c84330b79cbe86
4
- data.tar.gz: cbb4f5236a634654c5521334fe194627388eaea4
3
+ metadata.gz: 15d95f4893c2f57f54d755bc1c8bb7130537767c
4
+ data.tar.gz: 5a26c66732114f90119b54636ae6e7122cb6efeb
5
5
  SHA512:
6
- metadata.gz: a7ffe3bffe66ea43947f12aeb17ca5ed33c1bdb164e635c27d1638b8f85f9ce83eb12a628fed6828abfd62799f6923dbc6e071591c2785eb483b675eeb24b96f
7
- data.tar.gz: fa05c8f371ad213edcf9d492b9218b3ac19fd1748a4cd4d8204db64d4c7980d5354ad079796f27242cf9829278d6cb12e16710e6ba6b614f14875012116709a1
6
+ metadata.gz: 654863b402ff1e8a8ae2257999afb947c1ac3875fbb205c6b8de628b439f7dfafc84066f51d167aa4feb9082ec97466a7bb3928a6111e7d4673eb63020278683
7
+ data.tar.gz: 6704876202051c7d04dec540c5adb74a6d20d8fc9344d616d014d9355959e542a317dbeb1d66facc5e28434ba1ac57a5669a52ae8097c82caa7b35dc852d7ec7
data/README.md CHANGED
@@ -349,9 +349,10 @@ Your client must implement the following methods:
349
349
  ```ruby
350
350
  # Called when a new Split has been Assigned
351
351
  #
352
- # @param visitor_id [String] TestTrack's unique visitor identification key
353
- # @param assignment [TestTrack::Assignment] The assignment model itself
354
- def track_assignment(visitor_id, assignment)
352
+ # @param analytics_event [TestTrack::AnalyticsEvent] An object
353
+ # representing an analytics event providing name and properties
354
+ # values you can send to your analytics backend
355
+ def track(analytics_event)
355
356
 
356
357
  # Called after TestTrack.sign_up!
357
358
  #
@@ -361,7 +362,7 @@ def sign_up!(visitor_id)
361
362
 
362
363
  ### Using TestTrack with a new analytics tool
363
364
 
364
- TestTrack manages its own visitor identifier which is different from the identifier of your analytics tool. We recommend using TestTrack's visitor identifier as your analytics identifier when possible. Within TestTrack Rails Client, assignment events will trigger a call to `TestTrack.analytics.track_assignment` with a TestTrack visitor identifier. To ensure that analytics events coming from within the browser have the right identifier, you must set the identifier when your analytics javascript library is loaded.
365
+ TestTrack manages its own visitor identifier which is different from the identifier of your analytics tool. We recommend using TestTrack's visitor identifier as your analytics identifier when possible. Within TestTrack Rails Client, assignment events will trigger a call to `TestTrack.analytics.track` with a TestTrack visitor identifier. To ensure that analytics events coming from within the browser have the right identifier, you must set the identifier when your analytics javascript library is loaded.
365
366
 
366
367
  Here's an example for how to do it with Mixpanel:
367
368
 
@@ -373,44 +374,15 @@ mixpanel.init('YOUR MIXPANEL TOKEN', {
373
374
  });
374
375
  ```
375
376
 
376
- ### Using TestTrack with an existing analytics tool
377
-
378
- In cases where you have already established identities with your analytics tool, you can use TestTrack's hooks to link TestTrack's visitor identifier to your analytics identifier.
379
-
380
- Using Mixpanel as an example, you must call [`mixpanel.alias`](https://mixpanel.com/help/questions/articles/assigning-your-own-unique-ids-to-users) with the visitor's analytics identifier and their TestTrack visitor identifier. This will establish a link between those two identifiers within your analytics tool, allowing you to analyze your funnels. We recommend using a thread-local storage like [`RequestStore`](https://github.com/steveklabnik/request_store) to make your identifier available to the TestTrack analytics client.
381
-
382
- In your controller, store the Mixpanel distinct ID in the RequestStore.
383
-
384
- ```ruby
385
- class ApplicationController < ActionController::Base
386
- before_action :store_mixpanel_distinct_id
387
-
388
- def store_mixpanel_distinct_id
389
- RequestStore[:mixpanel_distinct_id] = cookies["mp_#{ENV['MIXPANEL_TOKEN']}_mixpanel"]
390
- end
391
- end
392
- ```
377
+ ## Upgrading
393
378
 
394
- Then in your custom analytics plugin, use that value for assignment events and aliasing.
379
+ ### From 3.0 to 4.0
395
380
 
396
- ```ruby
397
- def track_assignment!(visitor_id)
398
- identifier = RequestStore[:mixpanel_distinct_id] || visitor_id
399
- properties = {
400
- SplitName: assignment.split_name,
401
- SplitVariant: assignment.variant,
402
- SplitContext: assignment.context
403
- }
404
-
405
- mixpanel.track(identifier, 'SplitAssigned', properties)
406
- end
407
-
408
- def sign_up!(visitor_id)
409
- mixpanel.alias(visitor_id, RequestStore[:mixpanel_distinct_id])
410
- end
411
- ```
412
-
413
- ## Upgrading
381
+ The contract of custom analytics plugins has changed. Instead of
382
+ implementing `track_assignment` you now must implement `track`. It's
383
+ easier and more conventional, though, and takes care of differentiating
384
+ between expiriment assignments and feature gate experiences, which are
385
+ no longer recorded server-side.
414
386
 
415
387
  ### From 2.0 to 3.0
416
388
 
@@ -16,36 +16,36 @@ module TestTrack::Identity
16
16
  end
17
17
 
18
18
  define_method :test_track_ab do |*args|
19
- discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
20
- discriminator.with_visitor do |v|
19
+ locator = TestTrack::IdentitySessionLocator.new(self)
20
+ locator.with_visitor do |v|
21
21
  v.ab(*args)
22
22
  end
23
23
  end
24
24
 
25
25
  define_method :test_track_vary do |*args, &block|
26
- discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
27
- discriminator.with_visitor do |v|
26
+ locator = TestTrack::IdentitySessionLocator.new(self)
27
+ locator.with_visitor do |v|
28
28
  v.vary(*args, &block)
29
29
  end
30
30
  end
31
31
 
32
32
  define_method :test_track_visitor_id do
33
- discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
34
- discriminator.with_visitor do |v|
33
+ locator = TestTrack::IdentitySessionLocator.new(self)
34
+ locator.with_visitor do |v|
35
35
  v.id
36
36
  end
37
37
  end
38
38
 
39
39
  define_method :test_track_sign_up! do
40
- discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
41
- discriminator.with_session do |session|
40
+ locator = TestTrack::IdentitySessionLocator.new(self)
41
+ locator.with_session do |session|
42
42
  session.sign_up! self
43
43
  end
44
44
  end
45
45
 
46
46
  define_method :test_track_log_in! do |opts = {}|
47
- discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
48
- discriminator.with_session do |session|
47
+ locator = TestTrack::IdentitySessionLocator.new(self)
48
+ locator.with_session do |session|
49
49
  session.log_in! self, opts
50
50
  end
51
51
  end
@@ -1,7 +1,7 @@
1
1
  module TestTrack::Analytics
2
2
  class MixpanelClient
3
- def track_assignment(visitor_id, assignment)
4
- mixpanel.track(visitor_id, 'SplitAssigned', split_properties(assignment).merge(TTVisitorID: visitor_id))
3
+ def track(analytics_event)
4
+ mixpanel.track(analytics_event.visitor_id, analytics_event.name, analytics_event.properties)
5
5
  end
6
6
 
7
7
  private
@@ -10,13 +10,5 @@ module TestTrack::Analytics
10
10
  raise "ENV['MIXPANEL_TOKEN'] must be set" unless ENV['MIXPANEL_TOKEN']
11
11
  @mixpanel ||= Mixpanel::Tracker.new(ENV['MIXPANEL_TOKEN'])
12
12
  end
13
-
14
- def split_properties(assignment)
15
- {
16
- SplitName: assignment.split_name,
17
- SplitVariant: assignment.variant,
18
- SplitContext: assignment.context
19
- }
20
- end
21
13
  end
22
14
  end
@@ -12,8 +12,8 @@ module TestTrack::Analytics
12
12
  @error_handler = handler
13
13
  end
14
14
 
15
- def track_assignment(visitor_id, assignment)
16
- safe_action { underlying.track_assignment(visitor_id, assignment) }
15
+ def track(analytics_event)
16
+ safe_action { underlying.track(analytics_event) }
17
17
  end
18
18
 
19
19
  def sign_up!(visitor_id)
@@ -0,0 +1,28 @@
1
+ module TestTrack
2
+ class AnalyticsEvent
3
+ attr_reader :assignment
4
+
5
+ delegate :visitor_id, to: :assignment
6
+
7
+ def initialize(assignment)
8
+ @assignment = assignment
9
+ end
10
+
11
+ def name
12
+ if assignment.feature_gate?
13
+ 'FeatureGateExperienced'
14
+ else
15
+ 'SplitAssigned'
16
+ end
17
+ end
18
+
19
+ def properties
20
+ {
21
+ TTVisitorID: visitor_id,
22
+ SplitName: assignment.split_name,
23
+ SplitVariant: assignment.variant,
24
+ SplitContext: assignment.context
25
+ }
26
+ end
27
+ end
28
+ end
@@ -19,6 +19,18 @@ class TestTrack::Assignment
19
19
  true
20
20
  end
21
21
 
22
+ def feature_gate?
23
+ split_name.end_with?('_enabled')
24
+ end
25
+
26
+ def analytics_event
27
+ @analytics_event ||= AnalyticsEvent.new(self)
28
+ end
29
+
30
+ def visitor_id
31
+ visitor.id
32
+ end
33
+
22
34
  private
23
35
 
24
36
  def _variant
@@ -1,7 +1,7 @@
1
1
  class TestTrack::Fake::Visitor
2
2
  attr_reader :id
3
3
 
4
- Assignment = Struct.new(:split_name, :variant, :unsynced, :context)
4
+ Assignment = Struct.new(:split_name, :variant, :unsynced, :context, :visitor_id)
5
5
 
6
6
  def self.instance
7
7
  @instance ||= new(TestTrack::FakeServer.seed)
@@ -28,7 +28,7 @@ class TestTrack::Fake::Visitor
28
28
  def _assignments
29
29
  split_registry.keys.map do |split_name|
30
30
  variant = TestTrack::VariantCalculator.new(visitor: self, split_name: split_name).variant
31
- Assignment.new(split_name, variant, false, "the_context")
31
+ Assignment.new(split_name, variant, false, "the_context", id)
32
32
  end
33
33
  end
34
34
  end
@@ -1,4 +1,4 @@
1
- class TestTrack::IdentitySessionDiscriminator
1
+ class TestTrack::IdentitySessionLocator
2
2
  attr_reader :identity
3
3
 
4
4
  def initialize(identity)
@@ -8,8 +8,8 @@ class TestTrack::IdentitySessionDiscriminator
8
8
  def with_visitor
9
9
  raise ArgumentError, "must provide block to `with_visitor`" unless block_given?
10
10
 
11
- if matching_identity?
12
- yield session.visitor_dsl
11
+ if web_context?
12
+ yield session.visitor_dsl_for(identity)
13
13
  else
14
14
  TestTrack::OfflineSession.with_visitor_for(identity.test_track_identifier_type, identity.test_track_identifier_value) do |v|
15
15
  yield v
@@ -29,10 +29,6 @@ class TestTrack::IdentitySessionDiscriminator
29
29
 
30
30
  private
31
31
 
32
- def matching_identity?
33
- session.present? && session.has_matching_identity?(identity)
34
- end
35
-
36
32
  def web_context?
37
33
  session.present?
38
34
  end
@@ -12,19 +12,22 @@ class TestTrack::NotifyAssignmentJob
12
12
  end
13
13
 
14
14
  def perform
15
- TestTrack::Remote::AssignmentEvent.create!(
16
- visitor_id: visitor_id,
17
- split_name: assignment.split_name,
18
- context: assignment.context,
19
- mixpanel_result: track
20
- )
15
+ tracking_result = track
16
+ unless assignment.feature_gate?
17
+ TestTrack::Remote::AssignmentEvent.create!(
18
+ visitor_id: visitor_id,
19
+ split_name: assignment.split_name,
20
+ context: assignment.context,
21
+ mixpanel_result: tracking_result
22
+ )
23
+ end
21
24
  end
22
25
 
23
26
  private
24
27
 
25
28
  def track
26
29
  return "failure" unless TestTrack.enabled?
27
- result = TestTrack.analytics.track_assignment(visitor_id, assignment)
30
+ result = TestTrack.analytics.track(assignment.analytics_event)
28
31
  result ? "success" : "failure"
29
32
  end
30
33
  end
@@ -16,6 +16,27 @@ class TestTrack::Session
16
16
  notify_unsynced_assignments! if sync_assignments?
17
17
  end
18
18
 
19
+ def visitor_dsl_for(identity)
20
+ if has_matching_identity?(identity)
21
+ visitor_dsl
22
+ else
23
+ TestTrack::VisitorDSL.new(visitors_by_identity[identity])
24
+ end
25
+ end
26
+
27
+ def visitors_by_identity
28
+ @visitors_by_identity ||= Hash.new do |visitors_by_identity, identity|
29
+ remote_visitor = TestTrack::Remote::Visitor.from_identifier(
30
+ identity.test_track_identifier_type,
31
+ identity.test_track_identifier_value
32
+ )
33
+ visitors_by_identity[identity] = TestTrack::Visitor.new(
34
+ id: remote_visitor.id,
35
+ assignments: remote_visitor.assignments
36
+ )
37
+ end
38
+ end
39
+
19
40
  def visitor_dsl
20
41
  @visitor_dsl ||= TestTrack::VisitorDSL.new(visitor)
21
42
  end
@@ -1,3 +1,3 @@
1
1
  module TestTrackRailsClient
2
- VERSION = "3.0.1" # rubocop:disable Style/MutableConstant
2
+ VERSION = "4.0.0.alpha1" # rubocop:disable Style/MutableConstant
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test_track_rails_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 4.0.0.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan O'Neill
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2018-04-23 00:00:00.000000000 Z
16
+ date: 2018-04-28 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: airbrake
@@ -259,6 +259,7 @@ files:
259
259
  - app/models/test_track/ab_configuration.rb
260
260
  - app/models/test_track/analytics/mixpanel_client.rb
261
261
  - app/models/test_track/analytics/safe_wrapper.rb
262
+ - app/models/test_track/analytics_event.rb
262
263
  - app/models/test_track/assignment.rb
263
264
  - app/models/test_track/config_updater.rb
264
265
  - app/models/test_track/fake/split_detail.rb
@@ -266,7 +267,7 @@ files:
266
267
  - app/models/test_track/fake/visitor.rb
267
268
  - app/models/test_track/fake/visitor_detail.rb
268
269
  - app/models/test_track/fake_server.rb
269
- - app/models/test_track/identity_session_discriminator.rb
270
+ - app/models/test_track/identity_session_locator.rb
270
271
  - app/models/test_track/misconfiguration_notifier.rb
271
272
  - app/models/test_track/notify_assignment_job.rb
272
273
  - app/models/test_track/offline_session.rb
@@ -356,9 +357,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
356
357
  version: 2.1.0
357
358
  required_rubygems_version: !ruby/object:Gem::Requirement
358
359
  requirements:
359
- - - ">="
360
+ - - ">"
360
361
  - !ruby/object:Gem::Version
361
- version: '0'
362
+ version: 1.3.1
362
363
  requirements: []
363
364
  rubyforge_project:
364
365
  rubygems_version: 2.5.1