posthog-ruby 2.9.0 → 2.10.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.
@@ -1,30 +1,36 @@
1
+ require 'posthog/logging'
2
+
1
3
  class PostHog
2
4
  class FieldParser
3
5
  class << self
4
6
  include PostHog::Utils
7
+ include PostHog::Logging
5
8
 
6
9
  # In addition to the common fields, capture accepts:
7
10
  #
8
11
  # - "event"
9
12
  # - "properties"
10
13
  # - "groups"
14
+ # - "uuid"
11
15
  def parse_for_capture(fields)
12
16
  common = parse_common_fields(fields)
13
17
 
14
18
  event = fields[:event]
15
19
  properties = fields[:properties] || {}
16
20
  groups = fields[:groups]
17
-
21
+ uuid = fields[:uuid]
18
22
  check_presence!(event, 'event')
19
23
  check_is_hash!(properties, 'properties')
20
24
 
21
25
  if groups
22
26
  check_is_hash!(groups, 'groups')
23
- properties["$groups"] = groups
27
+ properties['$groups'] = groups
24
28
  end
25
29
 
26
30
  isoify_dates! properties
27
31
 
32
+ common['uuid'] = uuid if uuid? uuid
33
+
28
34
  common.merge(
29
35
  {
30
36
  type: 'capture',
@@ -49,7 +55,7 @@ class PostHog
49
55
  {
50
56
  type: 'identify',
51
57
  event: '$identify',
52
- '$set': properties,
58
+ :'$set' => properties,
53
59
  properties: properties.merge(common[:properties] || {})
54
60
  }
55
61
  )
@@ -73,10 +79,10 @@ class PostHog
73
79
  {
74
80
  event: '$groupidentify',
75
81
  properties: {
76
- "$group_type": group_type,
77
- "$group_key": group_key,
78
- "$group_set": properties.merge(common[:properties] || {})
79
- },
82
+ :'$group_type' => group_type,
83
+ :'$group_key' => group_key,
84
+ :'$group_set' => properties.merge(common[:properties] || {})
85
+ }
80
86
  }
81
87
  )
82
88
  end
@@ -139,34 +145,39 @@ class PostHog
139
145
  active_feature_variants = {}
140
146
  feature_variants.each do |key, value|
141
147
  parsed[:properties]["$feature/#{key}"] = value
142
- if value != false
143
- active_feature_variants[key] = value
144
- end
148
+ active_feature_variants[key] = value if value != false
145
149
  end
146
- parsed[:properties]["$active_feature_flags"] = active_feature_variants.keys
150
+ parsed[:properties]['$active_feature_flags'] = active_feature_variants.keys
147
151
  end
148
152
  parsed
149
153
  end
150
154
 
151
155
  def check_timestamp!(timestamp)
152
- unless timestamp.is_a? Time
153
- raise ArgumentError, 'Timestamp must be a Time'
154
- end
156
+ return if timestamp.is_a? Time
157
+
158
+ raise ArgumentError, 'Timestamp must be a Time'
155
159
  end
156
160
 
157
161
  # private: Ensures that a string is non-empty
158
162
  #
159
- # obj - String|Number that must be non-blank
160
- # name - Name of the validated value
163
+ # obj - String|Number that must be not blank
164
+ # name - The name of the validated value
161
165
  def check_presence!(obj, name)
162
- if obj.nil? || (obj.is_a?(String) && obj.empty?)
163
- raise ArgumentError, "#{name} must be given"
164
- end
166
+ return unless obj.nil? || (obj.is_a?(String) && obj.empty?)
167
+
168
+ raise ArgumentError, "#{name} must be given"
165
169
  end
166
170
 
167
171
  def check_is_hash!(obj, name)
168
172
  raise ArgumentError, "#{name} must be a Hash" unless obj.is_a? Hash
169
173
  end
174
+
175
+ def uuid?(uuid)
176
+ is_valid_uuid = uuid.match?(/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i) if uuid
177
+ logger.warn "UUID is not valid: #{uuid}. Ignoring it." unless is_valid_uuid
178
+
179
+ is_valid_uuid
180
+ end
170
181
  end
171
182
  end
172
183
  end
@@ -42,7 +42,7 @@ class PostHog
42
42
  if defined?(Rails)
43
43
  Rails.logger
44
44
  else
45
- logger = Logger.new STDOUT
45
+ logger = Logger.new $stdout
46
46
  logger.progname = 'PostHog'
47
47
  logger.level = Logger::WARN
48
48
  logger
@@ -9,7 +9,8 @@ class PostHog
9
9
  # Does nothing
10
10
  end
11
11
 
12
- def is_requesting?
12
+ # TODO: Rename to `requesting?` in future version
13
+ def is_requesting? # rubocop:disable Naming/PredicateName
13
14
  false
14
15
  end
15
16
  end
@@ -52,7 +52,8 @@ class PostHog
52
52
 
53
53
  # public: Check whether we have outstanding requests.
54
54
  #
55
- def is_requesting?
55
+ # TODO: Rename to `requesting?` in future version
56
+ def is_requesting? # rubocop:disable Naming/PredicateName
56
57
  @lock.synchronize { !@batch.empty? }
57
58
  end
58
59
 
@@ -21,10 +21,10 @@ class PostHog
21
21
  options[:port] = uri.port
22
22
  end
23
23
 
24
- options[:host] = !options[:host].nil? ? options[:host] : HOST
25
- options[:port] = !options[:port].nil? ? options[:port] : PORT
26
- options[:ssl] = !options[:ssl].nil? ? options[:ssl] : SSL
27
-
24
+ options[:host] = options[:host].nil? ? HOST : options[:host]
25
+ options[:port] = options[:port].nil? ? PORT : options[:port]
26
+ options[:ssl] = options[:ssl].nil? ? SSL : options[:ssl]
27
+
28
28
  @headers = options[:headers] || HEADERS
29
29
  @path = options[:path] || PATH
30
30
  @retries = options[:retries] || RETRIES
@@ -34,9 +34,7 @@ class PostHog
34
34
  http.use_ssl = options[:ssl]
35
35
  http.read_timeout = 8
36
36
  http.open_timeout = 4
37
- if options[:skip_ssl_verification]
38
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
39
- end
37
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if options[:skip_ssl_verification]
40
38
 
41
39
  @http = http
42
40
  end
@@ -77,7 +75,7 @@ class PostHog
77
75
  def should_retry_request?(status_code, body)
78
76
  if status_code >= 500
79
77
  true # Server error
80
- elsif status_code == 429
78
+ elsif status_code == 429 # rubocop:disable Lint/DuplicateBranch
81
79
  true # Rate limited
82
80
  elsif status_code >= 400
83
81
  logger.error(body)
@@ -123,7 +121,7 @@ class PostHog
123
121
 
124
122
  if self.class.stub
125
123
  logger.debug "stubbed request to #{@path}: " \
126
- "api key = #{api_key}, batch = #{JSON.generate(batch)}"
124
+ "api key = #{api_key}, batch = #{JSON.generate(batch)}"
127
125
 
128
126
  [200, '{}']
129
127
  else
@@ -137,7 +135,7 @@ class PostHog
137
135
  attr_writer :stub
138
136
 
139
137
  def stub
140
- @stub || ENV['STUB']
138
+ @stub || ENV.fetch('STUB', nil)
141
139
  end
142
140
  end
143
141
  end
data/lib/posthog/utils.rb CHANGED
@@ -1,12 +1,11 @@
1
1
  require 'securerandom'
2
2
 
3
3
  class PostHog
4
-
5
4
  class InconclusiveMatchError < StandardError
6
5
  end
7
6
 
8
7
  module Utils
9
- extend self
8
+ module_function
10
9
 
11
10
  # public: Return a new hash with keys converted from strings to symbols
12
11
  #
@@ -47,7 +46,8 @@ class PostHog
47
46
  arr = SecureRandom.random_bytes(16).unpack('NnnnnN')
48
47
  arr[2] = (arr[2] & 0x0fff) | 0x4000
49
48
  arr[3] = (arr[3] & 0x3fff) | 0x8000
50
- '%08x-%04x-%04x-%04x-%04x%08x' % arr
49
+
50
+ '%08x-%04x-%04x-%04x-%04x%08x' % arr # rubocop:disable Style/FormatStringToken, Style/FormatString
51
51
  end
52
52
 
53
53
  def datetime_in_iso8601(datetime)
@@ -65,7 +65,7 @@ class PostHog
65
65
 
66
66
  def time_in_iso8601(time, fraction_digits = 3)
67
67
  fraction =
68
- (('.%06i' % time.usec)[0, fraction_digits + 1] if fraction_digits > 0)
68
+ (('.%06i' % time.usec)[0, fraction_digits + 1] if fraction_digits > 0) # rubocop:disable Style/FormatString
69
69
 
70
70
  "#{time.strftime('%Y-%m-%dT%H:%M:%S')}#{fraction}#{formatted_offset(time, true, 'Z')}"
71
71
  end
@@ -75,44 +75,39 @@ class PostHog
75
75
  end
76
76
 
77
77
  def formatted_offset(time, colon = true, alternate_utc_string = nil)
78
- time.utc? && alternate_utc_string ||
78
+ (time.utc? && alternate_utc_string) ||
79
79
  seconds_to_utc_offset(time.utc_offset, colon)
80
80
  end
81
81
 
82
82
  def seconds_to_utc_offset(seconds, colon = true)
83
- (colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON) % [
84
- (seconds < 0 ? '-' : '+'),
85
- (seconds.abs / 3600),
86
- ((seconds.abs % 3600) / 60)
87
- ]
83
+ format((colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON), (seconds < 0 ? '-' : '+'),
84
+ seconds.abs / 3600, (seconds.abs % 3600) / 60)
88
85
  end
89
86
 
90
87
  def convert_to_datetime(value)
91
88
  if value.respond_to?(:strftime)
92
- parsed_date = value
93
- return parsed_date
89
+ value
90
+
94
91
  elsif value.respond_to?(:to_str)
95
92
  begin
96
- parsed_date = DateTime.parse(value)
97
- return parsed_date
98
- rescue ArgumentError => e
99
- raise InconclusiveMatchError.new("#{value} is not in a valid date format")
93
+ DateTime.parse(value)
94
+ rescue ArgumentError
95
+ raise InconclusiveMatchError, "#{value} is not in a valid date format"
100
96
  end
101
97
  else
102
- raise InconclusiveMatchError.new("The date provided must be a string or date object")
98
+ raise InconclusiveMatchError, 'The date provided must be a string or date object'
103
99
  end
104
100
  end
105
101
 
106
- UTC_OFFSET_WITH_COLON = '%s%02d:%02d'
102
+ UTC_OFFSET_WITH_COLON = '%s%02d:%02d'.freeze
107
103
  UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
108
104
 
109
- def is_valid_regex(regex)
110
- begin
111
- Regexp.new(regex)
112
- return true
113
- rescue RegexpError
114
- return false
115
- end
105
+ # TODO: Rename to `valid_regex?` in future version
106
+ def is_valid_regex(regex) # rubocop:disable Naming/PredicateName
107
+ Regexp.new(regex)
108
+ true
109
+ rescue RegexpError
110
+ false
116
111
  end
117
112
 
118
113
  class SizeLimitedHash < Hash
@@ -122,9 +117,7 @@ class PostHog
122
117
  end
123
118
 
124
119
  def []=(key, value)
125
- if length >= @max_length
126
- clear
127
- end
120
+ clear if length >= @max_length
128
121
  super
129
122
  end
130
123
  end
@@ -1,3 +1,3 @@
1
1
  class PostHog
2
- VERSION = '2.9.0'
2
+ VERSION = '2.10.0'.freeze
3
3
  end
data/lib/posthog-ruby.rb CHANGED
@@ -1 +1,3 @@
1
+ # rubocop:disable Naming/FileName
1
2
  require 'posthog'
3
+ # rubocop:enable Naming/FileName
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posthog-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-04-30 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: concurrent-ruby
@@ -24,104 +23,6 @@ dependencies:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
25
  version: '1'
27
- - !ruby/object:Gem::Dependency
28
- name: commander
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '4.4'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '4.4'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '13.1'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '13.1'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.13'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.13'
69
- - !ruby/object:Gem::Dependency
70
- name: tzinfo
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '2.0'
83
- - !ruby/object:Gem::Dependency
84
- name: activesupport
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '7.1'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '7.1'
97
- - !ruby/object:Gem::Dependency
98
- name: oj
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 3.16.3
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 3.16.3
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.51.0
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.51.0
125
26
  description: The PostHog ruby library
126
27
  email: hey@posthog.com
127
28
  executables:
@@ -151,8 +52,8 @@ files:
151
52
  homepage: https://github.com/PostHog/posthog-ruby
152
53
  licenses:
153
54
  - MIT
154
- metadata: {}
155
- post_install_message:
55
+ metadata:
56
+ rubygems_mfa_required: 'true'
156
57
  rdoc_options: []
157
58
  require_paths:
158
59
  - lib
@@ -167,8 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
68
  - !ruby/object:Gem::Version
168
69
  version: '0'
169
70
  requirements: []
170
- rubygems_version: 3.5.10
171
- signing_key:
71
+ rubygems_version: 3.6.9
172
72
  specification_version: 4
173
73
  summary: PostHog library
174
74
  test_files: []