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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '059ef73434d227fde96790307f75b6922f1dbd840f3e7afca68c4600f217263d'
4
- data.tar.gz: 7eb241bdd104280ee49117094859ba9b9801747c32a2b4e8ed043b96e336a812
3
+ metadata.gz: dd554df4ba15f0d1addaecc5e76502c1218c1b08842152eeeffd0f6e121dbcba
4
+ data.tar.gz: b1d19d91608685488db9705e213559c4a36c21731b0822137b55fab0693a871d
5
5
  SHA512:
6
- metadata.gz: b0b92e135f883955bd187971886822959656c644a9573f96de043c342f2930787152c0c16b293d8ed33cda25559dcd1298f9578056fc049a2042752a168ef0b1
7
- data.tar.gz: c0103fd2da0b70705540e391aa6afc2bfcd81a37a1dfa01791032aeb43b258ff782caf6eba8c8e4188b15d8676a643d8764a2bc9b6f2e9a022b07455fec221c3
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
@@ -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
- return default_value if @value[index_sym].class != default_value.class and default_value.class != TrueClass and default_value.class != FalseClass
57
- @value[index_sym]
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
@@ -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) < (rule[:passPercentage] * 100)
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
- return default_value if @value[index_sym].class != default_value.class and default_value.class != TrueClass and default_value.class != FalseClass
55
+ value = @value[index_sym]
56
56
 
57
- if @exposure_log_func.is_a? Proc
58
- @exposure_log_func.call(self, index)
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
- @value[index_sym]
80
+ default_value
62
81
  end
63
82
  end
data/lib/statsig.rb CHANGED
@@ -363,7 +363,7 @@ module Statsig
363
363
  def self.get_statsig_metadata
364
364
  {
365
365
  'sdkType' => 'ruby-server',
366
- 'sdkVersion' => '2.0.1',
366
+ 'sdkVersion' => '2.1.0',
367
367
  'languageVersion' => RUBY_VERSION
368
368
  }
369
369
  end
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.1
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-08-06 00:00:00.000000000 Z
11
+ date: 2024-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler