test_track_rails_client 1.2.0 → 1.3.0

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: 2e89607653cb61940fedd99d80d61957a0bf57a1
4
- data.tar.gz: dd88c45263723f36ac874a066dce626d24b85cc8
3
+ metadata.gz: 30685a58f06262e141d5deb48bce124da381861e
4
+ data.tar.gz: 22c790111f624535e1165bba5ad83b68b765944b
5
5
  SHA512:
6
- metadata.gz: a49693c2afd28427caacc2398673a8dc6442eabfa57bbc00a8d999343b7bf9220c0fd8a0c6dfba72bfb28e1a91009e67d97e7d77e229aee611190b7caa9a20bb
7
- data.tar.gz: ea250b67d413d2e3e6acd8b854d5bb9799cce2d2b6105570af3c192813cfcaff655d8e50cfb19218a35007003225005a95f4025bed779d541f9b6bcd91c0325c
6
+ metadata.gz: 7452da90b5d34c19107e6a446908fd48034e094997b0c40f612b9fdf4c3c10b0c7f80779eed9981294184c7982f39919a83b5086671b47bf42970dc2adca3106
7
+ data.tar.gz: 805507d3629c7cd387a0f90604a9e0725fa234360bd4d575a84a7f756c698440a39d088f29cc0dd642ff2bb9da947b581600d1584f6432a6cef07820a75634f6
data/README.md CHANGED
@@ -8,6 +8,17 @@ It provides server-side split-testing and feature-toggling through a simple API.
8
8
 
9
9
  If you're looking to do client-side assignment, then check out our [JS client](https://github.com/Betterment/test_track_js_client).
10
10
 
11
+ * [Installation](#installation)
12
+ * [Concepts](#concepts)
13
+ * [Configuring the TestTrack server from your app](#configuring-the-testtrack-server-from-your-app)
14
+ * [Varying app behavior based on assigned variant](#varying-app-behavior-based-on-assigned-variant)
15
+ * [Tracking visitor logins](#tracking-visitor-logins)
16
+ * [Tracking signups](#tracking-signups)
17
+ * [Testing splits](#testing-splits)
18
+ * [Custom Analytics](#custom-analytics)
19
+ * [Upgrading](#upgrading)
20
+ * [How to Contribute](#how-to-contribute)
21
+
11
22
  ## Installation
12
23
 
13
24
  Install the gem:
@@ -349,6 +360,12 @@ def track_assignment(visitor_id, assignment, properties)
349
360
  def alias(visitor_id, existing_id)
350
361
  ```
351
362
 
363
+ ## Upgrading
364
+
365
+ ### From 1.x to 1.3
366
+
367
+ `TestTrack::Session#log_in!` and `TestTrack:Session#sign_up!` now take a `TestTrack::Identity` instance argument instead of an identity type and identity value.
368
+
352
369
  ## How to Contribute
353
370
 
354
371
  We would love for you to contribute! Anything that benefits the majority of `test_track` users—from a documentation fix to an entirely new feature—is encouraged.
@@ -18,7 +18,7 @@ module TestTrack::Controller
18
18
  end
19
19
 
20
20
  def manage_test_track_session
21
- RequestStore[:test_track_controller] = self
21
+ RequestStore[:test_track_session] = test_track_session
22
22
  test_track_session.manage do
23
23
  yield
24
24
  end
@@ -2,74 +2,54 @@ module TestTrack::Identity
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  module ClassMethods
5
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity
6
- def test_track_identifier(identifier_type, identifier_value_method)
5
+ def test_track_identifier(identifier_type, identifier_value_method) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
7
6
  instance_methods = Module.new
8
7
  include instance_methods
9
8
 
10
9
  instance_methods.module_eval do
10
+ define_method :test_track_identifier_type do
11
+ identifier_type
12
+ end
13
+
14
+ define_method :test_track_identifier_value do
15
+ send(identifier_value_method)
16
+ end
17
+
11
18
  define_method :test_track_ab do |*args|
12
19
  discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
13
-
14
- if discriminator.authenticated_resource_matches_identity?
15
- discriminator.controller.send(:test_track_visitor).ab(*args)
16
- else
17
- identifier_value = send(identifier_value_method)
18
- TestTrack::OfflineSession.with_visitor_for(identifier_type, identifier_value) do |v|
19
- v.ab(*args)
20
- end
20
+ discriminator.with_visitor do |v|
21
+ v.ab(*args)
21
22
  end
22
23
  end
23
24
 
24
25
  define_method :test_track_vary do |*args, &block|
25
26
  discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
26
-
27
- if discriminator.authenticated_resource_matches_identity?
28
- discriminator.controller.send(:test_track_visitor).vary(*args, &block)
29
- else
30
- identifier_value = send(identifier_value_method)
31
- TestTrack::OfflineSession.with_visitor_for(identifier_type, identifier_value) do |v|
32
- v.vary(*args, &block)
33
- end
27
+ discriminator.with_visitor do |v|
28
+ v.vary(*args, &block)
34
29
  end
35
30
  end
36
31
 
37
32
  define_method :test_track_visitor_id do
38
33
  discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
39
-
40
- if discriminator.authenticated_resource_matches_identity?
41
- discriminator.controller.send(:test_track_visitor).id
42
- else
43
- identifier_value = send(identifier_value_method)
44
- TestTrack::OfflineSession.with_visitor_for(identifier_type, identifier_value) do |v|
45
- v.id
46
- end
34
+ discriminator.with_visitor do |v|
35
+ v.id
47
36
  end
48
37
  end
49
38
 
50
39
  define_method :test_track_sign_up! do
51
40
  discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
52
-
53
- if discriminator.web_context?
54
- identifier_value = send(identifier_value_method)
55
- discriminator.controller.send(:test_track_session).sign_up! identifier_type, identifier_value
56
- else
57
- raise "test_track_sign_up! called outside of a web context"
41
+ discriminator.with_session do |session|
42
+ session.sign_up! self
58
43
  end
59
44
  end
60
45
 
61
46
  define_method :test_track_log_in! do |opts = {}|
62
47
  discriminator = TestTrack::IdentitySessionDiscriminator.new(self)
63
-
64
- if discriminator.web_context?
65
- identifier_value = send(identifier_value_method)
66
- discriminator.controller.send(:test_track_session).log_in! identifier_type, identifier_value, opts
67
- else
68
- raise "test_track_log_in! called outside of a web context"
48
+ discriminator.with_session do |session|
49
+ session.log_in! self, opts
69
50
  end
70
51
  end
71
52
  end
72
53
  end
73
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity
74
54
  end
75
55
  end
@@ -5,26 +5,39 @@ class TestTrack::IdentitySessionDiscriminator
5
5
  @identity = identity
6
6
  end
7
7
 
8
- def controller
9
- @controller ||= RequestStore[:test_track_controller]
10
- end
8
+ def with_visitor
9
+ raise ArgumentError, "must provide block to `with_visitor`" unless block_given?
11
10
 
12
- def authenticated_resource_matches_identity?
13
- controller_has_authenticated_resource? && controller.send(authenticated_resource_method_name) == identity
11
+ if matching_identity?
12
+ yield session.visitor_dsl
13
+ else
14
+ TestTrack::OfflineSession.with_visitor_for(identity.test_track_identifier_type, identity.test_track_identifier_value) do |v|
15
+ yield v
16
+ end
17
+ end
14
18
  end
15
19
 
16
- def web_context?
17
- controller.present?
20
+ def with_session
21
+ raise ArgumentError, "must provide block to `with_session`" unless block_given?
22
+
23
+ if web_context?
24
+ yield session
25
+ else
26
+ raise "#with_session called outside of web context"
27
+ end
18
28
  end
19
29
 
20
30
  private
21
31
 
22
- def controller_has_authenticated_resource?
23
- # pass true to `respond_to?` to include private methods
24
- web_context? && controller.respond_to?(authenticated_resource_method_name, true)
32
+ def matching_identity?
33
+ session.present? && session.has_matching_identity?(identity)
34
+ end
35
+
36
+ def web_context?
37
+ session.present?
25
38
  end
26
39
 
27
- def authenticated_resource_method_name
28
- @authenticated_resource_method_name ||= "current_#{identity.class.model_name.element}"
40
+ def session
41
+ @session ||= RequestStore[:test_track_session]
29
42
  end
30
43
  end
@@ -31,18 +31,48 @@ class TestTrack::Session
31
31
  }
32
32
  end
33
33
 
34
- def log_in!(identifier_type, identifier_value, opts = {})
34
+ def log_in!(*args) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
35
+ opts = args[-1].is_a?(Hash) ? args.pop : {}
36
+
37
+ if args[0].is_a?(TestTrack::Identity)
38
+ identity = args[0]
39
+ identifier_type = identity.test_track_identifier_type
40
+ identifier_value = identity.test_track_identifier_value
41
+ else
42
+ identifier_type = args[0]
43
+ identifier_value = args[1]
44
+ warn "#log_in! with two args is deprecated. Please provide a TestTrack::Identity"
45
+ end
46
+
35
47
  @visitor = TestTrack::Visitor.new if opts[:forget_current_visitor]
36
48
  visitor.link_identifier!(identifier_type, identifier_value)
49
+
50
+ identities << identity if identity.present?
37
51
  self.mixpanel_distinct_id = visitor.id
38
52
  true
39
53
  end
40
54
 
41
- def sign_up!(identifier_type, identifier_value)
55
+ def sign_up!(*args) # rubocop:disable Metrics/MethodLength
56
+ if args[0].is_a?(TestTrack::Identity)
57
+ identity = args[0]
58
+ identifier_type = identity.test_track_identifier_type
59
+ identifier_value = identity.test_track_identifier_value
60
+ else
61
+ identifier_type = args[0]
62
+ identifier_value = args[1]
63
+ warn "#sign_up! with two args is deprecated. Please provide a TestTrack::Identity"
64
+ end
65
+
42
66
  visitor.link_identifier!(identifier_type, identifier_value)
67
+
68
+ identities << identity if identity.present?
43
69
  @signed_up = true
44
70
  end
45
71
 
72
+ def has_matching_identity?(identity)
73
+ identities.include?(identity)
74
+ end
75
+
46
76
  private
47
77
 
48
78
  attr_reader :controller, :signed_up
@@ -215,4 +245,8 @@ class TestTrack::Session
215
245
  end
216
246
  end
217
247
  end
248
+
249
+ def identities
250
+ @identities ||= TestTrack::SessionIdentityCollection.new(controller)
251
+ end
218
252
  end
@@ -0,0 +1,29 @@
1
+ class TestTrack::SessionIdentityCollection
2
+ def initialize(controller)
3
+ @controller = controller
4
+ end
5
+
6
+ def include?(identity)
7
+ found_identity = identities[identity.test_track_identifier_type] || authenticated_resource_for_identity(identity)
8
+ found_identity.present? && found_identity == identity
9
+ end
10
+
11
+ def <<(identity)
12
+ identities[identity.test_track_identifier_type] = identity
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :controller
18
+
19
+ def identities
20
+ @identities ||= {}
21
+ end
22
+
23
+ def authenticated_resource_for_identity(identity)
24
+ authenticated_resource_method_name = "current_#{identity.class.model_name.element}"
25
+
26
+ # pass true to `respond_to?` to include private methods
27
+ controller.respond_to?(authenticated_resource_method_name, true) && controller.send(authenticated_resource_method_name)
28
+ end
29
+ end
@@ -1,3 +1,3 @@
1
1
  module TestTrackRailsClient
2
- VERSION = "1.2.0" # rubocop:disable Style/MutableConstant
2
+ VERSION = "1.3.0" # 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: 1.2.0
4
+ version: 1.3.0
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: 2017-08-01 00:00:00.000000000 Z
16
+ date: 2017-10-02 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: rails
@@ -291,6 +291,7 @@ files:
291
291
  - app/models/test_track/remote/visitor.rb
292
292
  - app/models/test_track/remote/visitor_detail.rb
293
293
  - app/models/test_track/session.rb
294
+ - app/models/test_track/session_identity_collection.rb
294
295
  - app/models/test_track/unsynced_assignments_notifier.rb
295
296
  - app/models/test_track/variant_calculator.rb
296
297
  - app/models/test_track/vary_dsl.rb
@@ -441,7 +442,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
441
442
  version: '0'
442
443
  requirements: []
443
444
  rubyforge_project:
444
- rubygems_version: 2.5.1
445
+ rubygems_version: 2.6.13
445
446
  signing_key:
446
447
  specification_version: 4
447
448
  summary: Rails client for TestTrack