growthbook 0.3.0 → 1.0.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.
@@ -1,43 +0,0 @@
1
- module Growthbook
2
- class ExperimentResult
3
- # The experiment that was performed
4
- # @return [Growthbook::Experiment, nil] If nil, then the experiment with the required id could not be found
5
- attr_reader :experiment
6
-
7
- # The user that was experimented on
8
- # @return [Growthbook::User]
9
- attr_reader :user
10
-
11
- # The chosen variation. -1 for "not in experiment", 0 for control, 1 for 1st variation, etc.
12
- # @return [Integer]
13
- attr_reader :variation
14
-
15
- # The data tied to the chosen variation
16
- # @return [Hash]
17
- attr_reader :data
18
-
19
- @forced = false
20
-
21
- def forced?
22
- @forced
23
- end
24
-
25
- def shouldTrack?
26
- !@forced && @variation >= 0
27
- end
28
-
29
- def initialize(user = nil, experiment = nil, variation = -1, forced = false)
30
- @experiment = experiment
31
- @variation = variation
32
- @forced = forced
33
-
34
- @data = {}
35
- if experiment && experiment.data
36
- var = variation < 0 ? 0 : variation
37
- experiment.data.each do |k, v|
38
- @data[k] = v[var]
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,44 +0,0 @@
1
- module Growthbook
2
- class LookupResult
3
- # The first matching experiment
4
- # @return [Growthbook::Experiment]
5
- attr_reader :experiment
6
-
7
- # The chosen variation. -1 for "not in experiment", 0 for control, 1 for 1st variation, etc.
8
- # @return [Integer]
9
- attr_reader :variation
10
-
11
- # The data tied to the chosen variation
12
- # @return [Hash]
13
- attr_reader :data
14
-
15
- # The value of the data key that was used to lookup the experiment
16
- attr_reader :value
17
-
18
- @forced
19
-
20
- def forced?
21
- @forced
22
- end
23
-
24
- def shouldTrack?
25
- !@forced && @variation >= 0
26
- end
27
-
28
- def initialize(result, key)
29
- @experiment = result.experiment
30
- @variation = result.variation
31
- @forced = result.forced?
32
-
33
- @data = {}
34
- if @experiment && @experiment.data
35
- var = @variation <0 ? 0 : @variation
36
- @experiment.data.each do |k, v|
37
- @data[k] = v[var]
38
- end
39
- end
40
-
41
- @value = @data[key] || nil
42
- end
43
- end
44
- end
@@ -1,165 +0,0 @@
1
- require 'set'
2
-
3
- module Growthbook
4
- class User
5
- # @returns [String, nil]
6
- attr_accessor :id
7
-
8
- # @returns [String, nil]
9
- attr_accessor :anonId
10
-
11
- # @returns [Hash, nil]
12
- attr_reader :attributes
13
-
14
- # @returns [Array<Growthbook::ExperimentResult>]
15
- attr_reader :resultsToTrack
16
-
17
- @client
18
- @attributeMap = {}
19
- @experimentsTracked
20
-
21
- def initialize(anonId, id, attributes, client)
22
- @anonId = anonId
23
- @id = id
24
- @attributes = attributes
25
- @client = client
26
- updateAttributeMap
27
-
28
- @resultsToTrack = []
29
- @experimentsTracked = Set[]
30
- end
31
-
32
- # Set the user attributes
33
- #
34
- # @params attributes [Hash, nil] Any user attributes you want to use for experiment targeting
35
- # Values can be any type, even nested arrays and hashes
36
- def attributes=(attributes)
37
- @attributes = attributes
38
- updateAttributeMap
39
- end
40
-
41
- # Run an experiment on this user
42
- # @param experiment [Growthbook::Experiment, String] If string, will lookup the experiment by id in the client
43
- # @return [Growthbook::ExperimentResult]
44
- def experiment(experiment)
45
- # If experiments are disabled globally
46
- return getExperimentResult unless @client.enabled
47
-
48
- # Make sure experiment is always an object (or nil)
49
- id = ""
50
- if experiment.is_a? String
51
- id = experiment
52
- experiment = @client.getExperiment(id)
53
- else
54
- id = experiment.id
55
- override = @client.getExperiment(id)
56
- experiment = override if override
57
- end
58
-
59
- # No experiment found
60
- return getExperimentResult unless experiment
61
-
62
- # User missing required user id type
63
- userId = experiment.anon ? @anonId : @id
64
- if !userId
65
- return getExperimentResult(experiment)
66
- end
67
-
68
- # Experiment has targeting rules, check if user passes
69
- if experiment.targeting
70
- return getExperimentResult(experiment) unless isTargeted(experiment.targeting)
71
- end
72
-
73
- # Experiment has a specific variation forced
74
- if experiment.force != nil
75
- return getExperimentResult(experiment, experiment.force, true)
76
- end
77
-
78
- # Choose a variation for the user
79
- variation = Growthbook::Util.chooseVariation(userId, experiment)
80
- result = getExperimentResult(experiment, variation)
81
-
82
- # Add to the list of experiments that should be tracked in analytics
83
- if result.shouldTrack? && !@experimentsTracked.include?(experiment.id)
84
- @experimentsTracked << experiment.id
85
- @resultsToTrack << result
86
- end
87
-
88
- return result
89
- end
90
-
91
- # Run the first matching experiment that defines variation data for the requested key
92
- # @param key [String, Symbol] The key to look up
93
- # @return [Growthbook::LookupResult, nil] If nil, no matching experiments found
94
- def lookupByDataKey(key)
95
- @client.experiments.each do |exp|
96
- if exp.data && exp.data.key?(key)
97
- ret = experiment(exp)
98
- if ret.variation >= 0
99
- return Growthbook::LookupResult.new(ret, key)
100
- end
101
- end
102
- end
103
-
104
- return nil
105
- end
106
-
107
- private
108
-
109
- def getExperimentResult(experiment = nil, variation = -1, forced = false)
110
- Growthbook::ExperimentResult.new(self, experiment, variation, forced)
111
- end
112
-
113
- def flattenUserValues(prefix, val)
114
- if val.nil?
115
- return []
116
- end
117
-
118
- if val.is_a? Hash
119
- ret = []
120
- val.each do |k, v|
121
- ret.concat(flattenUserValues(prefix.length>0 ? prefix.to_s + "." + k.to_s : k.to_s, v))
122
- end
123
- return ret
124
- end
125
-
126
- if val.is_a? Array
127
- val = val.join ","
128
- elsif !!val == val
129
- val = val ? "true" : "false"
130
- end
131
-
132
- return [
133
- {
134
- "k" => prefix.to_s,
135
- "v" => val.to_s
136
- }
137
- ]
138
- end
139
-
140
- def updateAttributeMap
141
- @attributeMap = {}
142
- flat = flattenUserValues("", @attributes)
143
- flat.each do |item|
144
- @attributeMap[item["k"]] = item["v"]
145
- end
146
- end
147
-
148
- def isTargeted(rules)
149
- pass = true
150
- rules.each do |rule|
151
- parts = rule.split(" ", 3)
152
- if parts.length == 3
153
- key = parts[0].strip
154
- actual = @attributeMap[key] || ""
155
- if !Growthbook::Util.checkRule(actual, parts[1].strip, parts[2].strip)
156
- pass = false
157
- break
158
- end
159
- end
160
- end
161
-
162
- return pass
163
- end
164
- end
165
- end