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 +4 -4
- data/lib/posthog/client.rb +28 -1
- data/lib/posthog/feature_flags.rb +85 -18
- data/lib/posthog/version.rb +1 -1
- metadata +3 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d80e39f962a2bba799e013b2dfdcd88ab25a7b777d2185e8ef03c2c53446c7c0
|
4
|
+
data.tar.gz: 9550b79aad4b9c18c3870f0fa684181ce197e5fdaa5dbb3db7bba40c85005e6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35f6eb8128e2ff82739a7d9cdeb5f99b0a0a4c5923c7d295c17bedcccb44f562040e429f08c78cc1621ac6f35df46f6fecb6176505ffcff83540b8bb74d3a119
|
7
|
+
data.tar.gz: ecb9bb5e660722b07e16f765a920f642b5ff7b3a1a20ad9b20c3db12c1646ee6dd706e3696106d23f73e51f6fa15894b0fd03f09470cfe1dcb7b432fb3c36738
|
data/lib/posthog/client.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
143
|
-
|
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=
|
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
|
data/lib/posthog/version.rb
CHANGED
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.
|
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:
|
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
|
181
|
+
rubygems_version: 3.0.3.1
|
188
182
|
signing_key:
|
189
183
|
specification_version: 4
|
190
184
|
summary: PostHog library
|