growthbook 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Growthbook
4
+ class InlineExperimentResult
5
+ # Whether or not the user is in the experiment
6
+ # @return [Bool]
7
+ attr_reader :in_experiment
8
+
9
+ # The array index of the assigned variation
10
+ # @return [Integer]
11
+ attr_reader :variation_id
12
+
13
+ # The assigned variation value
14
+ # @return [Any]
15
+ attr_reader :value
16
+
17
+ # The attribute used to split traffic
18
+ # @return [String]
19
+ attr_reader :hash_attribute
20
+
21
+ # The value of the hashAttribute
22
+ # @return [String]
23
+ attr_reader :hash_value
24
+
25
+ def initialize(
26
+ in_experiment,
27
+ variation_id,
28
+ value,
29
+ hash_attribute,
30
+ hash_value
31
+ )
32
+
33
+ @in_experiment = in_experiment
34
+ @variation_id = variation_id
35
+ @value = value
36
+ @hash_attribute = hash_attribute
37
+ @hash_value = hash_value
38
+ end
39
+
40
+ def to_json(*_args)
41
+ res = {}
42
+ res['inExperiment'] = @in_experiment
43
+ res['variationId'] = @variation_id
44
+ res['value'] = @value
45
+ res['hashAttribute'] = @hash_attribute
46
+ res['hashValue'] = @hash_value
47
+ res
48
+ end
49
+ end
50
+ end
@@ -1,25 +1,39 @@
1
- require "fnv"
1
+ # frozen_string_literal: true
2
+
3
+ require 'fnv'
2
4
 
3
5
  module Growthbook
4
6
  class Util
5
7
  def self.checkRule(actual, op, desired)
6
8
  # Check if both strings are numeric so we can do natural ordering
7
9
  # for greater than / less than operators
8
- numeric = (Float(actual) != nil && Float(desired) != nil) rescue false
10
+ numeric = begin
11
+ (!Float(actual).nil? && !Float(desired).nil?)
12
+ rescue StandardError
13
+ false
14
+ end
9
15
 
10
16
  case op
11
- when "="
17
+ when '='
12
18
  numeric ? Float(actual) == Float(desired) : actual == desired
13
- when "!="
19
+ when '!='
14
20
  numeric ? Float(actual) != Float(desired) : actual != desired
15
- when ">"
21
+ when '>'
16
22
  numeric ? Float(actual) > Float(desired) : actual > desired
17
- when "<"
23
+ when '<'
18
24
  numeric ? Float(actual) < Float(desired) : actual < desired
19
- when "~"
20
- !!(actual =~ Regexp.new(desired)) rescue false
21
- when "!~"
22
- !(actual =~ Regexp.new(desired)) rescue false
25
+ when '~'
26
+ begin
27
+ !!(actual =~ Regexp.new(desired))
28
+ rescue StandardError
29
+ false
30
+ end
31
+ when '!~'
32
+ begin
33
+ actual !~ Regexp.new(desired)
34
+ rescue StandardError
35
+ false
36
+ end
23
37
  else
24
38
  true
25
39
  end
@@ -27,10 +41,10 @@ module Growthbook
27
41
 
28
42
  def self.chooseVariation(userId, experiment)
29
43
  testId = experiment.id
30
- weights = experiment.getScaledWeights()
44
+ weights = experiment.getScaledWeights
31
45
 
32
46
  # Hash the user id and testName to a number from 0 to 1
33
- n = (FNV.new.fnv1a_32(userId + testId)%1000)/1000.0
47
+ n = (FNV.new.fnv1a_32(userId + testId) % 1000) / 1000.0
34
48
 
35
49
  cumulativeWeight = 0
36
50
 
@@ -42,10 +56,97 @@ module Growthbook
42
56
  match = i
43
57
  break
44
58
  end
45
- i+=1
59
+ i += 1
60
+ end
61
+
62
+ match
63
+ end
64
+
65
+ def self.hash(str)
66
+ (FNV.new.fnv1a_32(str) % 1000) / 1000.0
67
+ end
68
+
69
+ def self.in_namespace(userId, namespace)
70
+ n = hash("#{userId}__#{namespace[0]}")
71
+ n >= namespace[1] && n < namespace[2]
72
+ end
73
+
74
+ def self.get_equal_weights(numVariations)
75
+ return [] if numVariations < 1
76
+
77
+ weights = []
78
+ (1..numVariations).each do |_i|
79
+ weights << (1.0 / numVariations)
80
+ end
81
+ weights
82
+ end
83
+
84
+ # Determine bucket ranges for experiment variations
85
+ def self.get_bucket_ranges(numVariations, coverage = 1, weights = [])
86
+ # Make sure coverage is within bounds
87
+ coverage = 1 if coverage.nil?
88
+ coverage = 0 if coverage.negative?
89
+ coverage = 1 if coverage > 1
90
+
91
+ # Default to equal weights
92
+ weights = get_equal_weights(numVariations) if !weights || weights.length != numVariations
93
+
94
+ # If weights don't add up to 1 (or close to it), default to equal weights
95
+ total = weights.sum
96
+ weights = get_equal_weights(numVariations) if total < 0.99 || total > 1.01
97
+
98
+ # Convert weights to ranges
99
+ cumulative = 0
100
+ ranges = []
101
+ weights.each do |w|
102
+ start = cumulative
103
+ cumulative += w
104
+ ranges << [start, start + coverage * w]
105
+ end
106
+
107
+ ranges
108
+ end
109
+
110
+ # Chose a variation based on a hash and range
111
+ def self.choose_variation(n, ranges)
112
+ ranges.each_with_index do |range, i|
113
+ return i if n >= range[0] && n < range[1]
114
+ end
115
+ -1
116
+ end
117
+
118
+ # Get an override variation from a url querystring
119
+ # e.g. http://localhost?my-test=1 will return `1` for id `my-test`
120
+ def self.get_query_string_override(id, url, numVariations)
121
+ # Skip if url is empty
122
+ return nil if url == ''
123
+
124
+ # Parse out the query string
125
+ parsed = URI(url)
126
+ return nil unless parsed.query
127
+
128
+ qs = URI.decode_www_form(parsed.query)
129
+
130
+ # Look for `id` in the querystring and get the value
131
+ vals = qs.assoc(id)
132
+ return nil unless vals
133
+
134
+ val = vals.last
135
+ return nill unless val
136
+
137
+ # Parse the value as an integer
138
+ n = begin
139
+ Integer(val)
140
+ rescue StandardError
141
+ nil
46
142
  end
47
143
 
48
- return match
144
+ # Make sure the integer is within range
145
+ return nil if n.nil?
146
+ return nil if n.negative?
147
+ return nil if n >= numVariations
148
+
149
+ n
49
150
  end
50
151
  end
51
- end
152
+ end
data/lib/growthbook.rb CHANGED
@@ -1,9 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Growthbook
2
4
  end
3
5
 
4
6
  require 'growthbook/client'
7
+ require 'growthbook/conditions'
8
+ require 'growthbook/context'
9
+ require 'growthbook/experiment'
5
10
  require 'growthbook/experiment_result'
11
+ require 'growthbook/feature'
12
+ require 'growthbook/feature_result'
13
+ require 'growthbook/feature_rule'
14
+ require 'growthbook/inline_experiment'
15
+ require 'growthbook/inline_experiment_result'
6
16
  require 'growthbook/lookup_result'
7
- require 'growthbook/experiment'
17
+ require 'growthbook/user'
8
18
  require 'growthbook/util'
9
- require 'growthbook/user'