statsig 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/client_initialize_helpers.rb +16 -2
- data/lib/constants.rb +6 -0
- data/lib/dynamic_config.rb +14 -2
- data/lib/evaluation_helpers.rb +13 -1
- data/lib/evaluator.rb +23 -1
- data/lib/layer.rb +23 -4
- data/lib/statsig.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd554df4ba15f0d1addaecc5e76502c1218c1b08842152eeeffd0f6e121dbcba
|
4
|
+
data.tar.gz: b1d19d91608685488db9705e213559c4a36c21731b0822137b55fab0693a871d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b360f7fb18b06e87b538eb005ce0f7344f8a633a1cb9915d3e6f74e5b0fab3b7d87d46ab4b4498548e66766d00a4f60a9bb5f502c270e09925e67c24575da7ca
|
7
|
+
data.tar.gz: 337e0fd5ecfc11fa5565980df91d21ee17cc6586d49f1a18b333eaa4de1da29094c453a00daf1671ce8e6872d03882b85c169df6709aa41e543500cdc5c78057
|
@@ -92,12 +92,26 @@ module Statsig
|
|
92
92
|
result[:rule_id] = eval_result.rule_id
|
93
93
|
|
94
94
|
if include_exposures
|
95
|
-
result[:secondary_exposures] = eval_result.secondary_exposures
|
95
|
+
result[:secondary_exposures] = hash_exposures(eval_result.secondary_exposures, hash_algo)
|
96
96
|
end
|
97
97
|
|
98
98
|
[hashed_name, result]
|
99
99
|
end
|
100
100
|
|
101
|
+
def self.hash_exposures(exposures, hash_algo)
|
102
|
+
return nil if exposures.nil?
|
103
|
+
hashed_exposures = []
|
104
|
+
exposures.each do |exp|
|
105
|
+
hashed_exposures << {
|
106
|
+
gate: hash_name(exp[:gate], hash_algo),
|
107
|
+
gateValue: exp[:gateValue],
|
108
|
+
ruleID: exp[:ruleID]
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
hashed_exposures
|
113
|
+
end
|
114
|
+
|
101
115
|
def self.populate_experiment_fields(config_name, config_spec, eval_result, result, evaluator)
|
102
116
|
result[:is_user_in_experiment] = eval_result.is_experiment_group
|
103
117
|
result[:is_experiment_active] = config_spec[:isActive] == true
|
@@ -132,7 +146,7 @@ module Statsig
|
|
132
146
|
end
|
133
147
|
|
134
148
|
if include_exposures
|
135
|
-
result[:undelegated_secondary_exposures] = eval_result.undelegated_sec_exps || []
|
149
|
+
result[:undelegated_secondary_exposures] = hash_exposures(eval_result.undelegated_sec_exps || [], hash_algo)
|
136
150
|
end
|
137
151
|
end
|
138
152
|
|
data/lib/constants.rb
CHANGED
@@ -123,5 +123,11 @@ module Statsig
|
|
123
123
|
# API Operators (Segments)
|
124
124
|
OP_IN_SEGMENT_LIST = 'in_segment_list'.freeze
|
125
125
|
OP_NOT_IN_SEGMENT_LIST = 'not_in_segment_list'.freeze
|
126
|
+
|
127
|
+
# API Operators (Array)
|
128
|
+
OP_ARRAY_CONTAINS_ANY = 'array_contains_any'.freeze
|
129
|
+
OP_ARRAY_CONTAINS_NONE = 'array_contains_none'.freeze
|
130
|
+
OP_ARRAY_CONTAINS_ALL = 'array_contains_all'.freeze
|
131
|
+
OP_NOT_ARRAY_CONTAINS_ALL = 'not_array_contains_all'.freeze
|
126
132
|
end
|
127
133
|
end
|
data/lib/dynamic_config.rb
CHANGED
@@ -53,7 +53,19 @@ class DynamicConfig
|
|
53
53
|
index_sym = index.to_sym
|
54
54
|
return default_value unless @value.key?(index_sym)
|
55
55
|
|
56
|
-
|
57
|
-
|
56
|
+
value = @value[index_sym]
|
57
|
+
|
58
|
+
case default_value
|
59
|
+
when Integer
|
60
|
+
return value.to_i if value.is_a?(Numeric) && default_value.is_a?(Integer)
|
61
|
+
when Float
|
62
|
+
return value.to_f if value.is_a?(Numeric) && default_value.is_a?(Float)
|
63
|
+
when TrueClass, FalseClass
|
64
|
+
return value if [true, false].include?(value)
|
65
|
+
else
|
66
|
+
return value if value.class == default_value.class
|
67
|
+
end
|
68
|
+
|
69
|
+
default_value
|
58
70
|
end
|
59
71
|
end
|
data/lib/evaluation_helpers.rb
CHANGED
@@ -58,6 +58,18 @@ module EvaluationHelpers
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
def self.array_contains_any(value, target)
|
62
|
+
return false if value.nil? || target.nil?
|
63
|
+
value_set = value.to_set
|
64
|
+
return target.any? { |item| value_set.include?(item) || value_set.include?(item.to_i) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.array_contains_all(value, target)
|
68
|
+
return false if value.nil? || target.nil?
|
69
|
+
value_set = value.to_set
|
70
|
+
return target.all? { |item| value_set.include?(item) || value_set.include?(item.to_i) }
|
71
|
+
end
|
72
|
+
|
61
73
|
private
|
62
74
|
|
63
75
|
def self.is_numeric(v)
|
@@ -73,4 +85,4 @@ module EvaluationHelpers
|
|
73
85
|
end
|
74
86
|
return time.to_i
|
75
87
|
end
|
76
|
-
end
|
88
|
+
end
|
data/lib/evaluator.rb
CHANGED
@@ -542,6 +542,24 @@ module Statsig
|
|
542
542
|
a.year == b.year && a.month == b.month && a.day == b.day
|
543
543
|
})
|
544
544
|
|
545
|
+
# array
|
546
|
+
when Const::OP_ARRAY_CONTAINS_ANY
|
547
|
+
if value.is_a?(Array) && target.is_a?(Array)
|
548
|
+
return EvaluationHelpers.array_contains_any(value, target)
|
549
|
+
end
|
550
|
+
when Const::OP_ARRAY_CONTAINS_NONE
|
551
|
+
if value.is_a?(Array) && target.is_a?(Array)
|
552
|
+
return !EvaluationHelpers.array_contains_any(value, target)
|
553
|
+
end
|
554
|
+
when Const::OP_ARRAY_CONTAINS_ALL
|
555
|
+
if value.is_a?(Array) && target.is_a?(Array)
|
556
|
+
return EvaluationHelpers.array_contains_all(value, target)
|
557
|
+
end
|
558
|
+
when Const::OP_NOT_ARRAY_CONTAINS_ALL
|
559
|
+
if value.is_a?(Array) && target.is_a?(Array)
|
560
|
+
return !EvaluationHelpers.array_contains_all(value, target)
|
561
|
+
end
|
562
|
+
|
545
563
|
# segments
|
546
564
|
when Const::OP_IN_SEGMENT_LIST, Const::OP_NOT_IN_SEGMENT_LIST
|
547
565
|
begin
|
@@ -670,10 +688,14 @@ module Statsig
|
|
670
688
|
end
|
671
689
|
|
672
690
|
def eval_pass_percent(user, rule, config_salt)
|
691
|
+
pass_percentage = rule[:passPercentage]
|
692
|
+
return true if pass_percentage == 100.0
|
693
|
+
return false if pass_percentage == 0.0
|
694
|
+
|
673
695
|
unit_id = user.get_unit_id(rule[:idType]) || Const::EMPTY_STR
|
674
696
|
rule_salt = rule[:salt] || rule[:id] || Const::EMPTY_STR
|
675
697
|
hash = compute_user_hash("#{config_salt}.#{rule_salt}.#{unit_id}")
|
676
|
-
return (hash % 10_000) < (
|
698
|
+
return (hash % 10_000) < (pass_percentage * 100)
|
677
699
|
end
|
678
700
|
|
679
701
|
def compute_user_hash(user_hash)
|
data/lib/layer.rb
CHANGED
@@ -52,12 +52,31 @@ class Layer
|
|
52
52
|
index_sym = index.to_sym
|
53
53
|
return default_value unless @value.key?(index_sym)
|
54
54
|
|
55
|
-
|
55
|
+
value = @value[index_sym]
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
case default_value
|
58
|
+
when Integer
|
59
|
+
if @exposure_log_func.is_a? Proc
|
60
|
+
@exposure_log_func.call(self, index)
|
61
|
+
end
|
62
|
+
return value.to_i if value.is_a?(Numeric) && default_value.is_a?(Integer)
|
63
|
+
when Float
|
64
|
+
if @exposure_log_func.is_a? Proc
|
65
|
+
@exposure_log_func.call(self, index)
|
66
|
+
end
|
67
|
+
return value.to_f if value.is_a?(Numeric) && default_value.is_a?(Float)
|
68
|
+
when TrueClass, FalseClass
|
69
|
+
if @exposure_log_func.is_a? Proc
|
70
|
+
@exposure_log_func.call(self, index)
|
71
|
+
end
|
72
|
+
return value if [true, false].include?(value)
|
73
|
+
else
|
74
|
+
if @exposure_log_func.is_a? Proc
|
75
|
+
@exposure_log_func.call(self, index)
|
76
|
+
end
|
77
|
+
return value if value.class == default_value.class
|
59
78
|
end
|
60
79
|
|
61
|
-
|
80
|
+
default_value
|
62
81
|
end
|
63
82
|
end
|
data/lib/statsig.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|