posthog-ruby 2.3.1 → 2.4.1

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: 987f48b8d0cfa660cf9fc2d53f7da5d7e59150b774fc8403c4b65b94873b577d
4
- data.tar.gz: 84402895313a99ebbf865e50ab06b5ee9876510e4c621b206a521dde8d371bc7
3
+ metadata.gz: 0b0fe64cbfa7e53a76fdd9241fb1eff4b428babe557ae8ee1ce62c2a287e42a5
4
+ data.tar.gz: afc4e5c842f2b38e8c2f9fa0247dfb4a01db2021ffccbb8d3e62f6acc904bf88
5
5
  SHA512:
6
- metadata.gz: e34a38c0b8386e95ab5fde0fad897f4bbccacf727cd72c7a72b3ec832977b460055b2ea35d2ab670e65bc916feb84f7d00e8bfa7eaee6e451ae1e6a156e6471f
7
- data.tar.gz: d338821ad6066df5a7036421d62b2de806f07fcb266cd695f87f605084b6644e96e954c90ab3395fcc2d246642d6e8055be04c6e6af15b90a730290156733c11
6
+ metadata.gz: 23134246b45ee9c507e4fb52aca1539ecf2af4b036976f7f5a6c6fbe2dafc20f3a3da677014019f5366243b10f5c2b29521dc81e4911ea2820d966d21b5c54ea
7
+ data.tar.gz: 72dea55baf64ca45b28d5642e8881004a6f0f2dc5f9f43e30d27a3392949a3994a16d805ce20e7bf2ac9f94ddce3d1817df33b152664b0dc582170281f03587d
@@ -174,6 +174,7 @@ class PostHog
174
174
  # group_properties: {"organization": {"name": "PostHog", "employees": 11}}
175
175
  # ```
176
176
  def get_feature_flag(key, distinct_id, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false, send_feature_flag_events: true)
177
+ person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
177
178
  feature_flag_response, flag_was_locally_evaluated = @feature_flags_poller.get_feature_flag(key, distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
178
179
 
179
180
  feature_flag_reported_key = "#{key}_#{feature_flag_response}"
@@ -204,6 +205,7 @@ class PostHog
204
205
  #
205
206
  # @return [Hash] String (not symbol) key value pairs of flag and their values
206
207
  def get_all_flags(distinct_id, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false)
208
+ person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
207
209
  return @feature_flags_poller.get_all_flags(distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
208
210
  end
209
211
 
@@ -218,6 +220,7 @@ class PostHog
218
220
  # @option [Boolean] only_evaluate_locally
219
221
  #
220
222
  def get_feature_flag_payload(key, distinct_id, match_value: nil, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false)
223
+ person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
221
224
  @feature_flags_poller.get_feature_flag_payload(key, distinct_id, match_value, groups, person_properties, group_properties, only_evaluate_locally)
222
225
  end
223
226
 
@@ -230,6 +233,7 @@ class PostHog
230
233
  # @option [Boolean] only_evaluate_locally
231
234
  #
232
235
  def get_all_flags_and_payloads(distinct_id, groups: {}, person_properties: {}, group_properties: {}, only_evaluate_locally: false)
236
+ person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
233
237
  @feature_flags_poller.get_all_flags_and_payloads(distinct_id, groups, person_properties, group_properties, only_evaluate_locally)
234
238
  end
235
239
 
@@ -288,5 +292,32 @@ class PostHog
288
292
  def worker_running?
289
293
  @worker_thread && @worker_thread.alive?
290
294
  end
295
+
296
+ def add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
297
+
298
+ groups ||= {}
299
+ person_properties ||= {}
300
+ group_properties ||= {}
301
+
302
+ symbolize_keys! groups
303
+ symbolize_keys! person_properties
304
+ symbolize_keys! group_properties
305
+
306
+ group_properties.each do |key, value|
307
+ symbolize_keys! value
308
+ end
309
+
310
+ all_person_properties = { "$current_distinct_id" => distinct_id }.merge(person_properties)
311
+
312
+ all_group_properties = {}
313
+ if groups
314
+ groups.each do |group_name, group_key|
315
+ all_group_properties[group_name] = {
316
+ "$group_key" => group_key}.merge(group_properties&.dig(group_name) || {})
317
+ end
318
+ end
319
+
320
+ return all_person_properties, all_group_properties
321
+ end
291
322
  end
292
323
  end
@@ -205,6 +205,52 @@ class PostHog
205
205
 
206
206
  # Class methods
207
207
 
208
+ def self.compare(lhs, rhs, operator)
209
+ if operator == "gt"
210
+ return lhs > rhs
211
+ elsif operator == "gte"
212
+ return lhs >= rhs
213
+ elsif operator == "lt"
214
+ return lhs < rhs
215
+ elsif operator == "lte"
216
+ return lhs <= rhs
217
+ else
218
+ raise "Invalid operator: #{operator}"
219
+ end
220
+ end
221
+
222
+ def self.relative_date_parse_for_feature_flag_matching(value)
223
+ match = /^([0-9]+)([a-z])$/.match(value)
224
+ parsed_dt = DateTime.now.new_offset(0)
225
+ if match
226
+ number = match[1].to_i
227
+
228
+ if number >= 10000
229
+ # Guard against overflow, disallow numbers greater than 10_000
230
+ return nil
231
+ end
232
+
233
+ interval = match[2]
234
+ if interval == "h"
235
+ parsed_dt = parsed_dt - (number/24r)
236
+ elsif interval == "d"
237
+ parsed_dt = parsed_dt.prev_day(number)
238
+ elsif interval == "w"
239
+ parsed_dt = parsed_dt.prev_day(number*7)
240
+ elsif interval == "m"
241
+ parsed_dt = parsed_dt.prev_month(number)
242
+ elsif interval == "y"
243
+ parsed_dt = parsed_dt.prev_year(number)
244
+ else
245
+ return nil
246
+ end
247
+ parsed_dt
248
+ else
249
+ nil
250
+ end
251
+ end
252
+
253
+
208
254
  def self.match_property(property, property_values)
209
255
  # only looks for matches where key exists in property_values
210
256
  # doesn't support operator is_not_set
@@ -225,11 +271,21 @@ class PostHog
225
271
  override_value = property_values[key]
226
272
 
227
273
  case operator
228
- when 'exact'
229
- value.is_a?(Array) ? value.include?(override_value) : value == override_value
230
- when 'is_not'
231
- value.is_a?(Array) ? !value.include?(override_value) : value != override_value
232
- when'is_set'
274
+ when 'exact', 'is_not'
275
+ if value.is_a?(Array)
276
+ values_stringified = value.map { |val| val.to_s.downcase }
277
+ if operator == 'exact'
278
+ return values_stringified.any?(override_value.to_s.downcase)
279
+ else
280
+ return !values_stringified.any?(override_value.to_s.downcase)
281
+ end
282
+ end
283
+ if operator == 'exact'
284
+ value.to_s.downcase == override_value.to_s.downcase
285
+ else
286
+ value.to_s.downcase != override_value.to_s.downcase
287
+ end
288
+ when 'is_set'
233
289
  property_values.key?(key)
234
290
  when 'icontains'
235
291
  override_value.to_s.downcase.include?(value.to_s.downcase)
@@ -239,25 +295,39 @@ class PostHog
239
295
  PostHog::Utils.is_valid_regex(value.to_s) && !Regexp.new(value.to_s).match(override_value.to_s).nil?
240
296
  when 'not_regex'
241
297
  PostHog::Utils.is_valid_regex(value.to_s) && Regexp.new(value.to_s).match(override_value.to_s).nil?
242
- when 'gt'
243
- override_value.class == value.class && override_value > value
244
- when 'gte'
245
- override_value.class == value.class && override_value >= value
246
- when 'lt'
247
- override_value.class == value.class && override_value < value
248
- when 'lte'
249
- override_value.class == value.class && override_value <= value
250
- when 'is_date_before', 'is_date_after'
251
- parsed_date = PostHog::Utils::convert_to_datetime(value)
252
- override_date = PostHog::Utils::convert_to_datetime(override_value)
253
- if operator == 'is_date_before'
254
- return override_date < parsed_date
298
+ when 'gt', 'gte', 'lt', 'lte'
299
+ parsed_value = nil
300
+ begin
301
+ parsed_value = Float(value)
302
+ rescue StandardError => e
303
+ end
304
+ if !parsed_value.nil? && !override_value.nil?
305
+ if override_value.is_a?(String)
306
+ self.compare(override_value, value.to_s, operator)
307
+ else
308
+ self.compare(override_value, parsed_value, operator)
309
+ end
310
+ else
311
+ self.compare(override_value.to_s, value.to_s, operator)
312
+ end
313
+ when 'is_date_before', 'is_date_after', 'is_relative_date_before', 'is_relative_date_after'
314
+ if operator == 'is_relative_date_before' || operator == 'is_relative_date_after'
315
+ parsed_date = self.relative_date_parse_for_feature_flag_matching(value.to_s)
316
+ override_date = PostHog::Utils.convert_to_datetime(override_value.to_s)
255
317
  else
318
+ parsed_date = PostHog::Utils.convert_to_datetime(value.to_s)
319
+ override_date = PostHog::Utils.convert_to_datetime(override_value.to_s)
320
+ end
321
+ if !parsed_date
322
+ raise InconclusiveMatchError.new("Invalid date format")
323
+ end
324
+ if operator == 'is_date_before' or operator == 'is_relative_date_before'
325
+ return override_date < parsed_date
326
+ elsif operator == 'is_date_after' or operator == 'is_relative_date_after'
256
327
  return override_date > parsed_date
257
328
  end
258
329
  else
259
- logger.error "Unknown operator: #{operator}"
260
- false
330
+ raise InconclusiveMatchError.new("Unknown operator: #{operator}")
261
331
  end
262
332
  end
263
333
 
@@ -1,3 +1,3 @@
1
1
  class PostHog
2
- VERSION = '2.3.1'
2
+ VERSION = '2.4.1'
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.3.1
4
+ version: 2.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-14 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby