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 +4 -4
- data/README.md +17 -0
- data/app/controllers/concerns/test_track/controller.rb +1 -1
- data/app/models/concerns/test_track/identity.rb +19 -39
- data/app/models/test_track/identity_session_discriminator.rb +25 -12
- data/app/models/test_track/session.rb +36 -2
- data/app/models/test_track/session_identity_collection.rb +29 -0
- data/lib/test_track_rails_client/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30685a58f06262e141d5deb48bce124da381861e
|
4
|
+
data.tar.gz: 22c790111f624535e1165bba5ad83b68b765944b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
9
|
-
|
10
|
-
end
|
8
|
+
def with_visitor
|
9
|
+
raise ArgumentError, "must provide block to `with_visitor`" unless block_given?
|
11
10
|
|
12
|
-
|
13
|
-
|
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
|
17
|
-
|
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
|
23
|
-
|
24
|
-
|
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
|
28
|
-
@
|
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!(
|
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!(
|
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
|
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.
|
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-
|
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.
|
445
|
+
rubygems_version: 2.6.13
|
445
446
|
signing_key:
|
446
447
|
specification_version: 4
|
447
448
|
summary: Rails client for TestTrack
|