posthog-ruby 2.1.0 → 2.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef38f429ce00bcdcfc5c861fd163c420b9b3823b7cbcef4019a8bad580a6ad6f
4
- data.tar.gz: '08effac4bc47b38a6e67fe2f578cd67a974a7462dcaa6e73e92ac11b5bb34333'
3
+ metadata.gz: d80e39f962a2bba799e013b2dfdcd88ab25a7b777d2185e8ef03c2c53446c7c0
4
+ data.tar.gz: 9550b79aad4b9c18c3870f0fa684181ce197e5fdaa5dbb3db7bba40c85005e6c
5
5
  SHA512:
6
- metadata.gz: 86892110210900d5a3faa13fe2c335ce7d1ce0390390ff25c3d8a29510187d8829bda4795ead866471aaab7fa333f50a9b8251ff8e4ae47411d7a601d9f15eb2
7
- data.tar.gz: 80374572728723780c1930555491445a4761685df6574305c0de73f9d0fbd1630924c5fd4412b469f735bd44d7657b7160d73ccb4094c978b58bb7494950bb32
6
+ metadata.gz: 35f6eb8128e2ff82739a7d9cdeb5f99b0a0a4c5923c7d295c17bedcccb44f562040e429f08c78cc1621ac6f35df46f6fecb6176505ffcff83540b8bb74d3a119
7
+ data.tar.gz: ecb9bb5e660722b07e16f765a920f642b5ff7b3a1a20ad9b20c3db12c1646ee6dd706e3696106d23f73e51f6fa15894b0fd03f09470cfe1dcb7b432fb3c36738
@@ -91,7 +91,8 @@ class PostHog
91
91
  symbolize_keys! attrs
92
92
 
93
93
  if attrs[:send_feature_flags]
94
- feature_variants = @feature_flags_poller.get_feature_variants(attrs[:distinct_id], attrs[:groups])
94
+ feature_variants = @feature_flags_poller._get_active_feature_variants(attrs[:distinct_id], attrs[:groups])
95
+
95
96
  attrs[:feature_variants] = feature_variants
96
97
  end
97
98
 
@@ -205,6 +206,32 @@ class PostHog
205
206
  return @feature_flags_poller.get_all_flags(distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
206
207
  end
207
208
 
209
+ # Returns payload for a given feature flag
210
+ #
211
+ # @param [String] key The key of the feature flag
212
+ # @param [String] distinct_id The distinct id of the user
213
+ # @option [String or boolean] match_value The value of the feature flag to be matched
214
+ # @option [Hash] groups
215
+ # @option [Hash] person_properties key-value pairs of properties to associate with the user.
216
+ # @option [Hash] group_properties
217
+ # @option [Boolean] only_evaluate_locally
218
+ #
219
+ def get_feature_flag_payload(key, distinct_id, match_value: nil, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false)
220
+ @feature_flags_poller.get_feature_flag_payload(key, distinct_id, match_value, groups, person_properties, group_properties, only_evaluate_locally)
221
+ end
222
+
223
+ # Returns all flags and payloads for a given user
224
+ #
225
+ # @param [String] distinct_id The distinct id of the user
226
+ # @option [Hash] groups
227
+ # @option [Hash] person_properties key-value pairs of properties to associate with the user.
228
+ # @option [Hash] group_properties
229
+ # @option [Boolean] only_evaluate_locally
230
+ #
231
+ def get_all_flags_and_payloads(distinct_id, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false)
232
+ @feature_flags_poller.get_all_flags_and_payloads(distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
233
+ end
234
+
208
235
  def reload_feature_flags
209
236
  unless @personal_api_key
210
237
  logger.error(
@@ -10,9 +10,6 @@ class PostHog
10
10
  class InconclusiveMatchError < StandardError
11
11
  end
12
12
 
13
- class DecideAPIError < StandardError
14
- end
15
-
16
13
  class FeatureFlagsPoller
17
14
  include PostHog::Logging
18
15
  include PostHog::Utils
@@ -25,6 +22,7 @@ class PostHog
25
22
  @feature_flags = Concurrent::Array.new
26
23
  @group_type_mapping = Concurrent::Hash.new
27
24
  @loaded_flags_successfully_once = Concurrent::AtomicBoolean.new
25
+ @feature_flags_by_key = nil
28
26
 
29
27
  @task =
30
28
  Concurrent::TimerTask.new(
@@ -49,7 +47,35 @@ class PostHog
49
47
  end
50
48
 
51
49
  def get_feature_variants(distinct_id, groups={}, person_properties={}, group_properties={})
50
+ decide_data = get_decide(distinct_id, groups, person_properties, group_properties)
51
+ if !decide_data.key?(:featureFlags)
52
+ logger.error "Missing feature flags key: #{decide_data.to_json}"
53
+ else
54
+ stringify_keys(decide_data[:featureFlags] || {})
55
+ end
56
+ end
57
+
58
+ def _get_active_feature_variants(distinct_id, groups={}, person_properties={}, group_properties={})
59
+ feature_variants = get_feature_variants(distinct_id, groups, person_properties, group_properties)
60
+ active_feature_variants = {}
61
+ feature_variants.each do |key, value|
62
+ if value != false
63
+ active_feature_variants[key] = value
64
+ end
65
+ end
66
+ active_feature_variants
67
+ end
68
+
69
+ def get_feature_payloads(distinct_id, groups = {}, person_properties = {}, group_properties = {}, only_evaluate_locally = false)
70
+ decide_data = get_decide(distinct_id, groups, person_properties, group_properties)
71
+ if !decide_data.key?(:featureFlagPayloads)
72
+ logger.error "Missing feature flag payloads key: #{decide_data.to_json}"
73
+ else
74
+ stringify_keys(decide_data[:featureFlagPayloads] || {})
75
+ end
76
+ end
52
77
 
78
+ def get_decide(distinct_id, groups={}, person_properties={}, group_properties={})
53
79
  request_data = {
54
80
  "distinct_id": distinct_id,
55
81
  "groups": groups,
@@ -58,12 +84,6 @@ class PostHog
58
84
  }
59
85
 
60
86
  decide_data = _request_feature_flag_evaluation(request_data)
61
-
62
- if !decide_data.key?(:featureFlags)
63
- raise DecideAPIError.new(decide_data.to_json)
64
- else
65
- stringify_keys(decide_data[:featureFlags] || {})
66
- end
67
87
  end
68
88
 
69
89
  def get_feature_flag(key, distinct_id, groups = {}, person_properties = {}, group_properties = {}, only_evaluate_locally = false)
@@ -119,16 +139,25 @@ class PostHog
119
139
 
120
140
  def get_all_flags(distinct_id, groups = {}, person_properties = {}, group_properties = {}, only_evaluate_locally = false)
121
141
  # returns a string hash of all flags
142
+ response = get_all_flags_and_payloads(distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
143
+ flags = response[:featureFlags]
144
+ end
122
145
 
123
- # make sure they're loaded on first run
146
+ def get_all_flags_and_payloads(distinct_id, groups = {}, person_properties = {}, group_properties = {}, only_evaluate_locally = false)
124
147
  load_feature_flags
125
148
 
126
- response = {}
149
+ flags = {}
150
+ payloads = {}
127
151
  fallback_to_decide = @feature_flags.empty?
128
152
 
129
153
  @feature_flags.each do |flag|
130
154
  begin
131
- response[flag[:key]] = _compute_flag_locally(flag, distinct_id, groups, person_properties, group_properties)
155
+ match_value = _compute_flag_locally(flag, distinct_id, groups, person_properties, group_properties)
156
+ flags[flag[:key]] = match_value
157
+ match_payload = _compute_flag_payload_locally(flag[:key], match_value)
158
+ if match_payload
159
+ payloads[flag[:key]] = match_payload
160
+ end
132
161
  rescue InconclusiveMatchError => e
133
162
  fallback_to_decide = true
134
163
  rescue StandardError => e
@@ -136,15 +165,37 @@ class PostHog
136
165
  fallback_to_decide = true
137
166
  end
138
167
  end
139
-
140
168
  if fallback_to_decide && !only_evaluate_locally
141
169
  begin
142
- flags = get_feature_variants(distinct_id, groups, person_properties, group_properties)
143
- response = {**response, **flags}
170
+ flags_and_payloads = get_decide(distinct_id, groups, person_properties, group_properties)
171
+ flags = stringify_keys(flags_and_payloads[:featureFlags] || {})
172
+ payloads = stringify_keys(flags_and_payloads[:featureFlagPayloads] || {})
144
173
  rescue StandardError => e
145
174
  logger.error "Error computing flag remotely: #{e}"
146
175
  end
147
176
  end
177
+ {"featureFlags": flags, "featureFlagPayloads": payloads}
178
+ end
179
+
180
+ def get_feature_flag_payload(key, distinct_id, match_value = nil, groups = {}, person_properties = {}, group_properties = {}, only_evaluate_locally = false)
181
+ if match_value == nil
182
+ match_value = get_feature_flag(
183
+ key,
184
+ distinct_id,
185
+ groups,
186
+ person_properties,
187
+ group_properties,
188
+ true,
189
+ )[0]
190
+ end
191
+ response = nil
192
+ if match_value != nil
193
+ response = _compute_flag_payload_locally(key, match_value)
194
+ end
195
+ if response == nil and !only_evaluate_locally
196
+ decide_payloads = get_feature_payloads(distinct_id, groups, person_properties, group_properties)
197
+ response = decide_payloads[key.downcase] || nil
198
+ end
148
199
  response
149
200
  end
150
201
 
@@ -248,6 +299,17 @@ class PostHog
248
299
 
249
300
  end
250
301
 
302
+ def _compute_flag_payload_locally(key, match_value)
303
+ response = nil
304
+
305
+ if [true, false].include? match_value
306
+ response = @feature_flags_by_key.dig(key, :filters, :payloads, match_value.to_s.to_sym)
307
+ elsif match_value.is_a? String
308
+ response = @feature_flags_by_key.dig(key, :filters, :payloads, match_value.to_sym)
309
+ end
310
+ response
311
+ end
312
+
251
313
  def match_feature_flag_properties(flag, distinct_id, properties)
252
314
  flag_filters = flag[:filters] || {}
253
315
 
@@ -341,12 +403,17 @@ class PostHog
341
403
 
342
404
  def _load_feature_flags()
343
405
  res = _request_feature_flag_definitions
344
- @feature_flags.clear
345
406
 
346
407
  if !res.key?(:flags)
347
408
  logger.error "Failed to load feature flags: #{res}"
348
409
  else
349
- @feature_flags = res[:flags] || []
410
+ @feature_flags = res[:flags] || []
411
+ @feature_flags_by_key = {}
412
+ @feature_flags.each do |flag|
413
+ if flag[:key] != nil
414
+ @feature_flags_by_key[flag[:key]] = flag
415
+ end
416
+ end
350
417
  @group_type_mapping = res[:group_type_mapping] || {}
351
418
 
352
419
  logger.debug "Loaded #{@feature_flags.length} feature flags"
@@ -365,7 +432,7 @@ class PostHog
365
432
  end
366
433
 
367
434
  def _request_feature_flag_evaluation(data={})
368
- uri = URI("#{@host}/decide/?v=2")
435
+ uri = URI("#{@host}/decide/?v=3")
369
436
  req = Net::HTTP::Post.new(uri)
370
437
  req['Content-Type'] = 'application/json'
371
438
  data['token'] = @project_api_key
@@ -1,3 +1,3 @@
1
1
  class PostHog
2
- VERSION = '2.1.0'
2
+ VERSION = '2.3.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posthog-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-14 00:00:00.000000000 Z
11
+ date: 2023-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -17,9 +17,6 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: 1.1.10
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,9 +24,6 @@ dependencies:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: '1'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: 1.1.10
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: commander
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -184,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
178
  - !ruby/object:Gem::Version
185
179
  version: '0'
186
180
  requirements: []
187
- rubygems_version: 3.1.2
181
+ rubygems_version: 3.0.3.1
188
182
  signing_key:
189
183
  specification_version: 4
190
184
  summary: PostHog library