growthbook 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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